Coverage Report

Created: 2026-01-17 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxml2/xpath.c
Line
Count
Source
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: Daniel Veillard
14
 */
15
16
/* To avoid EBCDIC trouble when parsing on zOS */
17
#if defined(__MVS__)
18
#pragma convert("ISO8859-1")
19
#endif
20
21
#define IN_LIBXML
22
#include "libxml.h"
23
24
#include <limits.h>
25
#include <string.h>
26
#include <stddef.h>
27
#include <math.h>
28
#include <float.h>
29
#include <ctype.h>
30
31
#include <libxml/xmlmemory.h>
32
#include <libxml/tree.h>
33
#include <libxml/xpath.h>
34
#include <libxml/xpathInternals.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/hash.h>
37
#ifdef LIBXML_DEBUG_ENABLED
38
#include <libxml/debugXML.h>
39
#endif
40
#include <libxml/xmlerror.h>
41
#include <libxml/threads.h>
42
#ifdef LIBXML_PATTERN_ENABLED
43
#include <libxml/pattern.h>
44
#endif
45
46
#include "private/buf.h"
47
#include "private/error.h"
48
#include "private/memory.h"
49
#include "private/parser.h"
50
#include "private/xpath.h"
51
52
/* Disabled for now */
53
#if 0
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
#endif
58
59
/**
60
 * Use the Timsort algorithm provided in timsort.h to sort
61
 * nodeset as this is a great improvement over the old Shell sort
62
 * used in #xmlXPathNodeSetSort
63
 */
64
#define WITH_TIM_SORT
65
66
/*
67
* If defined, this will use xmlXPathCmpNodesExt() instead of
68
* xmlXPathCmpNodes(). The new function is optimized comparison of
69
* non-element nodes; actually it will speed up comparison only if
70
* xmlXPathOrderDocElems() was called in order to index the elements of
71
* a tree in document order; Libxslt does such an indexing, thus it will
72
* benefit from this optimization.
73
*/
74
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
75
76
/*
77
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
78
* in a way, that it stop evaluation at the first node.
79
*/
80
#define XP_OPTIMIZED_FILTER_FIRST
81
82
/*
83
 * when compiling an XPath expression we arbitrary limit the maximum
84
 * number of step operation in the compiled expression. 1000000 is
85
 * an insanely large value which should never be reached under normal
86
 * circumstances
87
 */
88
47.7k
#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
284
#define XPATH_MAX_STACK_DEPTH 1000000
97
98
/*
99
 * when evaluating an XPath expression nodesets are created and we
100
 * arbitrary limit the maximum length of those node set. 10000000 is
101
 * an insanely large value which should never be reached under normal
102
 * circumstances, one would first need to construct an in memory tree
103
 * with more than 10 millions nodes.
104
 */
105
2.44M
#define XPATH_MAX_NODESET_LENGTH 10000000
106
107
/*
108
 * Maximum amount of nested functions calls when parsing or evaluating
109
 * expressions
110
 */
111
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
112
4.57M
#define XPATH_MAX_RECURSION_DEPTH 500
113
#elif defined(_WIN32)
114
/* Windows typically limits stack size to 1MB. */
115
#define XPATH_MAX_RECURSION_DEPTH 1000
116
#else
117
#define XPATH_MAX_RECURSION_DEPTH 5000
118
#endif
119
120
/*
121
 * TODO:
122
 * There are a few spots where some tests are done which depend upon ascii
123
 * data.  These should be enhanced for full UTF8 support (see particularly
124
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
125
 */
126
127
#if defined(LIBXML_XPATH_ENABLED)
128
129
static void
130
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
131
132
static const struct {
133
    const char *name;
134
    xmlXPathFunction func;
135
} xmlXPathStandardFunctions[] = {
136
    { "boolean", xmlXPathBooleanFunction },
137
    { "ceiling", xmlXPathCeilingFunction },
138
    { "count", xmlXPathCountFunction },
139
    { "concat", xmlXPathConcatFunction },
140
    { "contains", xmlXPathContainsFunction },
141
    { "id", xmlXPathIdFunction },
142
    { "false", xmlXPathFalseFunction },
143
    { "floor", xmlXPathFloorFunction },
144
    { "last", xmlXPathLastFunction },
145
    { "lang", xmlXPathLangFunction },
146
    { "local-name", xmlXPathLocalNameFunction },
147
    { "not", xmlXPathNotFunction },
148
    { "name", xmlXPathNameFunction },
149
    { "namespace-uri", xmlXPathNamespaceURIFunction },
150
    { "normalize-space", xmlXPathNormalizeFunction },
151
    { "number", xmlXPathNumberFunction },
152
    { "position", xmlXPathPositionFunction },
153
    { "round", xmlXPathRoundFunction },
154
    { "string", xmlXPathStringFunction },
155
    { "string-length", xmlXPathStringLengthFunction },
156
    { "starts-with", xmlXPathStartsWithFunction },
157
    { "substring", xmlXPathSubstringFunction },
158
    { "substring-before", xmlXPathSubstringBeforeFunction },
159
    { "substring-after", xmlXPathSubstringAfterFunction },
160
    { "sum", xmlXPathSumFunction },
161
    { "true", xmlXPathTrueFunction },
162
    { "translate", xmlXPathTranslateFunction }
163
};
164
165
#define NUM_STANDARD_FUNCTIONS \
166
56
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
5.59k
#define SF_HASH_SIZE 64
169
170
static unsigned char xmlXPathSFHash[SF_HASH_SIZE];
171
172
double xmlXPathNAN = 0.0;
173
double xmlXPathPINF = 0.0;
174
double xmlXPathNINF = 0.0;
175
176
/**
177
 * @deprecated Alias for #xmlInitParser.
178
 */
179
void
180
0
xmlXPathInit(void) {
181
0
    xmlInitParser();
182
0
}
183
184
ATTRIBUTE_NO_SANITIZE_INTEGER
185
static unsigned
186
3.83k
xmlXPathSFComputeHash(const xmlChar *name) {
187
3.83k
    unsigned hashValue = 5381;
188
3.83k
    const xmlChar *ptr;
189
190
29.5k
    for (ptr = name; *ptr; ptr++)
191
25.6k
        hashValue = hashValue * 33 + *ptr;
192
193
3.83k
    return(hashValue);
194
3.83k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
2
xmlInitXPathInternal(void) {
202
2
    size_t i;
203
204
2
#if defined(NAN) && defined(INFINITY)
205
2
    xmlXPathNAN = NAN;
206
2
    xmlXPathPINF = INFINITY;
207
2
    xmlXPathNINF = -INFINITY;
208
#else
209
    /* MSVC doesn't allow division by zero in constant expressions. */
210
    double zero = 0.0;
211
    xmlXPathNAN = 0.0 / zero;
212
    xmlXPathPINF = 1.0 / zero;
213
    xmlXPathNINF = -xmlXPathPINF;
214
#endif
215
216
    /*
217
     * Initialize hash table for standard functions
218
     */
219
220
130
    for (i = 0; i < SF_HASH_SIZE; i++)
221
128
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
56
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
54
        const char *name = xmlXPathStandardFunctions[i].name;
225
54
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
68
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
14
            bucketIndex += 1;
229
14
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
14
        }
232
233
54
        xmlXPathSFHash[bucketIndex] = i;
234
54
    }
235
2
}
236
237
/************************************************************************
238
 *                  *
239
 *      Floating point stuff        *
240
 *                  *
241
 ************************************************************************/
242
243
/**
244
 * Checks whether a double is a NaN.
245
 *
246
 * @param val  a double value
247
 * @returns 1 if the value is a NaN, 0 otherwise
248
 */
249
int
250
886k
xmlXPathIsNaN(double val) {
251
886k
#ifdef isnan
252
886k
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
886k
}
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
85.7k
xmlXPathIsInf(double val) {
266
85.7k
#ifdef isinf
267
85.7k
    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
85.7k
}
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
24.4M
#define XML_NODE_SORT_VALUE(n) XML_PTR_TO_INT((n)->content)
296
297
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
298
299
/**
300
 * Compare two nodes w.r.t document order.
301
 * This one is optimized for handling of non-element nodes.
302
 *
303
 * @param node1  the first node
304
 * @param node2  the second node
305
 * @returns -2 in case of error 1 if first point < second point, 0 if
306
 *         it's the same node, -1 otherwise
307
 */
308
static int
309
21.6M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
21.6M
    int depth1, depth2;
311
21.6M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
21.6M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
21.6M
    xmlNodePtr cur, root;
314
21.6M
    XML_INTPTR_T l1, l2;
315
316
21.6M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
21.6M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
21.6M
    switch (node1->type) {
326
13.5M
  case XML_ELEMENT_NODE:
327
13.5M
      if (node2->type == XML_ELEMENT_NODE) {
328
6.56M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
0
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
0
        (node1->doc == node2->doc))
331
0
    {
332
0
        l1 = -XML_NODE_SORT_VALUE(node1);
333
0
        l2 = -XML_NODE_SORT_VALUE(node2);
334
0
        if (l1 < l2)
335
0
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
6.56M
        goto turtle_comparison;
340
6.56M
      }
341
6.94M
      break;
342
6.94M
  case XML_ATTRIBUTE_NODE:
343
5.46k
      precedence1 = 1; /* element is owner */
344
5.46k
      miscNode1 = node1;
345
5.46k
      node1 = node1->parent;
346
5.46k
      misc = 1;
347
5.46k
      break;
348
7.78M
  case XML_TEXT_NODE:
349
7.78M
  case XML_CDATA_SECTION_NODE:
350
7.79M
  case XML_COMMENT_NODE:
351
7.79M
  case XML_PI_NODE: {
352
7.79M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
7.79M
      if (node1->prev != NULL) {
357
7.42M
    do {
358
7.42M
        node1 = node1->prev;
359
7.42M
        if (node1->type == XML_ELEMENT_NODE) {
360
7.38M
      precedence1 = 3; /* element in prev-sibl axis */
361
7.38M
      break;
362
7.38M
        }
363
37.7k
        if (node1->prev == NULL) {
364
1.91k
      precedence1 = 2; /* element is parent */
365
      /*
366
      * URGENT TODO: Are there any cases, where the
367
      * parent of such a node is not an element node?
368
      */
369
1.91k
      node1 = node1->parent;
370
1.91k
      break;
371
1.91k
        }
372
37.7k
    } while (1);
373
7.38M
      } else {
374
403k
    precedence1 = 2; /* element is parent */
375
403k
    node1 = node1->parent;
376
403k
      }
377
7.79M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
7.79M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
7.79M
    node1 = miscNode1;
383
7.79M
    precedence1 = 0;
384
7.79M
      } else
385
0
    misc = 1;
386
7.79M
  }
387
7.79M
      break;
388
248k
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
248k
      return(1);
393
88.1k
  default:
394
88.1k
      break;
395
21.6M
    }
396
14.8M
    switch (node2->type) {
397
6.19M
  case XML_ELEMENT_NODE:
398
6.19M
      break;
399
5.71k
  case XML_ATTRIBUTE_NODE:
400
5.71k
      precedence2 = 1; /* element is owner */
401
5.71k
      miscNode2 = node2;
402
5.71k
      node2 = node2->parent;
403
5.71k
      misc = 1;
404
5.71k
      break;
405
8.20M
  case XML_TEXT_NODE:
406
8.20M
  case XML_CDATA_SECTION_NODE:
407
8.20M
  case XML_COMMENT_NODE:
408
8.20M
  case XML_PI_NODE: {
409
8.20M
      miscNode2 = node2;
410
8.20M
      if (node2->prev != NULL) {
411
7.51M
    do {
412
7.51M
        node2 = node2->prev;
413
7.51M
        if (node2->type == XML_ELEMENT_NODE) {
414
7.47M
      precedence2 = 3; /* element in prev-sibl axis */
415
7.47M
      break;
416
7.47M
        }
417
37.5k
        if (node2->prev == NULL) {
418
2.06k
      precedence2 = 2; /* element is parent */
419
2.06k
      node2 = node2->parent;
420
2.06k
      break;
421
2.06k
        }
422
37.5k
    } while (1);
423
7.48M
      } else {
424
726k
    precedence2 = 2; /* element is parent */
425
726k
    node2 = node2->parent;
426
726k
      }
427
8.20M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
8.20M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
8.20M
      {
430
8.20M
    node2 = miscNode2;
431
8.20M
    precedence2 = 0;
432
8.20M
      } else
433
0
    misc = 1;
434
8.20M
  }
435
8.20M
      break;
436
3.14k
  case XML_NAMESPACE_DECL:
437
3.14k
      return(1);
438
420k
  default:
439
420k
      break;
440
14.8M
    }
441
14.8M
    if (misc) {
442
9.61k
  if (node1 == node2) {
443
2.07k
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
1.30k
    cur = miscNode2->prev;
449
1.52k
    while (cur != NULL) {
450
680
        if (cur == miscNode1)
451
464
      return(1);
452
216
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
216
        cur = cur->prev;
455
216
    }
456
842
    return (-1);
457
1.30k
      } 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
764
    if (precedence1 < precedence2)
464
411
        return(1);
465
353
    else
466
353
        return(-1);
467
764
      }
468
2.07k
  }
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
7.54k
  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
7.54k
  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
7.54k
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
14.8M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
6.94M
  (node2->type == XML_ELEMENT_NODE) &&
501
6.88k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
0
  (node1->doc == node2->doc)) {
504
505
0
  l1 = -XML_NODE_SORT_VALUE(node1);
506
0
  l2 = -XML_NODE_SORT_VALUE(node2);
507
0
  if (l1 < l2)
508
0
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
21.3M
turtle_comparison:
514
515
21.3M
    if (node1 == node2->prev)
516
8.65M
  return(1);
517
12.7M
    if (node1 == node2->next)
518
473k
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
78.4M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
68.1M
  if (cur->parent == node1)
524
2.01M
      return(1);
525
66.1M
  depth2++;
526
66.1M
    }
527
10.2M
    root = cur;
528
85.0M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
78.6M
  if (cur->parent == node2)
530
3.88M
      return(-1);
531
74.7M
  depth1++;
532
74.7M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
6.36M
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
20.7M
    while (depth1 > depth2) {
543
14.3M
  depth1--;
544
14.3M
  node1 = node1->parent;
545
14.3M
    }
546
8.01M
    while (depth2 > depth1) {
547
1.65M
  depth2--;
548
1.65M
  node2 = node2->parent;
549
1.65M
    }
550
6.44M
    while (node1->parent != node2->parent) {
551
80.5k
  node1 = node1->parent;
552
80.5k
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
80.5k
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
80.5k
    }
557
    /*
558
     * Find who's first.
559
     */
560
6.36M
    if (node1 == node2->prev)
561
145k
  return(1);
562
6.21M
    if (node1 == node2->next)
563
2.70M
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
3.51M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
2.65M
  (node2->type == XML_ELEMENT_NODE) &&
569
1.88M
  (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
79.4M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
77.1M
  if (cur == node2)
583
1.29M
      return(1);
584
2.22M
    return(-1); /* assume there is no sibling list corruption */
585
3.51M
}
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
3.24M
#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
21.6M
    {
607
21.6M
        int res = xmlXPathCmpNodesExt(x, y);
608
21.6M
        return res == -2 ? res : -res;
609
21.6M
    }
610
#else
611
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
612
    {
613
        int res = xmlXPathCmpNodes(x, y);
614
        return res == -2 ? res : -res;
615
    }
616
#endif
617
21.6M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
618
#include "timsort.h"
619
#endif /* WITH_TIM_SORT */
620
621
/************************************************************************
622
 *                  *
623
 *      Error handling routines       *
624
 *                  *
625
 ************************************************************************/
626
627
/**
628
 * Macro to raise an XPath error and return NULL.
629
 *
630
 * @param X  the error code
631
 */
632
#define XP_ERRORNULL(X)             \
633
472
    { xmlXPathErr(ctxt, X); return(NULL); }
634
635
/*
636
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
637
 */
638
static const char* const xmlXPathErrorMessages[] = {
639
    "Ok",
640
    "Number encoding",
641
    "Unfinished literal",
642
    "Start of literal",
643
    "Expected $ for variable reference",
644
    "Undefined variable",
645
    "Invalid predicate",
646
    "Invalid expression",
647
    "Missing closing curly brace",
648
    "Unregistered function",
649
    "Invalid operand",
650
    "Invalid type",
651
    "Invalid number of arguments",
652
    "Invalid context size",
653
    "Invalid context position",
654
    "Memory allocation error",
655
    "Syntax error",
656
    "Resource error",
657
    "Sub resource error",
658
    "Undefined namespace prefix",
659
    "Encoding error",
660
    "Char out of XML range",
661
    "Invalid or incomplete context",
662
    "Stack usage error",
663
    "Forbidden variable",
664
    "Operation limit exceeded",
665
    "Recursion limit exceeded",
666
    "?? Unknown error ??" /* Must be last in the list! */
667
};
668
23.5k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
23.5k
       sizeof(xmlXPathErrorMessages[0])) - 1)
670
/**
671
 * Handle a memory allocation failure.
672
 *
673
 * @param ctxt  an XPath context
674
 */
675
void
676
xmlXPathErrMemory(xmlXPathContext *ctxt)
677
3.12k
{
678
3.12k
    if (ctxt == NULL)
679
0
        return;
680
3.12k
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
3.12k
                        &ctxt->lastError);
682
3.12k
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
1.73k
{
692
1.73k
    if (ctxt == NULL)
693
0
        return;
694
1.73k
    ctxt->error = XPATH_MEMORY_ERROR;
695
1.73k
    xmlXPathErrMemory(ctxt->context);
696
1.73k
}
697
698
/**
699
 * Handle an XPath error
700
 *
701
 * @param ctxt  a XPath parser context
702
 * @param code  the error code
703
 * @param fmt  format string for error message
704
 * @param ...  extra args
705
 */
706
static void
707
23.5k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
23.5k
    va_list ap;
709
23.5k
    xmlStructuredErrorFunc schannel = NULL;
710
23.5k
    xmlGenericErrorFunc channel = NULL;
711
23.5k
    void *data = NULL;
712
23.5k
    xmlNodePtr node = NULL;
713
23.5k
    int res;
714
715
23.5k
    if (ctxt == NULL)
716
0
        return;
717
23.5k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
23.5k
    if (ctxt->error != 0)
721
7.17k
        return;
722
723
16.3k
    ctxt->error = code;
724
725
16.3k
    if (ctxt->context != NULL) {
726
16.3k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
16.3k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
16.3k
        xmlResetError(err);
734
735
16.3k
        err->domain = XML_FROM_XPATH;
736
16.3k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
16.3k
        err->level = XML_ERR_ERROR;
738
16.3k
        if (ctxt->base != NULL) {
739
16.3k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
16.3k
            if (err->str1 == NULL) {
741
106
                xmlXPathPErrMemory(ctxt);
742
106
                return;
743
106
            }
744
16.3k
        }
745
16.2k
        err->int1 = ctxt->cur - ctxt->base;
746
16.2k
        err->node = ctxt->context->debugNode;
747
748
16.2k
        schannel = ctxt->context->error;
749
16.2k
        data = ctxt->context->userData;
750
16.2k
        node = ctxt->context->debugNode;
751
16.2k
    }
752
753
16.2k
    if (schannel == NULL) {
754
16.2k
        channel = xmlGenericError;
755
16.2k
        data = xmlGenericErrorContext;
756
16.2k
    }
757
758
16.2k
    va_start(ap, fmt);
759
16.2k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
16.2k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
16.2k
                         XML_ERR_ERROR, NULL, 0,
762
16.2k
                         (const char *) ctxt->base, NULL, NULL,
763
16.2k
                         ctxt->cur - ctxt->base, 0,
764
16.2k
                         fmt, ap);
765
16.2k
    va_end(ap);
766
16.2k
    if (res < 0)
767
250
        xmlXPathPErrMemory(ctxt);
768
16.2k
}
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
23.1k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
23.1k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
23.1k
}
780
781
/**
782
 * Formats an error message.
783
 *
784
 * @param ctxt  the XPath Parser context
785
 * @param file  the file name
786
 * @param line  the line number
787
 * @param no  the error number
788
 */
789
void
790
xmlXPatherror(xmlXPathParserContext *ctxt, const char *file ATTRIBUTE_UNUSED,
791
0
              int line ATTRIBUTE_UNUSED, int no) {
792
0
    xmlXPathErr(ctxt, no);
793
0
}
794
795
/**
796
 * Adds opCount to the running total of operations and returns -1 if the
797
 * operation limit is exceeded. Returns 0 otherwise.
798
 *
799
 * @param ctxt  the XPath Parser context
800
 * @param opCount  the number of operations to be added
801
 */
802
static int
803
46.0M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
46.0M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
46.0M
    if ((opCount > xpctxt->opLimit) ||
807
46.0M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
114
        xpctxt->opCount = xpctxt->opLimit;
809
114
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
114
        return(-1);
811
114
    }
812
813
46.0M
    xpctxt->opCount += opCount;
814
46.0M
    return(0);
815
46.0M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
45.8M
    ((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
25.8k
xmlXPathNewCompExpr(void) {
941
25.8k
    xmlXPathCompExprPtr cur;
942
943
25.8k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
25.8k
    if (cur == NULL)
945
211
  return(NULL);
946
25.6k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
25.6k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
25.6k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
25.6k
    cur->nbStep = 0;
953
25.6k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
25.6k
                                     sizeof(xmlXPathStepOp));
955
25.6k
    if (cur->steps == NULL) {
956
79
  xmlFree(cur);
957
79
  return(NULL);
958
79
    }
959
25.5k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
25.5k
    cur->last = -1;
961
25.5k
    return(cur);
962
25.6k
}
963
964
/**
965
 * Free up the memory allocated by `comp`
966
 *
967
 * @param comp  an XPATH comp
968
 */
969
void
970
xmlXPathFreeCompExpr(xmlXPathCompExpr *comp)
971
25.5k
{
972
25.5k
    xmlXPathStepOpPtr op;
973
25.5k
    int i;
974
975
25.5k
    if (comp == NULL)
976
0
        return;
977
25.5k
    if (comp->dict == NULL) {
978
413k
  for (i = 0; i < comp->nbStep; i++) {
979
388k
      op = &comp->steps[i];
980
388k
      if (op->value4 != NULL) {
981
22.2k
    if (op->op == XPATH_OP_VALUE)
982
13.7k
        xmlXPathFreeObject(op->value4);
983
8.47k
    else
984
8.47k
        xmlFree(op->value4);
985
22.2k
      }
986
388k
      if (op->value5 != NULL)
987
51.6k
    xmlFree(op->value5);
988
388k
  }
989
25.5k
    } else {
990
0
  for (i = 0; i < comp->nbStep; i++) {
991
0
      op = &comp->steps[i];
992
0
      if (op->value4 != NULL) {
993
0
    if (op->op == XPATH_OP_VALUE)
994
0
        xmlXPathFreeObject(op->value4);
995
0
      }
996
0
  }
997
0
        xmlDictFree(comp->dict);
998
0
    }
999
25.5k
    if (comp->steps != NULL) {
1000
25.5k
        xmlFree(comp->steps);
1001
25.5k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
25.5k
    if (comp->expr != NULL) {
1008
0
        xmlFree(comp->expr);
1009
0
    }
1010
1011
25.5k
    xmlFree(comp);
1012
25.5k
}
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
388k
   int value2, int value3, void *value4, void *value5) {
1032
388k
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
388k
    if (comp->nbStep >= comp->maxStep) {
1034
47.7k
  xmlXPathStepOp *real;
1035
47.7k
        int newSize;
1036
1037
47.7k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
47.7k
                                  10, XPATH_MAX_STEPS);
1039
47.7k
        if (newSize < 0) {
1040
0
      xmlXPathPErrMemory(ctxt);
1041
0
      return(-1);
1042
0
        }
1043
47.7k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
47.7k
  if (real == NULL) {
1045
22
      xmlXPathPErrMemory(ctxt);
1046
22
      return(-1);
1047
22
  }
1048
47.7k
  comp->steps = real;
1049
47.7k
  comp->maxStep = newSize;
1050
47.7k
    }
1051
388k
    comp->last = comp->nbStep;
1052
388k
    comp->steps[comp->nbStep].ch1 = ch1;
1053
388k
    comp->steps[comp->nbStep].ch2 = ch2;
1054
388k
    comp->steps[comp->nbStep].op = op;
1055
388k
    comp->steps[comp->nbStep].value = value;
1056
388k
    comp->steps[comp->nbStep].value2 = value2;
1057
388k
    comp->steps[comp->nbStep].value3 = value3;
1058
388k
    if ((comp->dict != NULL) &&
1059
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
0
   (op == XPATH_OP_COLLECT))) {
1061
0
        if (value4 != NULL) {
1062
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
0
      xmlFree(value4);
1065
0
  } else
1066
0
      comp->steps[comp->nbStep].value4 = NULL;
1067
0
        if (value5 != NULL) {
1068
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
0
      xmlFree(value5);
1071
0
  } else
1072
0
      comp->steps[comp->nbStep].value5 = NULL;
1073
388k
    } else {
1074
388k
  comp->steps[comp->nbStep].value4 = value4;
1075
388k
  comp->steps[comp->nbStep].value5 = value5;
1076
388k
    }
1077
388k
    comp->steps[comp->nbStep].cache = NULL;
1078
388k
    return(comp->nbStep++);
1079
388k
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
75.6k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
75.6k
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
41.3k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
41.3k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
127k
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
127k
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
39.8k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
39.8k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
103k
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
103k
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
103k
      (val), (val2), 0 ,NULL ,NULL)
1097
1098
/************************************************************************
1099
 *                  *
1100
 *    XPath object cache structures       *
1101
 *                  *
1102
 ************************************************************************/
1103
1104
/* #define XP_DEFAULT_CACHE_ON */
1105
1106
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1107
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1108
struct _xmlXPathContextCache {
1109
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1110
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1111
    int numNodeset;
1112
    int maxNodeset;
1113
    int numMisc;
1114
    int maxMisc;
1115
};
1116
1117
/************************************************************************
1118
 *                  *
1119
 *    Debugging related functions       *
1120
 *                  *
1121
 ************************************************************************/
1122
1123
#ifdef LIBXML_DEBUG_ENABLED
1124
static void
1125
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1126
    int i;
1127
    char shift[100];
1128
1129
    for (i = 0;((i < depth) && (i < 25));i++)
1130
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
    if (cur == NULL) {
1133
  fprintf(output, "%s", shift);
1134
  fprintf(output, "Node is NULL !\n");
1135
  return;
1136
1137
    }
1138
1139
    if ((cur->type == XML_DOCUMENT_NODE) ||
1140
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1141
  fprintf(output, "%s", shift);
1142
  fprintf(output, " /\n");
1143
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1144
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1145
    else
1146
  xmlDebugDumpOneNode(output, cur, depth);
1147
}
1148
static void
1149
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1150
    xmlNodePtr tmp;
1151
    int i;
1152
    char shift[100];
1153
1154
    for (i = 0;((i < depth) && (i < 25));i++)
1155
        shift[2 * i] = shift[2 * i + 1] = ' ';
1156
    shift[2 * i] = shift[2 * i + 1] = 0;
1157
    if (cur == NULL) {
1158
  fprintf(output, "%s", shift);
1159
  fprintf(output, "Node is NULL !\n");
1160
  return;
1161
1162
    }
1163
1164
    while (cur != NULL) {
1165
  tmp = cur;
1166
  cur = cur->next;
1167
  xmlDebugDumpOneNode(output, tmp, depth);
1168
    }
1169
}
1170
1171
static void
1172
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1173
    int i;
1174
    char shift[100];
1175
1176
    for (i = 0;((i < depth) && (i < 25));i++)
1177
        shift[2 * i] = shift[2 * i + 1] = ' ';
1178
    shift[2 * i] = shift[2 * i + 1] = 0;
1179
1180
    if (cur == NULL) {
1181
  fprintf(output, "%s", shift);
1182
  fprintf(output, "NodeSet is NULL !\n");
1183
  return;
1184
1185
    }
1186
1187
    if (cur != NULL) {
1188
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1189
  for (i = 0;i < cur->nodeNr;i++) {
1190
      fprintf(output, "%s", shift);
1191
      fprintf(output, "%d", i + 1);
1192
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1193
  }
1194
    }
1195
}
1196
1197
static void
1198
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1199
    int i;
1200
    char shift[100];
1201
1202
    for (i = 0;((i < depth) && (i < 25));i++)
1203
        shift[2 * i] = shift[2 * i + 1] = ' ';
1204
    shift[2 * i] = shift[2 * i + 1] = 0;
1205
1206
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1207
  fprintf(output, "%s", shift);
1208
  fprintf(output, "Value Tree is NULL !\n");
1209
  return;
1210
1211
    }
1212
1213
    fprintf(output, "%s", shift);
1214
    fprintf(output, "%d", i + 1);
1215
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1216
}
1217
1218
/**
1219
 * Dump the content of the object for debugging purposes
1220
 *
1221
 * @param output  the FILE * to dump the output
1222
 * @param cur  the object to inspect
1223
 * @param depth  indentation level
1224
 */
1225
void
1226
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1227
    int i;
1228
    char shift[100];
1229
1230
    if (output == NULL) return;
1231
1232
    for (i = 0;((i < depth) && (i < 25));i++)
1233
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
    fprintf(output, "%s", shift);
1238
1239
    if (cur == NULL) {
1240
        fprintf(output, "Object is empty (NULL)\n");
1241
  return;
1242
    }
1243
    switch(cur->type) {
1244
        case XPATH_UNDEFINED:
1245
      fprintf(output, "Object is uninitialized\n");
1246
      break;
1247
        case XPATH_NODESET:
1248
      fprintf(output, "Object is a Node Set :\n");
1249
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
      break;
1251
  case XPATH_XSLT_TREE:
1252
      fprintf(output, "Object is an XSLT value tree :\n");
1253
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
      break;
1255
        case XPATH_BOOLEAN:
1256
      fprintf(output, "Object is a Boolean : ");
1257
      if (cur->boolval) fprintf(output, "true\n");
1258
      else fprintf(output, "false\n");
1259
      break;
1260
        case XPATH_NUMBER:
1261
      switch (xmlXPathIsInf(cur->floatval)) {
1262
      case 1:
1263
    fprintf(output, "Object is a number : Infinity\n");
1264
    break;
1265
      case -1:
1266
    fprintf(output, "Object is a number : -Infinity\n");
1267
    break;
1268
      default:
1269
    if (xmlXPathIsNaN(cur->floatval)) {
1270
        fprintf(output, "Object is a number : NaN\n");
1271
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
        fprintf(output, "Object is a number : 0\n");
1274
    } else {
1275
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
    }
1277
      }
1278
      break;
1279
        case XPATH_STRING:
1280
      fprintf(output, "Object is a string : ");
1281
      xmlDebugDumpString(output, cur->stringval);
1282
      fprintf(output, "\n");
1283
      break;
1284
  case XPATH_USERS:
1285
      fprintf(output, "Object is user defined\n");
1286
      break;
1287
    }
1288
}
1289
1290
static void
1291
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1292
                       xmlXPathStepOpPtr op, int depth) {
1293
    int i;
1294
    char shift[100];
1295
1296
    for (i = 0;((i < depth) && (i < 25));i++)
1297
        shift[2 * i] = shift[2 * i + 1] = ' ';
1298
    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300
    fprintf(output, "%s", shift);
1301
    if (op == NULL) {
1302
  fprintf(output, "Step is NULL\n");
1303
  return;
1304
    }
1305
    switch (op->op) {
1306
        case XPATH_OP_END:
1307
      fprintf(output, "END"); break;
1308
        case XPATH_OP_AND:
1309
      fprintf(output, "AND"); break;
1310
        case XPATH_OP_OR:
1311
      fprintf(output, "OR"); break;
1312
        case XPATH_OP_EQUAL:
1313
       if (op->value)
1314
     fprintf(output, "EQUAL =");
1315
       else
1316
     fprintf(output, "EQUAL !=");
1317
       break;
1318
        case XPATH_OP_CMP:
1319
       if (op->value)
1320
     fprintf(output, "CMP <");
1321
       else
1322
     fprintf(output, "CMP >");
1323
       if (!op->value2)
1324
     fprintf(output, "=");
1325
       break;
1326
        case XPATH_OP_PLUS:
1327
       if (op->value == 0)
1328
     fprintf(output, "PLUS -");
1329
       else if (op->value == 1)
1330
     fprintf(output, "PLUS +");
1331
       else if (op->value == 2)
1332
     fprintf(output, "PLUS unary -");
1333
       else if (op->value == 3)
1334
     fprintf(output, "PLUS unary - -");
1335
       break;
1336
        case XPATH_OP_MULT:
1337
       if (op->value == 0)
1338
     fprintf(output, "MULT *");
1339
       else if (op->value == 1)
1340
     fprintf(output, "MULT div");
1341
       else
1342
     fprintf(output, "MULT mod");
1343
       break;
1344
        case XPATH_OP_UNION:
1345
       fprintf(output, "UNION"); break;
1346
        case XPATH_OP_ROOT:
1347
       fprintf(output, "ROOT"); break;
1348
        case XPATH_OP_NODE:
1349
       fprintf(output, "NODE"); break;
1350
        case XPATH_OP_SORT:
1351
       fprintf(output, "SORT"); break;
1352
        case XPATH_OP_COLLECT: {
1353
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1354
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1355
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1356
      const xmlChar *prefix = op->value4;
1357
      const xmlChar *name = op->value5;
1358
1359
      fprintf(output, "COLLECT ");
1360
      switch (axis) {
1361
    case AXIS_ANCESTOR:
1362
        fprintf(output, " 'ancestors' "); break;
1363
    case AXIS_ANCESTOR_OR_SELF:
1364
        fprintf(output, " 'ancestors-or-self' "); break;
1365
    case AXIS_ATTRIBUTE:
1366
        fprintf(output, " 'attributes' "); break;
1367
    case AXIS_CHILD:
1368
        fprintf(output, " 'child' "); break;
1369
    case AXIS_DESCENDANT:
1370
        fprintf(output, " 'descendant' "); break;
1371
    case AXIS_DESCENDANT_OR_SELF:
1372
        fprintf(output, " 'descendant-or-self' "); break;
1373
    case AXIS_FOLLOWING:
1374
        fprintf(output, " 'following' "); break;
1375
    case AXIS_FOLLOWING_SIBLING:
1376
        fprintf(output, " 'following-siblings' "); break;
1377
    case AXIS_NAMESPACE:
1378
        fprintf(output, " 'namespace' "); break;
1379
    case AXIS_PARENT:
1380
        fprintf(output, " 'parent' "); break;
1381
    case AXIS_PRECEDING:
1382
        fprintf(output, " 'preceding' "); break;
1383
    case AXIS_PRECEDING_SIBLING:
1384
        fprintf(output, " 'preceding-sibling' "); break;
1385
    case AXIS_SELF:
1386
        fprintf(output, " 'self' "); break;
1387
      }
1388
      switch (test) {
1389
                case NODE_TEST_NONE:
1390
        fprintf(output, "'none' "); break;
1391
                case NODE_TEST_TYPE:
1392
        fprintf(output, "'type' "); break;
1393
                case NODE_TEST_PI:
1394
        fprintf(output, "'PI' "); break;
1395
                case NODE_TEST_ALL:
1396
        fprintf(output, "'all' "); break;
1397
                case NODE_TEST_NS:
1398
        fprintf(output, "'namespace' "); break;
1399
                case NODE_TEST_NAME:
1400
        fprintf(output, "'name' "); break;
1401
      }
1402
      switch (type) {
1403
                case NODE_TYPE_NODE:
1404
        fprintf(output, "'node' "); break;
1405
                case NODE_TYPE_COMMENT:
1406
        fprintf(output, "'comment' "); break;
1407
                case NODE_TYPE_TEXT:
1408
        fprintf(output, "'text' "); break;
1409
                case NODE_TYPE_PI:
1410
        fprintf(output, "'PI' "); break;
1411
      }
1412
      if (prefix != NULL)
1413
    fprintf(output, "%s:", prefix);
1414
      if (name != NULL)
1415
    fprintf(output, "%s", (const char *) name);
1416
      break;
1417
1418
        }
1419
  case XPATH_OP_VALUE: {
1420
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1421
1422
      fprintf(output, "ELEM ");
1423
      xmlXPathDebugDumpObject(output, object, 0);
1424
      goto finish;
1425
  }
1426
  case XPATH_OP_VARIABLE: {
1427
      const xmlChar *prefix = op->value5;
1428
      const xmlChar *name = op->value4;
1429
1430
      if (prefix != NULL)
1431
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1432
      else
1433
    fprintf(output, "VARIABLE %s", name);
1434
      break;
1435
  }
1436
  case XPATH_OP_FUNCTION: {
1437
      int nbargs = op->value;
1438
      const xmlChar *prefix = op->value5;
1439
      const xmlChar *name = op->value4;
1440
1441
      if (prefix != NULL)
1442
    fprintf(output, "FUNCTION %s:%s(%d args)",
1443
      prefix, name, nbargs);
1444
      else
1445
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1446
      break;
1447
  }
1448
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1449
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1450
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1451
  default:
1452
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1453
    }
1454
    fprintf(output, "\n");
1455
finish:
1456
    /* OP_VALUE has invalid ch1. */
1457
    if (op->op == XPATH_OP_VALUE)
1458
        return;
1459
1460
    if (op->ch1 >= 0)
1461
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1462
    if (op->ch2 >= 0)
1463
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1464
}
1465
1466
/**
1467
 * Dumps the tree of the compiled XPath expression.
1468
 *
1469
 * @param output  the FILE * for the output
1470
 * @param comp  the precompiled XPath expression
1471
 * @param depth  the indentation level.
1472
 */
1473
void
1474
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExpr *comp,
1475
                    int depth) {
1476
    int i;
1477
    char shift[100];
1478
1479
    if ((output == NULL) || (comp == NULL)) return;
1480
1481
    for (i = 0;((i < depth) && (i < 25));i++)
1482
        shift[2 * i] = shift[2 * i + 1] = ' ';
1483
    shift[2 * i] = shift[2 * i + 1] = 0;
1484
1485
    fprintf(output, "%s", shift);
1486
1487
#ifdef XPATH_STREAMING
1488
    if (comp->stream) {
1489
        fprintf(output, "Streaming Expression\n");
1490
    } else
1491
#endif
1492
    {
1493
        fprintf(output, "Compiled Expression : %d elements\n",
1494
                comp->nbStep);
1495
        i = comp->last;
1496
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1497
    }
1498
}
1499
1500
#endif /* LIBXML_DEBUG_ENABLED */
1501
1502
/************************************************************************
1503
 *                  *
1504
 *      XPath object caching        *
1505
 *                  *
1506
 ************************************************************************/
1507
1508
/**
1509
 * Create a new object cache
1510
 *
1511
 * @returns the xmlXPathCache just allocated.
1512
 */
1513
static xmlXPathContextCachePtr
1514
xmlXPathNewCache(void)
1515
25.9k
{
1516
25.9k
    xmlXPathContextCachePtr ret;
1517
1518
25.9k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
25.9k
    if (ret == NULL)
1520
641
  return(NULL);
1521
25.3k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
25.3k
    ret->maxNodeset = 100;
1523
25.3k
    ret->maxMisc = 100;
1524
25.3k
    return(ret);
1525
25.9k
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
12.8k
{
1530
46.4k
    while (list != NULL) {
1531
33.6k
        xmlXPathObjectPtr next;
1532
1533
33.6k
        next = (void *) list->stringval;
1534
1535
33.6k
  if (list->nodesetval != NULL) {
1536
23.5k
      if (list->nodesetval->nodeTab != NULL)
1537
21.0k
    xmlFree(list->nodesetval->nodeTab);
1538
23.5k
      xmlFree(list->nodesetval);
1539
23.5k
  }
1540
33.6k
  xmlFree(list);
1541
1542
33.6k
        list = next;
1543
33.6k
    }
1544
12.8k
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
25.3k
{
1549
25.3k
    if (cache == NULL)
1550
0
  return;
1551
25.3k
    if (cache->nodesetObjs)
1552
7.91k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
25.3k
    if (cache->miscObjs)
1554
4.89k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
25.3k
    xmlFree(cache);
1556
25.3k
}
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
25.9k
{
1582
25.9k
    if (ctxt == NULL)
1583
0
  return(-1);
1584
25.9k
    if (active) {
1585
25.9k
  xmlXPathContextCachePtr cache;
1586
1587
25.9k
  if (ctxt->cache == NULL) {
1588
25.9k
      ctxt->cache = xmlXPathNewCache();
1589
25.9k
      if (ctxt->cache == NULL) {
1590
641
                xmlXPathErrMemory(ctxt);
1591
641
    return(-1);
1592
641
            }
1593
25.9k
  }
1594
25.3k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
25.3k
  if (options == 0) {
1596
25.3k
      if (value < 0)
1597
0
    value = 100;
1598
25.3k
      cache->maxNodeset = value;
1599
25.3k
      cache->maxMisc = value;
1600
25.3k
  }
1601
25.3k
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
25.3k
    return(0);
1606
25.9k
}
1607
1608
/**
1609
 * This is the cached version of #xmlXPathWrapNodeSet.
1610
 * Wrap the Nodeset `val` in a new xmlXPathObject
1611
 *
1612
 * In case of error the node set is destroyed and NULL is returned.
1613
 *
1614
 * @param pctxt  the XPath context
1615
 * @param val  the NodePtr value
1616
 * @returns the created or reused object.
1617
 */
1618
static xmlXPathObjectPtr
1619
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1620
1.26M
{
1621
1.26M
    xmlXPathObjectPtr ret;
1622
1.26M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
1.26M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
1.01M
  xmlXPathContextCachePtr cache =
1626
1.01M
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
1.01M
  if (cache->miscObjs != NULL) {
1629
977k
      ret = cache->miscObjs;
1630
977k
            cache->miscObjs = (void *) ret->stringval;
1631
977k
            cache->numMisc -= 1;
1632
977k
            ret->stringval = NULL;
1633
977k
      ret->type = XPATH_NODESET;
1634
977k
      ret->nodesetval = val;
1635
977k
      return(ret);
1636
977k
  }
1637
1.01M
    }
1638
1639
288k
    ret = xmlXPathWrapNodeSet(val);
1640
288k
    if (ret == NULL)
1641
78
        xmlXPathPErrMemory(pctxt);
1642
288k
    return(ret);
1643
1.26M
}
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
57.3k
{
1656
57.3k
    xmlXPathObjectPtr ret;
1657
57.3k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
57.3k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
36.7k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
36.7k
  if (cache->miscObjs != NULL) {
1663
33.1k
      ret = cache->miscObjs;
1664
33.1k
            cache->miscObjs = (void *) ret->stringval;
1665
33.1k
            cache->numMisc -= 1;
1666
33.1k
      ret->type = XPATH_STRING;
1667
33.1k
      ret->stringval = val;
1668
33.1k
      return(ret);
1669
33.1k
  }
1670
36.7k
    }
1671
1672
24.2k
    ret = xmlXPathWrapString(val);
1673
24.2k
    if (ret == NULL)
1674
27
        xmlXPathPErrMemory(pctxt);
1675
24.2k
    return(ret);
1676
57.3k
}
1677
1678
/**
1679
 * This is the cached version of #xmlXPathNewNodeSet.
1680
 * Acquire an xmlXPathObject of type NodeSet and initialize
1681
 * it with the single Node `val`
1682
 *
1683
 * @param pctxt  the XPath context
1684
 * @param val  the NodePtr value
1685
 * @returns the created or reused object.
1686
 */
1687
static xmlXPathObjectPtr
1688
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1689
1.43M
{
1690
1.43M
    xmlXPathObjectPtr ret;
1691
1.43M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
1.43M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
1.17M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
1.17M
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
1.16M
      ret = cache->nodesetObjs;
1701
1.16M
            cache->nodesetObjs = (void *) ret->stringval;
1702
1.16M
            cache->numNodeset -= 1;
1703
1.16M
            ret->stringval = NULL;
1704
1.16M
      ret->type = XPATH_NODESET;
1705
1.16M
      ret->boolval = 0;
1706
1.16M
      if (val) {
1707
1.16M
    if ((ret->nodesetval->nodeMax == 0) ||
1708
1.15M
        (val->type == XML_NAMESPACE_DECL))
1709
121k
    {
1710
121k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
12
                        xmlXPathPErrMemory(pctxt);
1712
1.04M
    } else {
1713
1.04M
        ret->nodesetval->nodeTab[0] = val;
1714
1.04M
        ret->nodesetval->nodeNr = 1;
1715
1.04M
    }
1716
1.16M
      }
1717
1.16M
      return(ret);
1718
1.16M
  } else if (cache->miscObjs != NULL) {
1719
5.45k
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
5.45k
      set = xmlXPathNodeSetCreate(val);
1725
5.45k
      if (set == NULL) {
1726
3
                xmlXPathPErrMemory(pctxt);
1727
3
    return(NULL);
1728
3
      }
1729
1730
5.45k
      ret = cache->miscObjs;
1731
5.45k
            cache->miscObjs = (void *) ret->stringval;
1732
5.45k
            cache->numMisc -= 1;
1733
5.45k
            ret->stringval = NULL;
1734
5.45k
      ret->type = XPATH_NODESET;
1735
5.45k
      ret->boolval = 0;
1736
5.45k
      ret->nodesetval = set;
1737
5.45k
      return(ret);
1738
5.45k
  }
1739
1.17M
    }
1740
265k
    ret = xmlXPathNewNodeSet(val);
1741
265k
    if (ret == NULL)
1742
90
        xmlXPathPErrMemory(pctxt);
1743
265k
    return(ret);
1744
1.43M
}
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
623k
{
1757
623k
    xmlXPathObjectPtr ret;
1758
623k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
623k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
56.2k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
56.2k
  if (cache->miscObjs != NULL) {
1764
51.5k
            xmlChar *copy;
1765
1766
51.5k
            if (val == NULL)
1767
283
                val = BAD_CAST "";
1768
51.5k
            copy = xmlStrdup(val);
1769
51.5k
            if (copy == NULL) {
1770
19
                xmlXPathPErrMemory(pctxt);
1771
19
                return(NULL);
1772
19
            }
1773
1774
51.5k
      ret = cache->miscObjs;
1775
51.5k
            cache->miscObjs = (void *) ret->stringval;
1776
51.5k
            cache->numMisc -= 1;
1777
51.5k
      ret->type = XPATH_STRING;
1778
51.5k
            ret->stringval = copy;
1779
51.5k
      return(ret);
1780
51.5k
  }
1781
56.2k
    }
1782
1783
572k
    ret = xmlXPathNewString(val);
1784
572k
    if (ret == NULL)
1785
6
        xmlXPathPErrMemory(pctxt);
1786
572k
    return(ret);
1787
623k
}
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
8.96k
{
1800
8.96k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
8.96k
}
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
617k
{
1814
617k
    xmlXPathObjectPtr ret;
1815
617k
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
617k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
503k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
503k
  if (cache->miscObjs != NULL) {
1821
283k
      ret = cache->miscObjs;
1822
283k
            cache->miscObjs = (void *) ret->stringval;
1823
283k
            cache->numMisc -= 1;
1824
283k
            ret->stringval = NULL;
1825
283k
      ret->type = XPATH_BOOLEAN;
1826
283k
      ret->boolval = (val != 0);
1827
283k
      return(ret);
1828
283k
  }
1829
503k
    }
1830
1831
334k
    ret = xmlXPathNewBoolean(val);
1832
334k
    if (ret == NULL)
1833
16
        xmlXPathPErrMemory(pctxt);
1834
334k
    return(ret);
1835
617k
}
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
1.81M
{
1848
1.81M
    xmlXPathObjectPtr ret;
1849
1.81M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
1.81M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
683k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
683k
  if (cache->miscObjs != NULL) {
1855
453k
      ret = cache->miscObjs;
1856
453k
            cache->miscObjs = (void *) ret->stringval;
1857
453k
            cache->numMisc -= 1;
1858
453k
            ret->stringval = NULL;
1859
453k
      ret->type = XPATH_NUMBER;
1860
453k
      ret->floatval = val;
1861
453k
      return(ret);
1862
453k
  }
1863
683k
    }
1864
1865
1.35M
    ret = xmlXPathNewFloat(val);
1866
1.35M
    if (ret == NULL)
1867
57
        xmlXPathPErrMemory(pctxt);
1868
1.35M
    return(ret);
1869
1.81M
}
1870
1871
/**
1872
 * This is the cached version of #xmlXPathObjectCopy.
1873
 * Acquire a copy of a given object
1874
 *
1875
 * @param pctxt  the XPath context
1876
 * @param val  the original object
1877
 * @returns a created or reused created object.
1878
 */
1879
static xmlXPathObjectPtr
1880
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1881
1.12M
{
1882
1.12M
    xmlXPathObjectPtr ret;
1883
1.12M
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
1.12M
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
1.12M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
557k
  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
18.2k
      case XPATH_STRING:
1901
18.2k
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
539k
      case XPATH_NUMBER:
1905
539k
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
557k
  }
1909
557k
    }
1910
568k
    ret = xmlXPathObjectCopy(val);
1911
568k
    if (ret == NULL)
1912
0
        xmlXPathPErrMemory(pctxt);
1913
568k
    return(ret);
1914
1.12M
}
1915
1916
/************************************************************************
1917
 *                  *
1918
 *    Parser stacks related functions and macros    *
1919
 *                  *
1920
 ************************************************************************/
1921
1922
/**
1923
 * Converts an XPath object to its number value
1924
 *
1925
 * @param ctxt  parser context
1926
 * @param val  an XPath object
1927
 * @returns the number value
1928
 */
1929
static double
1930
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1931
1.38M
                             xmlXPathObjectPtr val) {
1932
1.38M
    double ret = 0.0;
1933
1934
1.38M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
1.38M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
89.0k
    case XPATH_NODESET:
1941
89.0k
    case XPATH_XSLT_TREE: {
1942
89.0k
        xmlChar *str;
1943
1944
89.0k
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
89.0k
        if (str == NULL) {
1946
30
            xmlXPathPErrMemory(ctxt);
1947
30
            ret = xmlXPathNAN;
1948
88.9k
        } else {
1949
88.9k
      ret = xmlXPathCastStringToNumber(str);
1950
88.9k
            xmlFree(str);
1951
88.9k
        }
1952
89.0k
  break;
1953
89.0k
    }
1954
1.14M
    case XPATH_STRING:
1955
1.14M
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
1.14M
  break;
1957
136k
    case XPATH_NUMBER:
1958
136k
  ret = val->floatval;
1959
136k
  break;
1960
7.95k
    case XPATH_BOOLEAN:
1961
7.95k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
7.95k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
1.38M
    }
1968
1.38M
    return(ret);
1969
1.38M
}
1970
1971
/**
1972
 * Pops the top XPath object from the value stack
1973
 *
1974
 * @param ctxt  an XPath evaluation context
1975
 * @returns the XPath object just removed
1976
 */
1977
xmlXPathObject *
1978
xmlXPathValuePop(xmlXPathParserContext *ctxt)
1979
7.70M
{
1980
7.70M
    xmlXPathObjectPtr ret;
1981
1982
7.70M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
22.7k
        return (NULL);
1984
1985
7.68M
    ctxt->valueNr--;
1986
7.68M
    if (ctxt->valueNr > 0)
1987
1.89M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
5.78M
    else
1989
5.78M
        ctxt->value = NULL;
1990
7.68M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
7.68M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
7.68M
    return (ret);
1993
7.70M
}
1994
1995
/**
1996
 * Pushes a new XPath object on top of the value stack. If value is NULL,
1997
 * a memory error is recorded in the parser context.
1998
 *
1999
 * The object is destroyed in case of error.
2000
 *
2001
 * @param ctxt  an XPath evaluation context
2002
 * @param value  the XPath object
2003
 * @returns the number of items on the value stack, or -1 in case of error.
2004
 */
2005
int
2006
xmlXPathValuePush(xmlXPathParserContext *ctxt, xmlXPathObject *value)
2007
7.69M
{
2008
7.69M
    if (ctxt == NULL) return(-1);
2009
7.69M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
315
        xmlXPathPErrMemory(ctxt);
2014
315
        return(-1);
2015
315
    }
2016
7.69M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
284
        xmlXPathObjectPtr *tmp;
2018
284
        int newSize;
2019
2020
284
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
284
                                  10, XPATH_MAX_STACK_DEPTH);
2022
284
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
284
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
284
        if (tmp == NULL) {
2029
3
            xmlXPathPErrMemory(ctxt);
2030
3
            xmlXPathFreeObject(value);
2031
3
            return (-1);
2032
3
        }
2033
281
  ctxt->valueTab = tmp;
2034
281
        ctxt->valueMax = newSize;
2035
281
    }
2036
7.69M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
7.69M
    ctxt->value = value;
2038
7.69M
    return (ctxt->valueNr++);
2039
7.69M
}
2040
2041
/**
2042
 * Pops a boolean from the stack, handling conversion if needed.
2043
 * Check error with xmlXPathCheckError.
2044
 *
2045
 * @param ctxt  an XPath parser context
2046
 * @returns the boolean
2047
 */
2048
int
2049
0
xmlXPathPopBoolean (xmlXPathParserContext *ctxt) {
2050
0
    xmlXPathObjectPtr obj;
2051
0
    int ret;
2052
2053
0
    obj = xmlXPathValuePop(ctxt);
2054
0
    if (obj == NULL) {
2055
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2056
0
  return(0);
2057
0
    }
2058
0
    if (obj->type != XPATH_BOOLEAN)
2059
0
  ret = xmlXPathCastToBoolean(obj);
2060
0
    else
2061
0
        ret = obj->boolval;
2062
0
    xmlXPathReleaseObject(ctxt->context, obj);
2063
0
    return(ret);
2064
0
}
2065
2066
/**
2067
 * Pops a number from the stack, handling conversion if needed.
2068
 * Check error with xmlXPathCheckError.
2069
 *
2070
 * @param ctxt  an XPath parser context
2071
 * @returns the number
2072
 */
2073
double
2074
0
xmlXPathPopNumber (xmlXPathParserContext *ctxt) {
2075
0
    xmlXPathObjectPtr obj;
2076
0
    double ret;
2077
2078
0
    obj = xmlXPathValuePop(ctxt);
2079
0
    if (obj == NULL) {
2080
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2081
0
  return(0);
2082
0
    }
2083
0
    if (obj->type != XPATH_NUMBER)
2084
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2085
0
    else
2086
0
        ret = obj->floatval;
2087
0
    xmlXPathReleaseObject(ctxt->context, obj);
2088
0
    return(ret);
2089
0
}
2090
2091
/**
2092
 * Pops a string from the stack, handling conversion if needed.
2093
 * Check error with xmlXPathCheckError.
2094
 *
2095
 * @param ctxt  an XPath parser context
2096
 * @returns the string
2097
 */
2098
xmlChar *
2099
0
xmlXPathPopString (xmlXPathParserContext *ctxt) {
2100
0
    xmlXPathObjectPtr obj;
2101
0
    xmlChar * ret;
2102
2103
0
    obj = xmlXPathValuePop(ctxt);
2104
0
    if (obj == NULL) {
2105
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2106
0
  return(NULL);
2107
0
    }
2108
0
    ret = xmlXPathCastToString(obj);
2109
0
    if (ret == NULL)
2110
0
        xmlXPathPErrMemory(ctxt);
2111
0
    xmlXPathReleaseObject(ctxt->context, obj);
2112
0
    return(ret);
2113
0
}
2114
2115
/**
2116
 * Pops a node-set from the stack, handling conversion if needed.
2117
 * Check error with xmlXPathCheckError.
2118
 *
2119
 * @param ctxt  an XPath parser context
2120
 * @returns the node-set
2121
 */
2122
xmlNodeSet *
2123
0
xmlXPathPopNodeSet (xmlXPathParserContext *ctxt) {
2124
0
    xmlXPathObjectPtr obj;
2125
0
    xmlNodeSetPtr ret;
2126
2127
0
    if (ctxt == NULL) return(NULL);
2128
0
    if (ctxt->value == NULL) {
2129
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130
0
  return(NULL);
2131
0
    }
2132
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2133
0
  xmlXPathSetTypeError(ctxt);
2134
0
  return(NULL);
2135
0
    }
2136
0
    obj = xmlXPathValuePop(ctxt);
2137
0
    ret = obj->nodesetval;
2138
0
    obj->nodesetval = NULL;
2139
0
    xmlXPathReleaseObject(ctxt->context, obj);
2140
0
    return(ret);
2141
0
}
2142
2143
/**
2144
 * Pops an external object from the stack, handling conversion if needed.
2145
 * Check error with xmlXPathCheckError.
2146
 *
2147
 * @param ctxt  an XPath parser context
2148
 * @returns the object
2149
 */
2150
void *
2151
0
xmlXPathPopExternal (xmlXPathParserContext *ctxt) {
2152
0
    xmlXPathObjectPtr obj;
2153
0
    void * ret;
2154
2155
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2156
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157
0
  return(NULL);
2158
0
    }
2159
0
    if (ctxt->value->type != XPATH_USERS) {
2160
0
  xmlXPathSetTypeError(ctxt);
2161
0
  return(NULL);
2162
0
    }
2163
0
    obj = xmlXPathValuePop(ctxt);
2164
0
    ret = obj->user;
2165
0
    obj->user = NULL;
2166
0
    xmlXPathReleaseObject(ctxt->context, obj);
2167
0
    return(ret);
2168
0
}
2169
2170
/*
2171
 * Macros for accessing the content. Those should be used only by the parser,
2172
 * and not exported.
2173
 *
2174
 * Dirty macros, i.e. one need to make assumption on the context to use them
2175
 *
2176
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2177
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2178
 *           in ISO-Latin or UTF-8.
2179
 *           This should be used internally by the parser
2180
 *           only to compare to ASCII values otherwise it would break when
2181
 *           running with UTF-8 encoding.
2182
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2183
 *           to compare on ASCII based substring.
2184
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2185
 *           strings within the parser.
2186
 *   CURRENT Returns the current char value, with the full decoding of
2187
 *           UTF-8 if we are using this mode. It returns an int.
2188
 *   NEXT    Skip to the next character, this does the proper decoding
2189
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2190
 *           It returns the pointer to the current xmlChar.
2191
 */
2192
2193
3.45M
#define CUR (*ctxt->cur)
2194
27.1k
#define SKIP(val) ctxt->cur += (val)
2195
403k
#define NXT(val) ctxt->cur[(val)]
2196
17.9k
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
1.76M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
1.31M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2203
2204
2205
#ifndef DBL_DIG
2206
#define DBL_DIG 16
2207
#endif
2208
#ifndef DBL_EPSILON
2209
#define DBL_EPSILON 1E-9
2210
#endif
2211
2212
2.58k
#define UPPER_DOUBLE 1E9
2213
1.62k
#define LOWER_DOUBLE 1E-5
2214
#define LOWER_DOUBLE_EXP 5
2215
2216
#define INTEGER_DIGITS DBL_DIG
2217
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2218
1.63k
#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
5.92k
{
2230
5.92k
    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
5.92k
    default:
2240
5.92k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
5.92k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
5.92k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
4.96k
                   (number == (int) number)) {
2248
3.34k
      char work[30];
2249
3.34k
      char *ptr, *cur;
2250
3.34k
      int value = (int) number;
2251
2252
3.34k
            ptr = &buffer[0];
2253
3.34k
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
3.34k
      } else {
2256
3.34k
    snprintf(work, 29, "%d", value);
2257
3.34k
    cur = &work[0];
2258
8.93k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
5.59k
        *ptr++ = *cur++;
2260
5.59k
    }
2261
3.34k
      }
2262
3.34k
      if (ptr - buffer < buffersize) {
2263
3.34k
    *ptr = 0;
2264
3.34k
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
3.34k
  } else {
2269
      /*
2270
        For the dimension of work,
2271
            DBL_DIG is number of significant digits
2272
      EXPONENT is only needed for "scientific notation"
2273
            3 is sign, decimal point, and terminating zero
2274
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2275
        Note that this dimension is slightly (a few characters)
2276
        larger than actually necessary.
2277
      */
2278
2.58k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
2.58k
      int integer_place, fraction_place;
2280
2.58k
      char *ptr;
2281
2.58k
      char *after_fraction;
2282
2.58k
      double absolute_value;
2283
2.58k
      int size;
2284
2285
2.58k
      absolute_value = fabs(number);
2286
2287
      /*
2288
       * First choose format - scientific or regular floating point.
2289
       * In either case, result is in work, and after_fraction points
2290
       * just past the fractional part.
2291
      */
2292
2.58k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
1.62k
      (absolute_value < LOWER_DOUBLE)) &&
2294
1.63k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
1.63k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
1.63k
    fraction_place = DBL_DIG - 1;
2298
1.63k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
1.63k
       integer_place, fraction_place, number);
2300
8.64k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
1.63k
      }
2303
945
      else {
2304
    /* Use regular notation */
2305
945
    if (absolute_value > 0.0) {
2306
945
        integer_place = (int)log10(absolute_value);
2307
945
        if (integer_place > 0)
2308
216
            fraction_place = DBL_DIG - integer_place - 1;
2309
729
        else
2310
729
            fraction_place = DBL_DIG - integer_place;
2311
945
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
945
    size = snprintf(work, sizeof(work), "%0.*f",
2315
945
        fraction_place, number);
2316
945
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
3.54k
      while (work[0] == ' ') {
2320
20.1k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
959
    size--;
2322
959
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
2.58k
      after_fraction = work + size;
2326
2.58k
      ptr = after_fraction;
2327
33.1k
      while (*(--ptr) == '0')
2328
30.6k
    ;
2329
2.58k
      if (*ptr != '.')
2330
1.60k
          ptr++;
2331
9.58k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
2.58k
      size = strlen(work) + 1;
2335
2.58k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
2.58k
      memmove(buffer, work, size);
2340
2.58k
  }
2341
5.92k
  break;
2342
5.92k
    }
2343
5.92k
}
2344
2345
2346
/************************************************************************
2347
 *                  *
2348
 *      Routines to handle NodeSets     *
2349
 *                  *
2350
 ************************************************************************/
2351
2352
/**
2353
 * Call this routine to speed up XPath computation on static documents.
2354
 * This stamps all the element nodes with the document order
2355
 * Like for line information, the order is kept in the element->content
2356
 * field, the value stored is actually - the node number (starting at -1)
2357
 * to be able to differentiate from line numbers.
2358
 *
2359
 * @param doc  an input document
2360
 * @returns the number of elements found in the document or -1 in case
2361
 *    of error.
2362
 */
2363
long
2364
0
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
0
    XML_INTPTR_T count = 0;
2366
0
    xmlNodePtr cur;
2367
2368
0
    if (doc == NULL)
2369
0
  return(-1);
2370
0
    cur = doc->children;
2371
0
    while (cur != NULL) {
2372
0
  if (cur->type == XML_ELEMENT_NODE) {
2373
0
            count += 1;
2374
0
            cur->content = XML_INT_TO_PTR(-count);
2375
0
      if (cur->children != NULL) {
2376
0
    cur = cur->children;
2377
0
    continue;
2378
0
      }
2379
0
  }
2380
0
  if (cur->next != NULL) {
2381
0
      cur = cur->next;
2382
0
      continue;
2383
0
  }
2384
0
  do {
2385
0
      cur = cur->parent;
2386
0
      if (cur == NULL)
2387
0
    break;
2388
0
      if (cur == (xmlNodePtr) doc) {
2389
0
    cur = NULL;
2390
0
    break;
2391
0
      }
2392
0
      if (cur->next != NULL) {
2393
0
    cur = cur->next;
2394
0
    break;
2395
0
      }
2396
0
  } while (cur != NULL);
2397
0
    }
2398
0
    return(count);
2399
0
}
2400
2401
/**
2402
 * Compare two nodes w.r.t document order
2403
 *
2404
 * @param node1  the first node
2405
 * @param node2  the second node
2406
 * @returns -2 in case of error 1 if first point < second point, 0 if
2407
 *         it's the same node, -1 otherwise
2408
 */
2409
int
2410
0
xmlXPathCmpNodes(xmlNode *node1, xmlNode *node2) {
2411
0
    int depth1, depth2;
2412
0
    int attr1 = 0, attr2 = 0;
2413
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2414
0
    xmlNodePtr cur, root;
2415
2416
0
    if ((node1 == NULL) || (node2 == NULL))
2417
0
  return(-2);
2418
    /*
2419
     * a couple of optimizations which will avoid computations in most cases
2420
     */
2421
0
    if (node1 == node2)   /* trivial case */
2422
0
  return(0);
2423
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2424
0
  attr1 = 1;
2425
0
  attrNode1 = node1;
2426
0
  node1 = node1->parent;
2427
0
    }
2428
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2429
0
  attr2 = 1;
2430
0
  attrNode2 = node2;
2431
0
  node2 = node2->parent;
2432
0
    }
2433
0
    if (node1 == node2) {
2434
0
  if (attr1 == attr2) {
2435
      /* not required, but we keep attributes in order */
2436
0
      if (attr1 != 0) {
2437
0
          cur = attrNode2->prev;
2438
0
    while (cur != NULL) {
2439
0
        if (cur == attrNode1)
2440
0
            return (1);
2441
0
        cur = cur->prev;
2442
0
    }
2443
0
    return (-1);
2444
0
      }
2445
0
      return(0);
2446
0
  }
2447
0
  if (attr2 == 1)
2448
0
      return(1);
2449
0
  return(-1);
2450
0
    }
2451
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2452
0
        (node2->type == XML_NAMESPACE_DECL))
2453
0
  return(1);
2454
0
    if (node1 == node2->prev)
2455
0
  return(1);
2456
0
    if (node1 == node2->next)
2457
0
  return(-1);
2458
2459
    /*
2460
     * Speedup using document order if available.
2461
     */
2462
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2463
0
  (node2->type == XML_ELEMENT_NODE) &&
2464
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2465
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2466
0
  (node1->doc == node2->doc)) {
2467
0
  XML_INTPTR_T l1, l2;
2468
2469
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2470
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2471
0
  if (l1 < l2)
2472
0
      return(1);
2473
0
  if (l1 > l2)
2474
0
      return(-1);
2475
0
    }
2476
2477
    /*
2478
     * compute depth to root
2479
     */
2480
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2481
0
  if (cur->parent == node1)
2482
0
      return(1);
2483
0
  depth2++;
2484
0
    }
2485
0
    root = cur;
2486
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2487
0
  if (cur->parent == node2)
2488
0
      return(-1);
2489
0
  depth1++;
2490
0
    }
2491
    /*
2492
     * Distinct document (or distinct entities :-( ) case.
2493
     */
2494
0
    if (root != cur) {
2495
0
  return(-2);
2496
0
    }
2497
    /*
2498
     * get the nearest common ancestor.
2499
     */
2500
0
    while (depth1 > depth2) {
2501
0
  depth1--;
2502
0
  node1 = node1->parent;
2503
0
    }
2504
0
    while (depth2 > depth1) {
2505
0
  depth2--;
2506
0
  node2 = node2->parent;
2507
0
    }
2508
0
    while (node1->parent != node2->parent) {
2509
0
  node1 = node1->parent;
2510
0
  node2 = node2->parent;
2511
  /* should not happen but just in case ... */
2512
0
  if ((node1 == NULL) || (node2 == NULL))
2513
0
      return(-2);
2514
0
    }
2515
    /*
2516
     * Find who's first.
2517
     */
2518
0
    if (node1 == node2->prev)
2519
0
  return(1);
2520
0
    if (node1 == node2->next)
2521
0
  return(-1);
2522
    /*
2523
     * Speedup using document order if available.
2524
     */
2525
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2526
0
  (node2->type == XML_ELEMENT_NODE) &&
2527
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2528
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2529
0
  (node1->doc == node2->doc)) {
2530
0
  XML_INTPTR_T l1, l2;
2531
2532
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2533
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2534
0
  if (l1 < l2)
2535
0
      return(1);
2536
0
  if (l1 > l2)
2537
0
      return(-1);
2538
0
    }
2539
2540
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2541
0
  if (cur == node2)
2542
0
      return(1);
2543
0
    return(-1); /* assume there is no sibling list corruption */
2544
0
}
2545
2546
/**
2547
 * Sort the node set in document order
2548
 *
2549
 * @param set  the node set
2550
 */
2551
void
2552
126k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
126k
    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
126k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
126k
#endif /* WITH_TIM_SORT */
2591
126k
}
2592
2593
3.64M
#define XML_NODESET_DEFAULT 10
2594
/**
2595
 * Namespace node in libxml don't match the XPath semantic. In a node set
2596
 * the namespace nodes are duplicated and the next pointer is set to the
2597
 * parent node in the XPath semantic.
2598
 *
2599
 * @param node  the parent node of the namespace XPath node
2600
 * @param ns  the libxml namespace declaration node.
2601
 * @returns the newly created object.
2602
 */
2603
static xmlNodePtr
2604
1.67M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
1.67M
    xmlNsPtr cur;
2606
2607
1.67M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
1.67M
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2610
0
  return((xmlNodePtr) ns);
2611
2612
    /*
2613
     * Allocate a new Namespace and fill the fields.
2614
     */
2615
1.67M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
1.67M
    if (cur == NULL)
2617
19
  return(NULL);
2618
1.67M
    memset(cur, 0, sizeof(xmlNs));
2619
1.67M
    cur->type = XML_NAMESPACE_DECL;
2620
1.67M
    if (ns->href != NULL) {
2621
1.67M
  cur->href = xmlStrdup(ns->href);
2622
1.67M
        if (cur->href == NULL) {
2623
16
            xmlFree(cur);
2624
16
            return(NULL);
2625
16
        }
2626
1.67M
    }
2627
1.67M
    if (ns->prefix != NULL) {
2628
1.16M
  cur->prefix = xmlStrdup(ns->prefix);
2629
1.16M
        if (cur->prefix == NULL) {
2630
14
            xmlFree((xmlChar *) cur->href);
2631
14
            xmlFree(cur);
2632
14
            return(NULL);
2633
14
        }
2634
1.16M
    }
2635
1.67M
    cur->next = (xmlNsPtr) node;
2636
1.67M
    return((xmlNodePtr) cur);
2637
1.67M
}
2638
2639
/**
2640
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2641
 * the namespace nodes are duplicated and the next pointer is set to the
2642
 * parent node in the XPath semantic. Check if such a node needs to be freed
2643
 *
2644
 * @param ns  the XPath namespace node found in a nodeset.
2645
 */
2646
void
2647
1.67M
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
1.67M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
1.67M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
1.67M
  if (ns->href != NULL)
2653
1.67M
      xmlFree((xmlChar *)ns->href);
2654
1.67M
  if (ns->prefix != NULL)
2655
1.16M
      xmlFree((xmlChar *)ns->prefix);
2656
1.67M
  xmlFree(ns);
2657
1.67M
    }
2658
1.67M
}
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
2.27M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
2.27M
    xmlNodeSetPtr ret;
2669
2670
2.27M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
2.27M
    if (ret == NULL)
2672
117
  return(NULL);
2673
2.27M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
2.27M
    if (val != NULL) {
2675
270k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
270k
               sizeof(xmlNodePtr));
2677
270k
  if (ret->nodeTab == NULL) {
2678
34
      xmlFree(ret);
2679
34
      return(NULL);
2680
34
  }
2681
270k
  memset(ret->nodeTab, 0 ,
2682
270k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
270k
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
270k
  if (val->type == XML_NAMESPACE_DECL) {
2685
36.7k
      xmlNsPtr ns = (xmlNsPtr) val;
2686
36.7k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
36.7k
            if (nsNode == NULL) {
2689
4
                xmlXPathFreeNodeSet(ret);
2690
4
                return(NULL);
2691
4
            }
2692
36.7k
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
36.7k
  } else
2694
233k
      ret->nodeTab[ret->nodeNr++] = val;
2695
270k
    }
2696
2.27M
    return(ret);
2697
2.27M
}
2698
2699
/**
2700
 * checks whether `cur` contains `val`
2701
 *
2702
 * @param cur  the node-set
2703
 * @param val  the node
2704
 * @returns true (1) if `cur` contains `val`, false (0) otherwise
2705
 */
2706
int
2707
0
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
0
    int i;
2709
2710
0
    if ((cur == NULL) || (val == NULL)) return(0);
2711
0
    if (val->type == XML_NAMESPACE_DECL) {
2712
0
  for (i = 0; i < cur->nodeNr; i++) {
2713
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2714
0
    xmlNsPtr ns1, ns2;
2715
2716
0
    ns1 = (xmlNsPtr) val;
2717
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2718
0
    if (ns1 == ns2)
2719
0
        return(1);
2720
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2721
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2722
0
        return(1);
2723
0
      }
2724
0
  }
2725
0
    } else {
2726
0
  for (i = 0; i < cur->nodeNr; i++) {
2727
0
      if (cur->nodeTab[i] == val)
2728
0
    return(1);
2729
0
  }
2730
0
    }
2731
0
    return(0);
2732
0
}
2733
2734
static int
2735
2.44M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
2.44M
    xmlNodePtr *temp;
2737
2.44M
    int newSize;
2738
2739
2.44M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
2.44M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
2.44M
    if (newSize < 0)
2742
0
        return(-1);
2743
2.44M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
2.44M
    if (temp == NULL)
2745
259
        return(-1);
2746
2.44M
    cur->nodeMax = newSize;
2747
2.44M
    cur->nodeTab = temp;
2748
2749
2.44M
    return(0);
2750
2.44M
}
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.38M
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
1.38M
    int i;
2763
1.38M
    xmlNodePtr nsNode;
2764
2765
1.38M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
1.38M
        (ns->type != XML_NAMESPACE_DECL) ||
2767
1.38M
  (node->type != XML_ELEMENT_NODE))
2768
0
  return(-1);
2769
2770
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2771
    /*
2772
     * prevent duplicates
2773
     */
2774
3.33M
    for (i = 0;i < cur->nodeNr;i++) {
2775
1.94M
        if ((cur->nodeTab[i] != NULL) &&
2776
1.94M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
1.94M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
1.94M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
1.94M
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
1.38M
    if (cur->nodeNr >= cur->nodeMax) {
2786
15.7k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
7
            return(-1);
2788
15.7k
    }
2789
1.38M
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
1.38M
    if(nsNode == NULL)
2791
19
        return(-1);
2792
1.38M
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
1.38M
    return(0);
2794
1.38M
}
2795
2796
/**
2797
 * add a new xmlNode to an existing NodeSet
2798
 *
2799
 * @param cur  the initial node set
2800
 * @param val  a new xmlNode
2801
 * @returns 0 in case of success, and -1 in case of error
2802
 */
2803
int
2804
3.55k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
3.55k
    int i;
2806
2807
3.55k
    if ((cur == NULL) || (val == NULL)) return(-1);
2808
2809
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2810
    /*
2811
     * prevent duplicates
2812
     */
2813
7.32k
    for (i = 0;i < cur->nodeNr;i++)
2814
4.25k
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
3.06k
    if (cur->nodeNr >= cur->nodeMax) {
2820
2.79k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
7
            return(-1);
2822
2.79k
    }
2823
2824
3.05k
    if (val->type == XML_NAMESPACE_DECL) {
2825
0
  xmlNsPtr ns = (xmlNsPtr) val;
2826
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828
0
        if (nsNode == NULL)
2829
0
            return(-1);
2830
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2831
0
    } else
2832
3.05k
  cur->nodeTab[cur->nodeNr++] = val;
2833
3.05k
    return(0);
2834
3.05k
}
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
32.0M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
32.0M
    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
32.0M
    if (cur->nodeNr >= cur->nodeMax) {
2853
2.01M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
121
            return(-1);
2855
2.01M
    }
2856
2857
32.0M
    if (val->type == XML_NAMESPACE_DECL) {
2858
242k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
242k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
242k
        if (nsNode == NULL)
2862
8
            return(-1);
2863
242k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
242k
    } else
2865
31.8M
  cur->nodeTab[cur->nodeNr++] = val;
2866
32.0M
    return(0);
2867
32.0M
}
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
807k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
807k
    int i, j, initNr, skip;
2882
807k
    xmlNodePtr n1, n2;
2883
2884
807k
    if (val1 == NULL) {
2885
1
  val1 = xmlXPathNodeSetCreate(NULL);
2886
1
        if (val1 == NULL)
2887
0
            return (NULL);
2888
1
    }
2889
807k
    if (val2 == NULL)
2890
28
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
807k
    initNr = val1->nodeNr;
2894
2895
3.37M
    for (i = 0;i < val2->nodeNr;i++) {
2896
2.56M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
2.56M
  skip = 0;
2901
9.09M
  for (j = 0; j < initNr; j++) {
2902
6.74M
      n1 = val1->nodeTab[j];
2903
6.74M
      if (n1 == n2) {
2904
202k
    skip = 1;
2905
202k
    break;
2906
6.53M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
2.28M
           (n2->type == XML_NAMESPACE_DECL)) {
2908
2.24M
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
15.2k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
15.2k
      ((xmlNsPtr) n2)->prefix)))
2911
12.4k
    {
2912
12.4k
        skip = 1;
2913
12.4k
        break;
2914
12.4k
    }
2915
2.24M
      }
2916
6.74M
  }
2917
2.56M
  if (skip)
2918
215k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
2.35M
        if (val1->nodeNr >= val1->nodeMax) {
2924
276k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
23
                goto error;
2926
276k
        }
2927
2.35M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
9.28k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
9.28k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
9.28k
            if (nsNode == NULL)
2932
18
                goto error;
2933
9.26k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
9.26k
  } else
2935
2.34M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
2.35M
    }
2937
2938
807k
    return(val1);
2939
2940
41
error:
2941
41
    xmlXPathFreeNodeSet(val1);
2942
41
    return(NULL);
2943
807k
}
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
735k
{
2959
735k
    {
2960
735k
  int i, j, initNbSet1;
2961
735k
  xmlNodePtr n1, n2;
2962
2963
735k
  initNbSet1 = set1->nodeNr;
2964
20.3M
  for (i = 0;i < set2->nodeNr;i++) {
2965
19.5M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
6.09G
      for (j = 0; j < initNbSet1; j++) {
2970
6.08G
    n1 = set1->nodeTab[j];
2971
6.08G
    if (n1 == n2) {
2972
17.4M
        goto skip_node;
2973
6.07G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
17.6M
        (n2->type == XML_NAMESPACE_DECL))
2975
16.9M
    {
2976
16.9M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
64.4k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
64.4k
      ((xmlNsPtr) n2)->prefix)))
2979
0
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
0
      goto skip_node;
2985
0
        }
2986
16.9M
    }
2987
6.08G
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
2.11M
            if (set1->nodeNr >= set1->nodeMax) {
2992
94.4k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
42
                    goto error;
2994
94.4k
            }
2995
2.11M
      set1->nodeTab[set1->nodeNr++] = n2;
2996
19.5M
skip_node:
2997
19.5M
            set2->nodeTab[i] = NULL;
2998
19.5M
  }
2999
735k
    }
3000
735k
    set2->nodeNr = 0;
3001
735k
    return(set1);
3002
3003
42
error:
3004
42
    xmlXPathFreeNodeSet(set1);
3005
42
    xmlXPathNodeSetClear(set2, 1);
3006
42
    return(NULL);
3007
735k
}
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
440k
{
3022
440k
    {
3023
440k
  int i;
3024
440k
  xmlNodePtr n2;
3025
3026
1.84M
  for (i = 0;i < set2->nodeNr;i++) {
3027
1.39M
      n2 = set2->nodeTab[i];
3028
1.39M
            if (set1->nodeNr >= set1->nodeMax) {
3029
40.5k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
59
                    goto error;
3031
40.5k
            }
3032
1.39M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
1.39M
            set2->nodeTab[i] = NULL;
3034
1.39M
  }
3035
440k
    }
3036
440k
    set2->nodeNr = 0;
3037
440k
    return(set1);
3038
3039
59
error:
3040
59
    xmlXPathFreeNodeSet(set1);
3041
59
    xmlXPathNodeSetClear(set2, 1);
3042
59
    return(NULL);
3043
440k
}
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
2.25M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
2.25M
    if (obj == NULL) return;
3103
2.25M
    if (obj->nodeTab != NULL) {
3104
608k
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
16.9M
  for (i = 0;i < obj->nodeNr;i++)
3108
16.3M
      if ((obj->nodeTab[i] != NULL) &&
3109
16.3M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
1.43M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
608k
  xmlFree(obj->nodeTab);
3112
608k
    }
3113
2.25M
    xmlFree(obj);
3114
2.25M
}
3115
3116
/**
3117
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3118
 * are feed) starting with the entry at `pos`, but does *not* free the list
3119
 * itself. Sets the length of the list to `pos`.
3120
 *
3121
 * @param set  the node set to be cleared
3122
 * @param pos  the start position to clear from
3123
 * @param hasNsNodes  the node set might contain namespace nodes
3124
 */
3125
static void
3126
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3127
7.86k
{
3128
7.86k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
7.86k
    else if ((hasNsNodes)) {
3131
7.34k
  int i;
3132
7.34k
  xmlNodePtr node;
3133
3134
287k
  for (i = pos; i < set->nodeNr; i++) {
3135
280k
      node = set->nodeTab[i];
3136
280k
      if ((node != NULL) &&
3137
280k
    (node->type == XML_NAMESPACE_DECL))
3138
35.6k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
280k
  }
3140
7.34k
    }
3141
7.86k
    set->nodeNr = pos;
3142
7.86k
}
3143
3144
/**
3145
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3146
 * are feed), but does *not* free the list itself. Sets the length of the
3147
 * list to 0.
3148
 *
3149
 * @param set  the node set to clear
3150
 * @param hasNsNodes  the node set might contain namespace nodes
3151
 */
3152
static void
3153
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3154
1.27k
{
3155
1.27k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
1.27k
}
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
11.9k
{
3168
11.9k
    int i;
3169
11.9k
    xmlNodePtr node;
3170
3171
11.9k
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
604k
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
592k
        node = set->nodeTab[i];
3175
592k
        if ((node != NULL) &&
3176
592k
            (node->type == XML_NAMESPACE_DECL))
3177
680
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
592k
    }
3179
11.9k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
11.9k
    set->nodeNr = 1;
3181
11.9k
}
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
266k
xmlXPathNewNodeSet(xmlNode *val) {
3192
266k
    xmlXPathObjectPtr ret;
3193
3194
266k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
266k
    if (ret == NULL)
3196
29
  return(NULL);
3197
266k
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
266k
    ret->type = XPATH_NODESET;
3199
266k
    ret->boolval = 0;
3200
266k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
266k
    if (ret->nodesetval == NULL) {
3202
69
        xmlFree(ret);
3203
69
        return(NULL);
3204
69
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
266k
    return(ret);
3207
266k
}
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
288k
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
288k
    xmlXPathObjectPtr ret;
3269
3270
288k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
288k
    if (ret == NULL) {
3272
78
        xmlXPathFreeNodeSet(val);
3273
78
  return(NULL);
3274
78
    }
3275
288k
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
288k
    ret->type = XPATH_NODESET;
3277
288k
    ret->nodesetval = val;
3278
288k
    return(ret);
3279
288k
}
3280
3281
/**
3282
 * Free up the xmlXPathObject `obj` but don't deallocate the objects in
3283
 * the list contrary to #xmlXPathFreeObject.
3284
 *
3285
 * @param obj  an existing NodeSetList object
3286
 */
3287
void
3288
0
xmlXPathFreeNodeSetList(xmlXPathObject *obj) {
3289
0
    if (obj == NULL) return;
3290
0
    xmlFree(obj);
3291
0
}
3292
3293
/**
3294
 * Implements the EXSLT - Sets difference() function:
3295
 *    node-set set:difference (node-set, node-set)
3296
 *
3297
 * @param nodes1  a node-set
3298
 * @param nodes2  a node-set
3299
 * @returns the difference between the two node sets, or nodes1 if
3300
 *         nodes2 is empty
3301
 */
3302
xmlNodeSet *
3303
0
xmlXPathDifference (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3304
0
    xmlNodeSetPtr ret;
3305
0
    int i, l1;
3306
0
    xmlNodePtr cur;
3307
3308
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3309
0
  return(nodes1);
3310
3311
0
    ret = xmlXPathNodeSetCreate(NULL);
3312
0
    if (ret == NULL)
3313
0
        return(NULL);
3314
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3315
0
  return(ret);
3316
3317
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3318
3319
0
    for (i = 0; i < l1; i++) {
3320
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3321
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3322
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3323
0
                xmlXPathFreeNodeSet(ret);
3324
0
          return(NULL);
3325
0
            }
3326
0
  }
3327
0
    }
3328
0
    return(ret);
3329
0
}
3330
3331
/**
3332
 * Implements the EXSLT - Sets intersection() function:
3333
 *    node-set set:intersection (node-set, node-set)
3334
 *
3335
 * @param nodes1  a node-set
3336
 * @param nodes2  a node-set
3337
 * @returns a node set comprising the nodes that are within both the
3338
 *         node sets passed as arguments
3339
 */
3340
xmlNodeSet *
3341
0
xmlXPathIntersection (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3342
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3343
0
    int i, l1;
3344
0
    xmlNodePtr cur;
3345
3346
0
    if (ret == NULL)
3347
0
        return(ret);
3348
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3349
0
  return(ret);
3350
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3351
0
  return(ret);
3352
3353
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3354
3355
0
    for (i = 0; i < l1; i++) {
3356
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3357
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3358
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3359
0
                xmlXPathFreeNodeSet(ret);
3360
0
          return(NULL);
3361
0
            }
3362
0
  }
3363
0
    }
3364
0
    return(ret);
3365
0
}
3366
3367
/**
3368
 * Implements the EXSLT - Sets distinct() function:
3369
 *    node-set set:distinct (node-set)
3370
 *
3371
 * @param nodes  a node-set, sorted by document order
3372
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3373
 *         it is empty
3374
 */
3375
xmlNodeSet *
3376
0
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3377
0
    xmlNodeSetPtr ret;
3378
0
    xmlHashTablePtr hash;
3379
0
    int i, l;
3380
0
    xmlChar * strval;
3381
0
    xmlNodePtr cur;
3382
3383
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3384
0
  return(nodes);
3385
3386
0
    ret = xmlXPathNodeSetCreate(NULL);
3387
0
    if (ret == NULL)
3388
0
        return(ret);
3389
0
    l = xmlXPathNodeSetGetLength(nodes);
3390
0
    hash = xmlHashCreate (l);
3391
0
    for (i = 0; i < l; i++) {
3392
0
  cur = xmlXPathNodeSetItem(nodes, i);
3393
0
  strval = xmlXPathCastNodeToString(cur);
3394
0
  if (xmlHashLookup(hash, strval) == NULL) {
3395
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3396
0
                xmlFree(strval);
3397
0
                goto error;
3398
0
            }
3399
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3400
0
          goto error;
3401
0
  } else {
3402
0
      xmlFree(strval);
3403
0
  }
3404
0
    }
3405
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3406
0
    return(ret);
3407
3408
0
error:
3409
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3410
0
    xmlXPathFreeNodeSet(ret);
3411
0
    return(NULL);
3412
0
}
3413
3414
/**
3415
 * Implements the EXSLT - Sets distinct() function:
3416
 *    node-set set:distinct (node-set)
3417
 * `nodes` is sorted by document order, then exslSetsDistinctSorted
3418
 * is called with the sorted node-set
3419
 *
3420
 * @param nodes  a node-set
3421
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3422
 *         it is empty
3423
 */
3424
xmlNodeSet *
3425
0
xmlXPathDistinct (xmlNodeSet *nodes) {
3426
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3427
0
  return(nodes);
3428
3429
0
    xmlXPathNodeSetSort(nodes);
3430
0
    return(xmlXPathDistinctSorted(nodes));
3431
0
}
3432
3433
/**
3434
 * Implements the EXSLT - Sets has-same-nodes function:
3435
 *    boolean set:has-same-node(node-set, node-set)
3436
 *
3437
 * @param nodes1  a node-set
3438
 * @param nodes2  a node-set
3439
 * @returns true (1) if `nodes1` shares any node with `nodes2`, false (0)
3440
 *         otherwise
3441
 */
3442
int
3443
0
xmlXPathHasSameNodes (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3444
0
    int i, l;
3445
0
    xmlNodePtr cur;
3446
3447
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3448
0
  xmlXPathNodeSetIsEmpty(nodes2))
3449
0
  return(0);
3450
3451
0
    l = xmlXPathNodeSetGetLength(nodes1);
3452
0
    for (i = 0; i < l; i++) {
3453
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3454
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3455
0
      return(1);
3456
0
    }
3457
0
    return(0);
3458
0
}
3459
3460
/**
3461
 * Implements the EXSLT - Sets leading() function:
3462
 *    node-set set:leading (node-set, node-set)
3463
 *
3464
 * @param nodes  a node-set, sorted by document order
3465
 * @param node  a node
3466
 * @returns the nodes in `nodes` that precede `node` in document order,
3467
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3468
 *         doesn't contain `node`
3469
 */
3470
xmlNodeSet *
3471
0
xmlXPathNodeLeadingSorted (xmlNodeSet *nodes, xmlNode *node) {
3472
0
    int i, l;
3473
0
    xmlNodePtr cur;
3474
0
    xmlNodeSetPtr ret;
3475
3476
0
    if (node == NULL)
3477
0
  return(nodes);
3478
3479
0
    ret = xmlXPathNodeSetCreate(NULL);
3480
0
    if (ret == NULL)
3481
0
        return(ret);
3482
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3483
0
  (!xmlXPathNodeSetContains(nodes, node)))
3484
0
  return(ret);
3485
3486
0
    l = xmlXPathNodeSetGetLength(nodes);
3487
0
    for (i = 0; i < l; i++) {
3488
0
  cur = xmlXPathNodeSetItem(nodes, i);
3489
0
  if (cur == node)
3490
0
      break;
3491
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3492
0
            xmlXPathFreeNodeSet(ret);
3493
0
      return(NULL);
3494
0
        }
3495
0
    }
3496
0
    return(ret);
3497
0
}
3498
3499
/**
3500
 * Implements the EXSLT - Sets leading() function:
3501
 *    node-set set:leading (node-set, node-set)
3502
 * `nodes` is sorted by document order, then exslSetsNodeLeadingSorted
3503
 * is called.
3504
 *
3505
 * @param nodes  a node-set
3506
 * @param node  a node
3507
 * @returns the nodes in `nodes` that precede `node` in document order,
3508
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3509
 *         doesn't contain `node`
3510
 */
3511
xmlNodeSet *
3512
0
xmlXPathNodeLeading (xmlNodeSet *nodes, xmlNode *node) {
3513
0
    xmlXPathNodeSetSort(nodes);
3514
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3515
0
}
3516
3517
/**
3518
 * Implements the EXSLT - Sets leading() function:
3519
 *    node-set set:leading (node-set, node-set)
3520
 *
3521
 * @param nodes1  a node-set, sorted by document order
3522
 * @param nodes2  a node-set, sorted by document order
3523
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3524
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3525
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3526
 */
3527
xmlNodeSet *
3528
0
xmlXPathLeadingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3529
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3530
0
  return(nodes1);
3531
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3532
0
             xmlXPathNodeSetItem(nodes2, 1)));
3533
0
}
3534
3535
/**
3536
 * Implements the EXSLT - Sets leading() function:
3537
 *    node-set set:leading (node-set, node-set)
3538
 * `nodes1` and `nodes2` are sorted by document order, then
3539
 * exslSetsLeadingSorted is called.
3540
 *
3541
 * @param nodes1  a node-set
3542
 * @param nodes2  a node-set
3543
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3544
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3545
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3546
 */
3547
xmlNodeSet *
3548
0
xmlXPathLeading (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3549
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3550
0
  return(nodes1);
3551
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3552
0
  return(xmlXPathNodeSetCreate(NULL));
3553
0
    xmlXPathNodeSetSort(nodes1);
3554
0
    xmlXPathNodeSetSort(nodes2);
3555
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3556
0
             xmlXPathNodeSetItem(nodes2, 1)));
3557
0
}
3558
3559
/**
3560
 * Implements the EXSLT - Sets trailing() function:
3561
 *    node-set set:trailing (node-set, node-set)
3562
 *
3563
 * @param nodes  a node-set, sorted by document order
3564
 * @param node  a node
3565
 * @returns the nodes in `nodes` that follow `node` in document order,
3566
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3567
 *         doesn't contain `node`
3568
 */
3569
xmlNodeSet *
3570
0
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3571
0
    int i, l;
3572
0
    xmlNodePtr cur;
3573
0
    xmlNodeSetPtr ret;
3574
3575
0
    if (node == NULL)
3576
0
  return(nodes);
3577
3578
0
    ret = xmlXPathNodeSetCreate(NULL);
3579
0
    if (ret == NULL)
3580
0
        return(ret);
3581
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3582
0
  (!xmlXPathNodeSetContains(nodes, node)))
3583
0
  return(ret);
3584
3585
0
    l = xmlXPathNodeSetGetLength(nodes);
3586
0
    for (i = l - 1; i >= 0; i--) {
3587
0
  cur = xmlXPathNodeSetItem(nodes, i);
3588
0
  if (cur == node)
3589
0
      break;
3590
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3591
0
            xmlXPathFreeNodeSet(ret);
3592
0
      return(NULL);
3593
0
        }
3594
0
    }
3595
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3596
0
    return(ret);
3597
0
}
3598
3599
/**
3600
 * Implements the EXSLT - Sets trailing() function:
3601
 *    node-set set:trailing (node-set, node-set)
3602
 * `nodes` is sorted by document order, then #xmlXPathNodeTrailingSorted
3603
 * is called.
3604
 *
3605
 * @param nodes  a node-set
3606
 * @param node  a node
3607
 * @returns the nodes in `nodes` that follow `node` in document order,
3608
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3609
 *         doesn't contain `node`
3610
 */
3611
xmlNodeSet *
3612
0
xmlXPathNodeTrailing (xmlNodeSet *nodes, xmlNode *node) {
3613
0
    xmlXPathNodeSetSort(nodes);
3614
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3615
0
}
3616
3617
/**
3618
 * Implements the EXSLT - Sets trailing() function:
3619
 *    node-set set:trailing (node-set, node-set)
3620
 *
3621
 * @param nodes1  a node-set, sorted by document order
3622
 * @param nodes2  a node-set, sorted by document order
3623
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3624
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3625
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3626
 */
3627
xmlNodeSet *
3628
0
xmlXPathTrailingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3629
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3630
0
  return(nodes1);
3631
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3632
0
              xmlXPathNodeSetItem(nodes2, 0)));
3633
0
}
3634
3635
/**
3636
 * Implements the EXSLT - Sets trailing() function:
3637
 *    node-set set:trailing (node-set, node-set)
3638
 * `nodes1` and `nodes2` are sorted by document order, then
3639
 * #xmlXPathTrailingSorted is called.
3640
 *
3641
 * @param nodes1  a node-set
3642
 * @param nodes2  a node-set
3643
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3644
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3645
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3646
 */
3647
xmlNodeSet *
3648
0
xmlXPathTrailing (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3649
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3650
0
  return(nodes1);
3651
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3652
0
  return(xmlXPathNodeSetCreate(NULL));
3653
0
    xmlXPathNodeSetSort(nodes1);
3654
0
    xmlXPathNodeSetSort(nodes2);
3655
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3656
0
              xmlXPathNodeSetItem(nodes2, 0)));
3657
0
}
3658
3659
/************************************************************************
3660
 *                  *
3661
 *    Routines to handle extra functions      *
3662
 *                  *
3663
 ************************************************************************/
3664
3665
/**
3666
 * Register a new function. If `f` is NULL it unregisters the function
3667
 *
3668
 * @param ctxt  the XPath context
3669
 * @param name  the function name
3670
 * @param f  the function implementation or NULL
3671
 * @returns 0 in case of success, -1 in case of error
3672
 */
3673
int
3674
xmlXPathRegisterFunc(xmlXPathContext *ctxt, const xmlChar *name,
3675
0
         xmlXPathFunction f) {
3676
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
0
}
3678
3679
/**
3680
 * Register a new function. If `f` is NULL it unregisters the function
3681
 *
3682
 * @param ctxt  the XPath context
3683
 * @param name  the function name
3684
 * @param ns_uri  the function namespace URI
3685
 * @param f  the function implementation or NULL
3686
 * @returns 0 in case of success, -1 in case of error
3687
 */
3688
int
3689
xmlXPathRegisterFuncNS(xmlXPathContext *ctxt, const xmlChar *name,
3690
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
0
    int ret;
3692
0
    void *payload;
3693
3694
0
    if (ctxt == NULL)
3695
0
  return(-1);
3696
0
    if (name == NULL)
3697
0
  return(-1);
3698
3699
0
    if (ctxt->funcHash == NULL)
3700
0
  ctxt->funcHash = xmlHashCreate(0);
3701
0
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
0
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
0
    memcpy(&payload, &f, sizeof(f));
3708
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
0
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
0
    return(0);
3715
0
}
3716
3717
/**
3718
 * Registers an external mechanism to do function lookup.
3719
 *
3720
 * @param ctxt  the XPath context
3721
 * @param f  the lookup function
3722
 * @param funcCtxt  the lookup data
3723
 */
3724
void
3725
xmlXPathRegisterFuncLookup (xmlXPathContext *ctxt,
3726
          xmlXPathFuncLookupFunc f,
3727
0
          void *funcCtxt) {
3728
0
    if (ctxt == NULL)
3729
0
  return;
3730
0
    ctxt->funcLookupFunc = f;
3731
0
    ctxt->funcLookupData = funcCtxt;
3732
0
}
3733
3734
/**
3735
 * Search in the Function array of the context for the given
3736
 * function.
3737
 *
3738
 * @param ctxt  the XPath context
3739
 * @param name  the function name
3740
 * @returns the xmlXPathFunction or NULL if not found
3741
 */
3742
xmlXPathFunction
3743
3.78k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
3.78k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
3.78k
}
3746
3747
/**
3748
 * Search in the Function array of the context for the given
3749
 * function.
3750
 *
3751
 * @param ctxt  the XPath context
3752
 * @param name  the function name
3753
 * @param ns_uri  the function namespace URI
3754
 * @returns the xmlXPathFunction or NULL if not found
3755
 */
3756
xmlXPathFunction
3757
xmlXPathFunctionLookupNS(xmlXPathContext *ctxt, const xmlChar *name,
3758
3.78k
       const xmlChar *ns_uri) {
3759
3.78k
    xmlXPathFunction ret;
3760
3.78k
    void *payload;
3761
3762
3.78k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
3.78k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
3.78k
    if (ns_uri == NULL) {
3768
3.78k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
5.40k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
5.08k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
5.08k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
5.08k
                       (char *) name) == 0)
3775
3.46k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
1.61k
            bucketIndex += 1;
3778
1.61k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
1.61k
        }
3781
3.78k
    }
3782
3783
316
    if (ctxt->funcLookupFunc != NULL) {
3784
0
  xmlXPathFuncLookupFunc f;
3785
3786
0
  f = ctxt->funcLookupFunc;
3787
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
0
  if (ret != NULL)
3789
0
      return(ret);
3790
0
    }
3791
3792
316
    if (ctxt->funcHash == NULL)
3793
316
  return(NULL);
3794
3795
0
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
0
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
0
    return(ret);
3799
316
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
25.9k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
25.9k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
25.9k
    xmlHashFree(ctxt->funcHash, NULL);
3812
25.9k
    ctxt->funcHash = NULL;
3813
25.9k
}
3814
3815
/************************************************************************
3816
 *                  *
3817
 *      Routines to handle Variables      *
3818
 *                  *
3819
 ************************************************************************/
3820
3821
/**
3822
 * Register a new variable value. If `value` is NULL it unregisters
3823
 * the variable
3824
 *
3825
 * @param ctxt  the XPath context
3826
 * @param name  the variable name
3827
 * @param value  the variable value or NULL
3828
 * @returns 0 in case of success, -1 in case of error
3829
 */
3830
int
3831
xmlXPathRegisterVariable(xmlXPathContext *ctxt, const xmlChar *name,
3832
0
       xmlXPathObject *value) {
3833
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
0
}
3835
3836
/**
3837
 * Register a new variable value. If `value` is NULL it unregisters
3838
 * the variable
3839
 *
3840
 * @param ctxt  the XPath context
3841
 * @param name  the variable name
3842
 * @param ns_uri  the variable namespace URI
3843
 * @param value  the variable value or NULL
3844
 * @returns 0 in case of success, -1 in case of error
3845
 */
3846
int
3847
xmlXPathRegisterVariableNS(xmlXPathContext *ctxt, const xmlChar *name,
3848
         const xmlChar *ns_uri,
3849
0
         xmlXPathObject *value) {
3850
0
    if (ctxt == NULL)
3851
0
  return(-1);
3852
0
    if (name == NULL)
3853
0
  return(-1);
3854
3855
0
    if (ctxt->varHash == NULL)
3856
0
  ctxt->varHash = xmlHashCreate(0);
3857
0
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
0
    if (value == NULL)
3860
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
0
                             xmlXPathFreeObjectEntry));
3862
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
0
             (void *) value, xmlXPathFreeObjectEntry));
3864
0
}
3865
3866
/**
3867
 * register an external mechanism to do variable lookup
3868
 *
3869
 * @param ctxt  the XPath context
3870
 * @param f  the lookup function
3871
 * @param data  the lookup data
3872
 */
3873
void
3874
xmlXPathRegisterVariableLookup(xmlXPathContext *ctxt,
3875
0
   xmlXPathVariableLookupFunc f, void *data) {
3876
0
    if (ctxt == NULL)
3877
0
  return;
3878
0
    ctxt->varLookupFunc = f;
3879
0
    ctxt->varLookupData = data;
3880
0
}
3881
3882
/**
3883
 * Search in the Variable array of the context for the given
3884
 * variable value.
3885
 *
3886
 * @param ctxt  the XPath context
3887
 * @param name  the variable name
3888
 * @returns a copy of the value or NULL if not found
3889
 */
3890
xmlXPathObject *
3891
59
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
59
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
59
    if (ctxt->varLookupFunc != NULL) {
3896
0
  xmlXPathObjectPtr ret;
3897
3898
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3899
0
          (ctxt->varLookupData, name, NULL);
3900
0
  return(ret);
3901
0
    }
3902
59
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
59
}
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
60
       const xmlChar *ns_uri) {
3917
60
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
60
    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
60
    if (ctxt->varHash == NULL)
3929
60
  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
25.9k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
25.9k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
25.9k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
25.9k
    ctxt->varHash = NULL;
3948
25.9k
}
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
482
         const xmlChar *ns_uri) {
3962
482
    xmlChar *copy;
3963
3964
482
    if (ctxt == NULL)
3965
0
  return(-1);
3966
482
    if (prefix == NULL)
3967
0
  return(-1);
3968
482
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
482
    if (ctxt->nsHash == NULL)
3972
80
  ctxt->nsHash = xmlHashCreate(10);
3973
482
    if (ctxt->nsHash == NULL) {
3974
3
        xmlXPathErrMemory(ctxt);
3975
3
  return(-1);
3976
3
    }
3977
479
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
479
    copy = xmlStrdup(ns_uri);
3982
479
    if (copy == NULL) {
3983
3
        xmlXPathErrMemory(ctxt);
3984
3
        return(-1);
3985
3
    }
3986
476
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
476
                           xmlHashDefaultDeallocator) < 0) {
3988
2
        xmlXPathErrMemory(ctxt);
3989
2
        xmlFree(copy);
3990
2
        return(-1);
3991
2
    }
3992
3993
474
    return(0);
3994
476
}
3995
3996
/**
3997
 * Search in the namespace declaration array of the context for the given
3998
 * namespace name associated to the given prefix
3999
 *
4000
 * @param ctxt  the XPath context
4001
 * @param prefix  the namespace prefix value
4002
 * @returns the value or NULL if not found
4003
 */
4004
const xmlChar *
4005
6.30k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
6.30k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
6.30k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
6.30k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
6.19k
  return(XML_XML_NAMESPACE);
4013
4014
112
    if (ctxt->namespaces != NULL) {
4015
0
  int i;
4016
4017
0
  for (i = 0;i < ctxt->nsNr;i++) {
4018
0
      if ((ctxt->namespaces[i] != NULL) &&
4019
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4020
0
    return(ctxt->namespaces[i]->href);
4021
0
  }
4022
0
    }
4023
4024
112
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
112
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
25.9k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
25.9k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
25.9k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
25.9k
    ctxt->nsHash = NULL;
4039
25.9k
}
4040
4041
/************************************************************************
4042
 *                  *
4043
 *      Routines to handle Values     *
4044
 *                  *
4045
 ************************************************************************/
4046
4047
/* Allocations are terrible, one needs to optimize all this !!! */
4048
4049
/**
4050
 * Create a new xmlXPathObject of type double and of value `val`
4051
 *
4052
 * @param val  the double value
4053
 * @returns the newly created object.
4054
 */
4055
xmlXPathObject *
4056
1.35M
xmlXPathNewFloat(double val) {
4057
1.35M
    xmlXPathObjectPtr ret;
4058
4059
1.35M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
1.35M
    if (ret == NULL)
4061
57
  return(NULL);
4062
1.35M
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
1.35M
    ret->type = XPATH_NUMBER;
4064
1.35M
    ret->floatval = val;
4065
1.35M
    return(ret);
4066
1.35M
}
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
334k
xmlXPathNewBoolean(int val) {
4076
334k
    xmlXPathObjectPtr ret;
4077
4078
334k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
334k
    if (ret == NULL)
4080
16
  return(NULL);
4081
334k
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
334k
    ret->type = XPATH_BOOLEAN;
4083
334k
    ret->boolval = (val != 0);
4084
334k
    return(ret);
4085
334k
}
4086
4087
/**
4088
 * Create a new xmlXPathObject of type string and of value `val`
4089
 *
4090
 * @param val  the xmlChar * value
4091
 * @returns the newly created object.
4092
 */
4093
xmlXPathObject *
4094
574k
xmlXPathNewString(const xmlChar *val) {
4095
574k
    xmlXPathObjectPtr ret;
4096
4097
574k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
574k
    if (ret == NULL)
4099
12
  return(NULL);
4100
574k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
574k
    ret->type = XPATH_STRING;
4102
574k
    if (val == NULL)
4103
225
        val = BAD_CAST "";
4104
574k
    ret->stringval = xmlStrdup(val);
4105
574k
    if (ret->stringval == NULL) {
4106
9
        xmlFree(ret);
4107
9
        return(NULL);
4108
9
    }
4109
574k
    return(ret);
4110
574k
}
4111
4112
/**
4113
 * Wraps the `val` string into an XPath object.
4114
 *
4115
 * Frees `val` in case of error.
4116
 *
4117
 * @param val  the xmlChar * value
4118
 * @returns the newly created object.
4119
 */
4120
xmlXPathObject *
4121
24.2k
xmlXPathWrapString (xmlChar *val) {
4122
24.2k
    xmlXPathObjectPtr ret;
4123
4124
24.2k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
24.2k
    if (ret == NULL) {
4126
27
        xmlFree(val);
4127
27
  return(NULL);
4128
27
    }
4129
24.2k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
24.2k
    ret->type = XPATH_STRING;
4131
24.2k
    ret->stringval = val;
4132
24.2k
    return(ret);
4133
24.2k
}
4134
4135
/**
4136
 * Create a new xmlXPathObject of type string and of value `val`
4137
 *
4138
 * @param val  the char * value
4139
 * @returns the newly created object.
4140
 */
4141
xmlXPathObject *
4142
0
xmlXPathNewCString(const char *val) {
4143
0
    return(xmlXPathNewString(BAD_CAST val));
4144
0
}
4145
4146
/**
4147
 * Wraps a string into an XPath object.
4148
 *
4149
 * @param val  the char * value
4150
 * @returns the newly created object.
4151
 */
4152
xmlXPathObject *
4153
0
xmlXPathWrapCString (char * val) {
4154
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4155
0
}
4156
4157
/**
4158
 * Wraps the `val` data into an XPath object.
4159
 *
4160
 * @param val  the user data
4161
 * @returns the newly created object.
4162
 */
4163
xmlXPathObject *
4164
0
xmlXPathWrapExternal (void *val) {
4165
0
    xmlXPathObjectPtr ret;
4166
4167
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4168
0
    if (ret == NULL)
4169
0
  return(NULL);
4170
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4171
0
    ret->type = XPATH_USERS;
4172
0
    ret->user = val;
4173
0
    return(ret);
4174
0
}
4175
4176
/**
4177
 * allocate a new copy of a given object
4178
 *
4179
 * @param val  the original object
4180
 * @returns the newly created object.
4181
 */
4182
xmlXPathObject *
4183
568k
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
568k
    xmlXPathObjectPtr ret;
4185
4186
568k
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
568k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
568k
    if (ret == NULL)
4191
0
  return(NULL);
4192
568k
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
568k
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
9.51k
  case XPATH_NUMBER:
4196
9.51k
      break;
4197
559k
  case XPATH_STRING:
4198
559k
      ret->stringval = xmlStrdup(val->stringval);
4199
559k
            if (ret->stringval == NULL) {
4200
0
                xmlFree(ret);
4201
0
                return(NULL);
4202
0
            }
4203
559k
      break;
4204
559k
  case XPATH_XSLT_TREE:
4205
0
  case XPATH_NODESET:
4206
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4207
0
            if (ret->nodesetval == NULL) {
4208
0
                xmlFree(ret);
4209
0
                return(NULL);
4210
0
            }
4211
      /* Do not deallocate the copied tree value */
4212
0
      ret->boolval = 0;
4213
0
      break;
4214
0
        case XPATH_USERS:
4215
0
      ret->user = val->user;
4216
0
      break;
4217
0
        default:
4218
0
            xmlFree(ret);
4219
0
            ret = NULL;
4220
0
      break;
4221
568k
    }
4222
568k
    return(ret);
4223
568k
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
3.39M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
3.39M
    if (obj == NULL) return;
4233
3.37M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
957k
        if (obj->nodesetval != NULL)
4235
957k
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
2.41M
    } else if (obj->type == XPATH_STRING) {
4237
1.14M
  if (obj->stringval != NULL)
4238
1.14M
      xmlFree(obj->stringval);
4239
1.14M
    }
4240
3.37M
    xmlFree(obj);
4241
3.37M
}
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
5.91M
{
4258
5.91M
    if (obj == NULL)
4259
8
  return;
4260
5.91M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
2.90M
   xmlXPathFreeObject(obj);
4262
3.01M
    } else {
4263
3.01M
  xmlXPathContextCachePtr cache =
4264
3.01M
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
3.01M
  switch (obj->type) {
4267
1.74M
      case XPATH_NODESET:
4268
1.74M
      case XPATH_XSLT_TREE:
4269
1.74M
    if (obj->nodesetval != NULL) {
4270
1.74M
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
1.66M
      (cache->numNodeset < cache->maxNodeset)) {
4272
1.18M
                        obj->stringval = (void *) cache->nodesetObjs;
4273
1.18M
                        cache->nodesetObjs = obj;
4274
1.18M
                        cache->numNodeset += 1;
4275
1.18M
      goto obj_cached;
4276
1.18M
        } else {
4277
557k
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
557k
      obj->nodesetval = NULL;
4279
557k
        }
4280
1.74M
    }
4281
557k
    break;
4282
557k
      case XPATH_STRING:
4283
92.4k
    if (obj->stringval != NULL)
4284
92.4k
        xmlFree(obj->stringval);
4285
92.4k
                obj->stringval = NULL;
4286
92.4k
    break;
4287
502k
      case XPATH_BOOLEAN:
4288
1.17M
      case XPATH_NUMBER:
4289
1.17M
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
3.01M
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
1.82M
        if (cache->numMisc >= cache->maxMisc)
4298
8.85k
      goto free_obj;
4299
1.81M
        obj->stringval = (void *) cache->miscObjs;
4300
1.81M
        cache->miscObjs = obj;
4301
1.81M
        cache->numMisc += 1;
4302
4303
3.00M
obj_cached:
4304
3.00M
        obj->boolval = 0;
4305
3.00M
  if (obj->nodesetval != NULL) {
4306
1.18M
      xmlNodeSetPtr tmpset = obj->nodesetval;
4307
4308
      /*
4309
      * Due to those nasty ns-nodes, we need to traverse
4310
      * the list and free the ns-nodes.
4311
      */
4312
1.18M
      if (tmpset->nodeNr > 0) {
4313
1.16M
    int i;
4314
1.16M
    xmlNodePtr node;
4315
4316
2.39M
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
1.22M
        node = tmpset->nodeTab[i];
4318
1.22M
        if ((node != NULL) &&
4319
1.22M
      (node->type == XML_NAMESPACE_DECL))
4320
117k
        {
4321
117k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
117k
        }
4323
1.22M
    }
4324
1.16M
      }
4325
1.18M
      tmpset->nodeNr = 0;
4326
1.18M
        }
4327
4328
3.00M
  return;
4329
4330
8.85k
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
8.85k
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
8.85k
  xmlFree(obj);
4337
8.85k
    }
4338
5.91M
}
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
853
xmlXPathCastBooleanToString (int val) {
4355
853
    xmlChar *ret;
4356
853
    if (val)
4357
240
  ret = xmlStrdup((const xmlChar *) "true");
4358
613
    else
4359
613
  ret = xmlStrdup((const xmlChar *) "false");
4360
853
    return(ret);
4361
853
}
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
8.95k
xmlXPathCastNumberToString (double val) {
4371
8.95k
    xmlChar *ret;
4372
8.95k
    switch (xmlXPathIsInf(val)) {
4373
215
    case 1:
4374
215
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
215
  break;
4376
215
    case -1:
4377
215
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
215
  break;
4379
8.52k
    default:
4380
8.52k
  if (xmlXPathIsNaN(val)) {
4381
614
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
7.91k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
1.99k
      ret = xmlStrdup((const xmlChar *) "0");
4385
5.92k
  } else {
4386
      /* could be improved */
4387
5.92k
      char buf[100];
4388
5.92k
      xmlXPathFormatNumber(val, buf, 99);
4389
5.92k
      buf[99] = 0;
4390
5.92k
      ret = xmlStrdup((const xmlChar *) buf);
4391
5.92k
  }
4392
8.95k
    }
4393
8.95k
    return(ret);
4394
8.95k
}
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.17M
xmlXPathCastNodeToString (xmlNode *node) {
4404
7.17M
    return(xmlNodeGetContent(node));
4405
7.17M
}
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
112k
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
112k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
48.2k
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
64.0k
    if (ns->nodeNr > 1)
4419
22.6k
  xmlXPathNodeSetSort(ns);
4420
64.0k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
112k
}
4422
4423
/**
4424
 * Converts an existing object to its string() equivalent
4425
 *
4426
 * @param val  an XPath object
4427
 * @returns the allocated string value of the object, NULL in case of error.
4428
 *         It's up to the caller to free the string memory with #xmlFree.
4429
 */
4430
xmlChar *
4431
35.2k
xmlXPathCastToString(xmlXPathObject *val) {
4432
35.2k
    xmlChar *ret = NULL;
4433
4434
35.2k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
35.2k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
23.2k
        case XPATH_NODESET:
4441
23.2k
        case XPATH_XSLT_TREE:
4442
23.2k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
23.2k
      break;
4444
2.12k
  case XPATH_STRING:
4445
2.12k
      return(xmlStrdup(val->stringval));
4446
853
        case XPATH_BOOLEAN:
4447
853
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
853
      break;
4449
8.95k
  case XPATH_NUMBER: {
4450
8.95k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
8.95k
      break;
4452
23.2k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
35.2k
    }
4458
33.1k
    return(ret);
4459
35.2k
}
4460
4461
/**
4462
 * Converts an existing object to its string() equivalent
4463
 *
4464
 * @param val  an XPath object
4465
 * @returns the new object, the old one is freed (or the operation
4466
 *         is done directly on `val`)
4467
 */
4468
xmlXPathObject *
4469
0
xmlXPathConvertString(xmlXPathObject *val) {
4470
0
    xmlChar *res = NULL;
4471
4472
0
    if (val == NULL)
4473
0
  return(xmlXPathNewCString(""));
4474
4475
0
    switch (val->type) {
4476
0
    case XPATH_UNDEFINED:
4477
0
  break;
4478
0
    case XPATH_NODESET:
4479
0
    case XPATH_XSLT_TREE:
4480
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4481
0
  break;
4482
0
    case XPATH_STRING:
4483
0
  return(val);
4484
0
    case XPATH_BOOLEAN:
4485
0
  res = xmlXPathCastBooleanToString(val->boolval);
4486
0
  break;
4487
0
    case XPATH_NUMBER:
4488
0
  res = xmlXPathCastNumberToString(val->floatval);
4489
0
  break;
4490
0
    case XPATH_USERS:
4491
  /* TODO */
4492
0
  break;
4493
0
    }
4494
0
    xmlXPathFreeObject(val);
4495
0
    if (res == NULL)
4496
0
  return(xmlXPathNewCString(""));
4497
0
    return(xmlXPathWrapString(res));
4498
0
}
4499
4500
/**
4501
 * Converts a boolean to its number value
4502
 *
4503
 * @param val  a boolean
4504
 * @returns the number value
4505
 */
4506
double
4507
7.95k
xmlXPathCastBooleanToNumber(int val) {
4508
7.95k
    if (val)
4509
3.11k
  return(1.0);
4510
4.83k
    return(0.0);
4511
7.95k
}
4512
4513
/**
4514
 * Converts a string to its number value
4515
 *
4516
 * @param val  a string
4517
 * @returns the number value
4518
 */
4519
double
4520
7.04M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
7.04M
    return(xmlXPathStringEvalNumber(val));
4522
7.04M
}
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
5.81M
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
5.81M
    xmlChar *strval;
4534
5.81M
    double ret;
4535
4536
5.81M
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
5.81M
    strval = xmlXPathCastNodeToString(node);
4539
5.81M
    if (strval == NULL) {
4540
28
        xmlXPathPErrMemory(ctxt);
4541
28
  return(xmlXPathNAN);
4542
28
    }
4543
5.81M
    ret = xmlXPathCastStringToNumber(strval);
4544
5.81M
    xmlFree(strval);
4545
4546
5.81M
    return(ret);
4547
5.81M
}
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
214k
xmlXPathCastNumberToBoolean (double val) {
4618
214k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
213k
   return(0);
4620
1.84k
     return(1);
4621
214k
}
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
6.33k
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
6.33k
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
2.64k
  return(0);
4633
3.68k
    return(1);
4634
6.33k
}
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
95.3k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
95.3k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
94.2k
  return(0);
4646
1.02k
    return(1);
4647
95.3k
}
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
103k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
103k
    int ret = 0;
4658
4659
103k
    if (val == NULL)
4660
0
  return(0);
4661
103k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
95.3k
    case XPATH_NODESET:
4666
95.3k
    case XPATH_XSLT_TREE:
4667
95.3k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
95.3k
  break;
4669
6.33k
    case XPATH_STRING:
4670
6.33k
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
6.33k
  break;
4672
1.87k
    case XPATH_NUMBER:
4673
1.87k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
1.87k
  break;
4675
0
    case XPATH_BOOLEAN:
4676
0
  ret = val->boolval;
4677
0
  break;
4678
0
    case XPATH_USERS:
4679
  /* TODO */
4680
0
  ret = 0;
4681
0
  break;
4682
103k
    }
4683
103k
    return(ret);
4684
103k
}
4685
4686
4687
/**
4688
 * Converts an existing object to its boolean() equivalent
4689
 *
4690
 * @param val  an XPath object
4691
 * @returns the new object, the old one is freed (or the operation
4692
 *         is done directly on `val`)
4693
 */
4694
xmlXPathObject *
4695
0
xmlXPathConvertBoolean(xmlXPathObject *val) {
4696
0
    xmlXPathObjectPtr ret;
4697
4698
0
    if (val == NULL)
4699
0
  return(xmlXPathNewBoolean(0));
4700
0
    if (val->type == XPATH_BOOLEAN)
4701
0
  return(val);
4702
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4703
0
    xmlXPathFreeObject(val);
4704
0
    return(ret);
4705
0
}
4706
4707
/************************************************************************
4708
 *                  *
4709
 *    Routines to handle XPath contexts     *
4710
 *                  *
4711
 ************************************************************************/
4712
4713
/**
4714
 * Create a new xmlXPathContext
4715
 *
4716
 * @param doc  the XML document
4717
 * @returns the xmlXPathContext just allocated. The caller will need to free it.
4718
 */
4719
xmlXPathContext *
4720
26.0k
xmlXPathNewContext(xmlDoc *doc) {
4721
26.0k
    xmlXPathContextPtr ret;
4722
4723
26.0k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
26.0k
    if (ret == NULL)
4725
97
  return(NULL);
4726
25.9k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
25.9k
    ret->doc = doc;
4728
25.9k
    ret->node = NULL;
4729
4730
25.9k
    ret->varHash = NULL;
4731
4732
25.9k
    ret->nb_types = 0;
4733
25.9k
    ret->max_types = 0;
4734
25.9k
    ret->types = NULL;
4735
4736
25.9k
    ret->nb_axis = 0;
4737
25.9k
    ret->max_axis = 0;
4738
25.9k
    ret->axis = NULL;
4739
4740
25.9k
    ret->nsHash = NULL;
4741
25.9k
    ret->user = NULL;
4742
4743
25.9k
    ret->contextSize = -1;
4744
25.9k
    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
25.9k
    return(ret);
4754
26.0k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
25.9k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
25.9k
    if (ctxt == NULL) return;
4764
4765
25.9k
    if (ctxt->cache != NULL)
4766
25.3k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
25.9k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
25.9k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
25.9k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
25.9k
    xmlResetError(&ctxt->lastError);
4771
25.9k
    xmlFree(ctxt);
4772
25.9k
}
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
25.9k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
25.9k
    xmlXPathParserContextPtr ret;
4809
4810
25.9k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
25.9k
    if (ret == NULL) {
4812
84
        xmlXPathErrMemory(ctxt);
4813
84
  return(NULL);
4814
84
    }
4815
25.8k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
25.8k
    ret->cur = ret->base = str;
4817
25.8k
    ret->context = ctxt;
4818
4819
25.8k
    ret->comp = xmlXPathNewCompExpr();
4820
25.8k
    if (ret->comp == NULL) {
4821
290
        xmlXPathErrMemory(ctxt);
4822
290
  xmlFree(ret->valueTab);
4823
290
  xmlFree(ret);
4824
290
  return(NULL);
4825
290
    }
4826
25.5k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
25.5k
    return(ret);
4832
25.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
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
0
    xmlXPathParserContextPtr ret;
4844
4845
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
0
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
0
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
0
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
0
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
0
    ret->valueNr = 0;
4865
0
    ret->value = NULL;
4866
4867
0
    ret->context = ctxt;
4868
0
    ret->comp = comp;
4869
4870
0
    return(ret);
4871
0
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
25.5k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
25.5k
    int i;
4881
4882
25.5k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
25.5k
    if (ctxt->valueTab != NULL) {
4886
35.2k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
9.77k
            if (ctxt->context)
4888
9.77k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
9.77k
        }
4892
25.5k
        xmlFree(ctxt->valueTab);
4893
25.5k
    }
4894
25.5k
    if (ctxt->comp != NULL) {
4895
#ifdef XPATH_STREAMING
4896
  if (ctxt->comp->stream != NULL) {
4897
      xmlFreePatternList(ctxt->comp->stream);
4898
      ctxt->comp->stream = NULL;
4899
  }
4900
#endif
4901
25.5k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
25.5k
    }
4903
25.5k
    xmlFree(ctxt);
4904
25.5k
}
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
134k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
134k
    int len = 2;
4922
134k
    const xmlChar * string = NULL;
4923
134k
    xmlNodePtr tmp = NULL;
4924
134k
    unsigned int ret = 0;
4925
4926
134k
    if (node == NULL)
4927
0
  return(0);
4928
4929
134k
    if (node->type == XML_DOCUMENT_NODE) {
4930
5.33k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
5.33k
  if (tmp == NULL)
4932
477
      node = node->children;
4933
4.86k
  else
4934
4.86k
      node = tmp;
4935
4936
5.33k
  if (node == NULL)
4937
276
      return(0);
4938
5.33k
    }
4939
4940
134k
    switch (node->type) {
4941
253
  case XML_COMMENT_NODE:
4942
453
  case XML_PI_NODE:
4943
662
  case XML_CDATA_SECTION_NODE:
4944
1.01k
  case XML_TEXT_NODE:
4945
1.01k
      string = node->content;
4946
1.01k
      if (string == NULL)
4947
200
    return(0);
4948
818
      if (string[0] == 0)
4949
438
    return(0);
4950
380
      return(string[0] + (string[1] << 8));
4951
117k
  case XML_NAMESPACE_DECL:
4952
117k
      string = ((xmlNsPtr)node)->href;
4953
117k
      if (string == NULL)
4954
0
    return(0);
4955
117k
      if (string[0] == 0)
4956
36.9k
    return(0);
4957
80.7k
      return(string[0] + (string[1] << 8));
4958
199
  case XML_ATTRIBUTE_NODE:
4959
199
      tmp = ((xmlAttrPtr) node)->children;
4960
199
      break;
4961
15.2k
  case XML_ELEMENT_NODE:
4962
15.2k
      tmp = node->children;
4963
15.2k
      break;
4964
194
  default:
4965
194
      return(0);
4966
134k
    }
4967
58.6k
    while (tmp != NULL) {
4968
48.3k
  switch (tmp->type) {
4969
907
      case XML_CDATA_SECTION_NODE:
4970
9.46k
      case XML_TEXT_NODE:
4971
9.46k
    string = tmp->content;
4972
9.46k
    break;
4973
38.8k
      default:
4974
38.8k
                string = NULL;
4975
38.8k
    break;
4976
48.3k
  }
4977
48.3k
  if ((string != NULL) && (string[0] != 0)) {
4978
8.57k
      if (len == 1) {
4979
1.33k
    return(ret + (string[0] << 8));
4980
1.33k
      }
4981
7.24k
      if (string[1] == 0) {
4982
3.48k
    len = 1;
4983
3.48k
    ret = string[0];
4984
3.75k
      } else {
4985
3.75k
    return(string[0] + (string[1] << 8));
4986
3.75k
      }
4987
7.24k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
43.2k
        if ((tmp->children != NULL) &&
4992
10.9k
            (tmp->type != XML_DTD_NODE) &&
4993
10.9k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
10.7k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
10.7k
            tmp = tmp->children;
4996
10.7k
            continue;
4997
10.7k
  }
4998
32.4k
  if (tmp == node)
4999
0
      break;
5000
5001
32.4k
  if (tmp->next != NULL) {
5002
26.7k
      tmp = tmp->next;
5003
26.7k
      continue;
5004
26.7k
  }
5005
5006
9.83k
  do {
5007
9.83k
      tmp = tmp->parent;
5008
9.83k
      if (tmp == NULL)
5009
0
    break;
5010
9.83k
      if (tmp == node) {
5011
5.50k
    tmp = NULL;
5012
5.50k
    break;
5013
5.50k
      }
5014
4.33k
      if (tmp->next != NULL) {
5015
229
    tmp = tmp->next;
5016
229
    break;
5017
229
      }
5018
4.33k
  } while (tmp != NULL);
5019
5.73k
    }
5020
10.3k
    return(ret);
5021
15.4k
}
5022
5023
/**
5024
 * Function computing the beginning of the string value of the node,
5025
 * used to speed up comparisons
5026
 *
5027
 * @param string  a string
5028
 * @returns an int usable as a hash
5029
 */
5030
static unsigned int
5031
2.22k
xmlXPathStringHash(const xmlChar * string) {
5032
2.22k
    if (string == NULL)
5033
0
  return(0);
5034
2.22k
    if (string[0] == 0)
5035
704
  return(0);
5036
1.51k
    return(string[0] + (string[1] << 8));
5037
2.22k
}
5038
5039
/**
5040
 * Implement the compare operation between a nodeset and a number
5041
 *     `ns` < `val`    (1, 1, ...
5042
 *     `ns` <= `val`   (1, 0, ...
5043
 *     `ns` > `val`    (0, 1, ...
5044
 *     `ns` >= `val`   (0, 0, ...
5045
 *
5046
 * If one object to be compared is a node-set and the other is a number,
5047
 * then the comparison will be true if and only if there is a node in the
5048
 * node-set such that the result of performing the comparison on the number
5049
 * to be compared and on the result of converting the string-value of that
5050
 * node to a number using the number function is true.
5051
 *
5052
 * @param ctxt  the XPath Parser context
5053
 * @param inf  less than (1) or greater than (0)
5054
 * @param strict  is the comparison strict
5055
 * @param arg  the node set
5056
 * @param f  the value
5057
 * @returns 0 or 1 depending on the results of the test.
5058
 */
5059
static int
5060
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5061
5.69k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
5.69k
    int i, ret = 0;
5063
5.69k
    xmlNodeSetPtr ns;
5064
5.69k
    xmlChar *str2;
5065
5066
5.69k
    if ((f == NULL) || (arg == NULL) ||
5067
5.69k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5068
0
  xmlXPathReleaseObject(ctxt->context, arg);
5069
0
  xmlXPathReleaseObject(ctxt->context, f);
5070
0
        return(0);
5071
0
    }
5072
5.69k
    ns = arg->nodesetval;
5073
5.69k
    if (ns != NULL) {
5074
15.3k
  for (i = 0;i < ns->nodeNr;i++) {
5075
9.92k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
9.92k
       if (str2 != NULL) {
5077
9.91k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
9.91k
     xmlFree(str2);
5079
9.91k
     xmlXPathNumberFunction(ctxt, 1);
5080
9.91k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
9.91k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
9.91k
     if (ret)
5083
238
         break;
5084
9.91k
       } else {
5085
5
                 xmlXPathPErrMemory(ctxt);
5086
5
             }
5087
9.92k
  }
5088
5.69k
    }
5089
5.69k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
5.69k
    xmlXPathReleaseObject(ctxt->context, f);
5091
5.69k
    return(ret);
5092
5.69k
}
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
18.9k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
18.9k
    int i, ret = 0;
5117
18.9k
    xmlNodeSetPtr ns;
5118
18.9k
    xmlChar *str2;
5119
5120
18.9k
    if ((s == NULL) || (arg == NULL) ||
5121
18.9k
  ((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
18.9k
    ns = arg->nodesetval;
5127
18.9k
    if (ns != NULL) {
5128
580k
  for (i = 0;i < ns->nodeNr;i++) {
5129
562k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
562k
       if (str2 != NULL) {
5131
562k
     xmlXPathValuePush(ctxt,
5132
562k
         xmlXPathCacheNewString(ctxt, str2));
5133
562k
     xmlFree(str2);
5134
562k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
562k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
562k
     if (ret)
5137
208
         break;
5138
562k
       } else {
5139
2
                 xmlXPathPErrMemory(ctxt);
5140
2
             }
5141
562k
  }
5142
18.9k
    }
5143
18.9k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
18.9k
    xmlXPathReleaseObject(ctxt->context, s);
5145
18.9k
    return(ret);
5146
18.9k
}
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
219k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
219k
    int i, j, init = 0;
5180
219k
    double val1;
5181
219k
    double *values2;
5182
219k
    int ret = 0;
5183
219k
    xmlNodeSetPtr ns1;
5184
219k
    xmlNodeSetPtr ns2;
5185
5186
219k
    if ((arg1 == NULL) ||
5187
219k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
219k
    if ((arg2 == NULL) ||
5192
219k
  ((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
219k
    ns1 = arg1->nodesetval;
5199
219k
    ns2 = arg2->nodesetval;
5200
5201
219k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
213k
  xmlXPathFreeObject(arg1);
5203
213k
  xmlXPathFreeObject(arg2);
5204
213k
  return(0);
5205
213k
    }
5206
5.73k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
1.48k
  xmlXPathFreeObject(arg1);
5208
1.48k
  xmlXPathFreeObject(arg2);
5209
1.48k
  return(0);
5210
1.48k
    }
5211
5212
4.25k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
4.25k
    if (values2 == NULL) {
5214
1
        xmlXPathPErrMemory(ctxt);
5215
1
  xmlXPathFreeObject(arg1);
5216
1
  xmlXPathFreeObject(arg2);
5217
1
  return(0);
5218
1
    }
5219
21.8k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
18.1k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
18.1k
  if (xmlXPathIsNaN(val1))
5222
14.6k
      continue;
5223
7.32k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
4.35k
      if (init == 0) {
5225
1.74k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
1.74k
                                                          ns2->nodeTab[j]);
5227
1.74k
      }
5228
4.35k
      if (xmlXPathIsNaN(values2[j]))
5229
1.00k
    continue;
5230
3.35k
      if (inf && strict)
5231
890
    ret = (val1 < values2[j]);
5232
2.46k
      else if (inf && !strict)
5233
215
    ret = (val1 <= values2[j]);
5234
2.25k
      else if (!inf && strict)
5235
2.03k
    ret = (val1 > values2[j]);
5236
215
      else if (!inf && !strict)
5237
215
    ret = (val1 >= values2[j]);
5238
3.35k
      if (ret)
5239
463
    break;
5240
3.35k
  }
5241
3.42k
  if (ret)
5242
463
      break;
5243
2.96k
  init = 1;
5244
2.96k
    }
5245
4.25k
    xmlFree(values2);
5246
4.25k
    xmlXPathFreeObject(arg1);
5247
4.25k
    xmlXPathFreeObject(arg2);
5248
4.25k
    return(ret);
5249
4.25k
}
5250
5251
/**
5252
 * Implement the compare operation between a nodeset and a value
5253
 *     `ns` < `val`    (1, 1, ...
5254
 *     `ns` <= `val`   (1, 0, ...
5255
 *     `ns` > `val`    (0, 1, ...
5256
 *     `ns` >= `val`   (0, 0, ...
5257
 *
5258
 * If one object to be compared is a node-set and the other is a boolean,
5259
 * then the comparison will be true if and only if the result of performing
5260
 * the comparison on the boolean and on the result of converting
5261
 * the node-set to a boolean using the boolean function is true.
5262
 *
5263
 * @param ctxt  the XPath Parser context
5264
 * @param inf  less than (1) or greater than (0)
5265
 * @param strict  is the comparison strict
5266
 * @param arg  the node set
5267
 * @param val  the value
5268
 * @returns 0 or 1 depending on the results of the test.
5269
 */
5270
static int
5271
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5272
27.4k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
27.4k
    if ((val == NULL) || (arg == NULL) ||
5274
27.4k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
27.4k
    switch(val->type) {
5278
5.69k
        case XPATH_NUMBER:
5279
5.69k
      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
18.9k
        case XPATH_STRING:
5284
18.9k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
2.82k
        case XPATH_BOOLEAN:
5286
2.82k
      xmlXPathValuePush(ctxt, arg);
5287
2.82k
      xmlXPathBooleanFunction(ctxt, 1);
5288
2.82k
      xmlXPathValuePush(ctxt, val);
5289
2.82k
      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
27.4k
    }
5295
0
    return(0);
5296
27.4k
}
5297
5298
/**
5299
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5300
 * If one object to be compared is a node-set and the other is a string,
5301
 * then the comparison will be true if and only if there is a node in
5302
 * the node-set such that the result of performing the comparison on the
5303
 * string-value of the node and the other string is true.
5304
 *
5305
 * @param ctxt  XPath parser context
5306
 * @param arg  the nodeset object argument
5307
 * @param str  the string to compare to.
5308
 * @param neq  flag to show whether for '=' (0) or '!=' (1)
5309
 * @returns 0 or 1 depending on the results of the test.
5310
 */
5311
static int
5312
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5313
                           xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5314
2.79k
{
5315
2.79k
    int i;
5316
2.79k
    xmlNodeSetPtr ns;
5317
2.79k
    xmlChar *str2;
5318
2.79k
    unsigned int hash;
5319
5320
2.79k
    if ((str == NULL) || (arg == NULL) ||
5321
2.79k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
2.79k
    ns = arg->nodesetval;
5324
    /*
5325
     * A NULL nodeset compared with a string is always false
5326
     * (since there is no node equal, and no node not equal)
5327
     */
5328
2.79k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
572
        return (0);
5330
2.22k
    hash = xmlXPathStringHash(str);
5331
6.59k
    for (i = 0; i < ns->nodeNr; i++) {
5332
5.24k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
1.48k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
1.48k
            if (str2 == NULL) {
5335
3
                xmlXPathPErrMemory(ctxt);
5336
3
                return(0);
5337
3
            }
5338
1.48k
            if (xmlStrEqual(str, str2)) {
5339
995
                xmlFree(str2);
5340
995
    if (neq)
5341
663
        continue;
5342
332
                return (1);
5343
995
            } else if (neq) {
5344
215
    xmlFree(str2);
5345
215
    return (1);
5346
215
      }
5347
272
            xmlFree(str2);
5348
3.75k
        } else if (neq)
5349
316
      return (1);
5350
5.24k
    }
5351
1.35k
    return (0);
5352
2.22k
}
5353
5354
/**
5355
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5356
 * If one object to be compared is a node-set and the other is a number,
5357
 * then the comparison will be true if and only if there is a node in
5358
 * the node-set such that the result of performing the comparison on the
5359
 * number to be compared and on the result of converting the string-value
5360
 * of that node to a number using the number function is true.
5361
 *
5362
 * @param ctxt  XPath parser context
5363
 * @param arg  the nodeset object argument
5364
 * @param f  the float to compare to
5365
 * @param neq  flag to show whether to compare '=' (0) or '!=' (1)
5366
 * @returns 0 or 1 depending on the results of the test.
5367
 */
5368
static int
5369
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5370
3.96k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
3.96k
  int i, ret=0;
5372
3.96k
  xmlNodeSetPtr ns;
5373
3.96k
  xmlChar *str2;
5374
3.96k
  xmlXPathObjectPtr val;
5375
3.96k
  double v;
5376
5377
3.96k
    if ((arg == NULL) ||
5378
3.96k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
3.96k
    ns = arg->nodesetval;
5382
3.96k
    if (ns != NULL) {
5383
9.24k
  for (i=0;i<ns->nodeNr;i++) {
5384
5.71k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
5.71k
      if (str2 != NULL) {
5386
5.71k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
5.71k
    xmlFree(str2);
5388
5.71k
    xmlXPathNumberFunction(ctxt, 1);
5389
5.71k
                CHECK_ERROR0;
5390
5.70k
    val = xmlXPathValuePop(ctxt);
5391
5.70k
    v = val->floatval;
5392
5.70k
    xmlXPathReleaseObject(ctxt->context, val);
5393
5.70k
    if (!xmlXPathIsNaN(v)) {
5394
956
        if ((!neq) && (v==f)) {
5395
215
      ret = 1;
5396
215
      break;
5397
741
        } else if ((neq) && (v!=f)) {
5398
215
      ret = 1;
5399
215
      break;
5400
215
        }
5401
4.75k
    } else { /* NaN is unequal to any value */
5402
4.75k
        if (neq)
5403
914
      ret = 1;
5404
4.75k
    }
5405
5.70k
      } else {
5406
6
                xmlXPathPErrMemory(ctxt);
5407
6
            }
5408
5.71k
  }
5409
3.96k
    }
5410
5411
3.95k
    return(ret);
5412
3.96k
}
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
8.37k
                      xmlXPathObjectPtr arg2, int neq) {
5434
8.37k
    int i, j;
5435
8.37k
    unsigned int *hashs1;
5436
8.37k
    unsigned int *hashs2;
5437
8.37k
    xmlChar **values1;
5438
8.37k
    xmlChar **values2;
5439
8.37k
    int ret = 0;
5440
8.37k
    xmlNodeSetPtr ns1;
5441
8.37k
    xmlNodeSetPtr ns2;
5442
5443
8.37k
    if ((arg1 == NULL) ||
5444
8.37k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
8.37k
    if ((arg2 == NULL) ||
5447
8.37k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
8.37k
    ns1 = arg1->nodesetval;
5451
8.37k
    ns2 = arg2->nodesetval;
5452
5453
8.37k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
2.35k
  return(0);
5455
6.02k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
1.93k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
4.09k
    if (neq == 0)
5462
997k
  for (i = 0;i < ns1->nodeNr;i++)
5463
1.99M
      for (j = 0;j < ns2->nodeNr;j++)
5464
996k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
335
        return(1);
5466
5467
3.75k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
3.75k
    if (values1 == NULL) {
5469
1
        xmlXPathPErrMemory(ctxt);
5470
1
  return(0);
5471
1
    }
5472
3.75k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
3.75k
    if (hashs1 == NULL) {
5474
2
        xmlXPathPErrMemory(ctxt);
5475
2
  xmlFree(values1);
5476
2
  return(0);
5477
2
    }
5478
3.75k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
3.75k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
3.75k
    if (values2 == NULL) {
5481
1
        xmlXPathPErrMemory(ctxt);
5482
1
  xmlFree(hashs1);
5483
1
  xmlFree(values1);
5484
1
  return(0);
5485
1
    }
5486
3.75k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
3.75k
    if (hashs2 == NULL) {
5488
1
        xmlXPathPErrMemory(ctxt);
5489
1
  xmlFree(hashs1);
5490
1
  xmlFree(values1);
5491
1
  xmlFree(values2);
5492
1
  return(0);
5493
1
    }
5494
3.75k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
124k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
122k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
246k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
126k
      if (i == 0)
5499
7.21k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
126k
      if (hashs1[i] != hashs2[j]) {
5501
118k
    if (neq) {
5502
507
        ret = 1;
5503
507
        break;
5504
507
    }
5505
118k
      }
5506
7.69k
      else {
5507
7.69k
    if (values1[i] == NULL) {
5508
4.25k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
4.25k
                    if (values1[i] == NULL)
5510
4
                        xmlXPathPErrMemory(ctxt);
5511
4.25k
                }
5512
7.69k
    if (values2[j] == NULL) {
5513
6.00k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
6.00k
                    if (values2[j] == NULL)
5515
6
                        xmlXPathPErrMemory(ctxt);
5516
6.00k
                }
5517
7.69k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
7.69k
    if (ret)
5519
1.19k
        break;
5520
7.69k
      }
5521
126k
  }
5522
122k
  if (ret)
5523
1.69k
      break;
5524
122k
    }
5525
1.00M
    for (i = 0;i < ns1->nodeNr;i++)
5526
1.00M
  if (values1[i] != NULL)
5527
4.24k
      xmlFree(values1[i]);
5528
11.4k
    for (j = 0;j < ns2->nodeNr;j++)
5529
7.65k
  if (values2[j] != NULL)
5530
5.99k
      xmlFree(values2[j]);
5531
3.75k
    xmlFree(values1);
5532
3.75k
    xmlFree(values2);
5533
3.75k
    xmlFree(hashs1);
5534
3.75k
    xmlFree(hashs2);
5535
3.75k
    return(ret);
5536
3.75k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
231k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
231k
    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
231k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
213k
        case XPATH_BOOLEAN:
5550
213k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
1.09k
    case XPATH_BOOLEAN:
5554
1.09k
        ret = (arg1->boolval == arg2->boolval);
5555
1.09k
        break;
5556
211k
    case XPATH_NUMBER:
5557
211k
        ret = (arg1->boolval ==
5558
211k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
211k
        break;
5560
651
    case XPATH_STRING:
5561
651
        if ((arg2->stringval == NULL) ||
5562
651
      (arg2->stringval[0] == 0)) ret = 0;
5563
322
        else
5564
322
      ret = 1;
5565
651
        ret = (arg1->boolval == ret);
5566
651
        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
213k
      }
5574
213k
      break;
5575
213k
        case XPATH_NUMBER:
5576
15.1k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
1.25k
    case XPATH_BOOLEAN:
5580
1.25k
        ret = (arg2->boolval==
5581
1.25k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
1.25k
        break;
5583
2.72k
    case XPATH_STRING:
5584
2.72k
        xmlXPathValuePush(ctxt, arg2);
5585
2.72k
        xmlXPathNumberFunction(ctxt, 1);
5586
2.72k
        arg2 = xmlXPathValuePop(ctxt);
5587
2.72k
                    if (ctxt->error)
5588
0
                        break;
5589
                    /* Falls through. */
5590
13.8k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
13.8k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
13.4k
          xmlXPathIsNaN(arg2->floatval)) {
5594
3.04k
            ret = 0;
5595
10.8k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
430
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
215
          ret = 1;
5598
215
      else
5599
215
          ret = 0;
5600
10.3k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
491
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
215
          ret = 1;
5603
276
      else
5604
276
          ret = 0;
5605
9.89k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
215
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
215
      else
5609
215
          ret = 0;
5610
9.68k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
215
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
215
      else
5614
215
          ret = 0;
5615
9.46k
        } else {
5616
9.46k
            ret = (arg1->floatval == arg2->floatval);
5617
9.46k
        }
5618
13.8k
        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
15.1k
      }
5626
15.1k
      break;
5627
15.1k
        case XPATH_STRING:
5628
2.87k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
613
    case XPATH_BOOLEAN:
5632
613
        if ((arg1->stringval == NULL) ||
5633
613
      (arg1->stringval[0] == 0)) ret = 0;
5634
331
        else
5635
331
      ret = 1;
5636
613
        ret = (arg2->boolval == ret);
5637
613
        break;
5638
226
    case XPATH_STRING:
5639
226
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
226
        break;
5641
2.03k
    case XPATH_NUMBER:
5642
2.03k
        xmlXPathValuePush(ctxt, arg1);
5643
2.03k
        xmlXPathNumberFunction(ctxt, 1);
5644
2.03k
        arg1 = xmlXPathValuePop(ctxt);
5645
2.03k
                    if (ctxt->error)
5646
0
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
2.03k
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
1.65k
          xmlXPathIsNaN(arg2->floatval)) {
5650
583
            ret = 0;
5651
1.45k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
404
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
195
          ret = 1;
5654
209
      else
5655
209
          ret = 0;
5656
1.05k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
393
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
197
          ret = 1;
5659
196
      else
5660
196
          ret = 0;
5661
658
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
197
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
197
      else
5665
197
          ret = 0;
5666
461
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
206
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
206
      else
5670
206
          ret = 0;
5671
255
        } else {
5672
255
            ret = (arg1->floatval == arg2->floatval);
5673
255
        }
5674
2.03k
        break;
5675
0
    case XPATH_USERS:
5676
        /* TODO */
5677
0
        break;
5678
0
    case XPATH_NODESET:
5679
0
    case XPATH_XSLT_TREE:
5680
0
        break;
5681
2.87k
      }
5682
2.87k
      break;
5683
2.87k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
231k
    }
5690
231k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
231k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
231k
    return(ret);
5693
231k
}
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
243k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
243k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
243k
    int ret = 0;
5705
5706
243k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
243k
    arg2 = xmlXPathValuePop(ctxt);
5708
243k
    arg1 = xmlXPathValuePop(ctxt);
5709
243k
    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
243k
    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
243k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
234k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
12.8k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
3.28k
    argtmp = arg2;
5732
3.28k
    arg2 = arg1;
5733
3.28k
    arg1 = argtmp;
5734
3.28k
  }
5735
12.8k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
5.91k
      case XPATH_NODESET:
5739
5.91k
      case XPATH_XSLT_TREE:
5740
5.91k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
5.91k
    break;
5742
2.02k
      case XPATH_BOOLEAN:
5743
2.02k
    if ((arg1->nodesetval == NULL) ||
5744
2.02k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
300
    else
5746
300
        ret = 1;
5747
2.02k
    ret = (ret == arg2->boolval);
5748
2.02k
    break;
5749
3.23k
      case XPATH_NUMBER:
5750
3.23k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
3.23k
    break;
5752
1.72k
      case XPATH_STRING:
5753
1.72k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
1.72k
                                                 arg2->stringval, 0);
5755
1.72k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
12.8k
  }
5760
12.8k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
12.8k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
12.8k
  return(ret);
5763
12.8k
    }
5764
5765
230k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
243k
}
5767
5768
/**
5769
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5770
 *
5771
 * @param ctxt  the XPath Parser context
5772
 * @returns 0 or 1 depending on the results of the test.
5773
 */
5774
int
5775
5.59k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
5.59k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
5.59k
    int ret = 0;
5778
5779
5.59k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
5.59k
    arg2 = xmlXPathValuePop(ctxt);
5781
5.59k
    arg1 = xmlXPathValuePop(ctxt);
5782
5.59k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5783
0
  if (arg1 != NULL)
5784
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5785
0
  else
5786
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5787
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5788
0
    }
5789
5790
5.59k
    if (arg1 == arg2) {
5791
0
  xmlXPathReleaseObject(ctxt->context, arg1);
5792
0
        return(0);
5793
0
    }
5794
5795
    /*
5796
     *If either argument is a nodeset, it's a 'special case'
5797
     */
5798
5.59k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
4.98k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
4.98k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
388
    argtmp = arg2;
5805
388
    arg2 = arg1;
5806
388
    arg1 = argtmp;
5807
388
  }
5808
4.98k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
2.46k
      case XPATH_NODESET:
5812
2.46k
      case XPATH_XSLT_TREE:
5813
2.46k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
2.46k
    break;
5815
718
      case XPATH_BOOLEAN:
5816
718
    if ((arg1->nodesetval == NULL) ||
5817
718
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
497
    else
5819
497
        ret = 1;
5820
718
    ret = (ret != arg2->boolval);
5821
718
    break;
5822
728
      case XPATH_NUMBER:
5823
728
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
728
    break;
5825
1.07k
      case XPATH_STRING:
5826
1.07k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
1.07k
                                                 arg2->stringval, 1);
5828
1.07k
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
4.98k
  }
5833
4.98k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
4.98k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
4.98k
  return(ret);
5836
4.98k
    }
5837
5838
606
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
5.59k
}
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
831k
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
831k
    int ret = 0, arg1i = 0, arg2i = 0;
5866
831k
    xmlXPathObjectPtr arg1, arg2;
5867
5868
831k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
831k
    arg2 = xmlXPathValuePop(ctxt);
5870
831k
    arg1 = xmlXPathValuePop(ctxt);
5871
831k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
9
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
9
  else
5875
9
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
9
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
831k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
604k
      (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
246k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
226k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
219k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
219k
  } else {
5890
27.4k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
20.5k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
20.5k
                                arg1, arg2);
5893
20.5k
      } else {
5894
6.88k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
6.88k
                                arg2, arg1);
5896
6.88k
      }
5897
27.4k
  }
5898
246k
  return(ret);
5899
246k
    }
5900
5901
584k
    if (arg1->type != XPATH_NUMBER) {
5902
566k
  xmlXPathValuePush(ctxt, arg1);
5903
566k
  xmlXPathNumberFunction(ctxt, 1);
5904
566k
  arg1 = xmlXPathValuePop(ctxt);
5905
566k
    }
5906
584k
    if (arg2->type != XPATH_NUMBER) {
5907
565k
  xmlXPathValuePush(ctxt, arg2);
5908
565k
  xmlXPathNumberFunction(ctxt, 1);
5909
565k
  arg2 = xmlXPathValuePop(ctxt);
5910
565k
    }
5911
584k
    if (ctxt->error)
5912
207
        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
584k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
572k
  ret=0;
5920
572k
    } else {
5921
11.9k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
11.9k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
11.9k
  if (inf && strict) {
5924
5.23k
      if ((arg1i == -1 && arg2i != -1) ||
5925
5.01k
    (arg2i == 1 && arg1i != 1)) {
5926
1.09k
    ret = 1;
5927
4.13k
      } else if (arg1i == 0 && arg2i == 0) {
5928
3.41k
    ret = (arg1->floatval < arg2->floatval);
5929
3.41k
      } else {
5930
715
    ret = 0;
5931
715
      }
5932
5.23k
  }
5933
6.71k
  else if (inf && !strict) {
5934
1.29k
      if (arg1i == -1 || arg2i == 1) {
5935
429
    ret = 1;
5936
866
      } else if (arg1i == 0 && arg2i == 0) {
5937
388
    ret = (arg1->floatval <= arg2->floatval);
5938
478
      } else {
5939
478
    ret = 0;
5940
478
      }
5941
1.29k
  }
5942
5.42k
  else if (!inf && strict) {
5943
4.11k
      if ((arg1i == 1 && arg2i != 1) ||
5944
3.90k
    (arg2i == -1 && arg1i != -1)) {
5945
419
    ret = 1;
5946
3.69k
      } else if (arg1i == 0 && arg2i == 0) {
5947
2.88k
    ret = (arg1->floatval > arg2->floatval);
5948
2.88k
      } else {
5949
811
    ret = 0;
5950
811
      }
5951
4.11k
  }
5952
1.31k
  else if (!inf && !strict) {
5953
1.31k
      if (arg1i == 1 || arg2i == -1) {
5954
455
    ret = 1;
5955
855
      } else if (arg1i == 0 && arg2i == 0) {
5956
428
    ret = (arg1->floatval >= arg2->floatval);
5957
428
      } else {
5958
427
    ret = 0;
5959
427
      }
5960
1.31k
  }
5961
11.9k
    }
5962
584k
error:
5963
584k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
584k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
584k
    return(ret);
5966
584k
}
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
34.7k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
34.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
34.7k
    CAST_TO_NUMBER;
5979
34.7k
    CHECK_TYPE(XPATH_NUMBER);
5980
34.7k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
34.7k
}
5982
5983
/**
5984
 * Implement the add operation on XPath objects:
5985
 * The numeric operators convert their operands to numbers as if
5986
 * by calling the number function.
5987
 *
5988
 * @param ctxt  the XPath Parser context
5989
 */
5990
void
5991
2.41k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
2.41k
    xmlXPathObjectPtr arg;
5993
2.41k
    double val;
5994
5995
2.41k
    arg = xmlXPathValuePop(ctxt);
5996
2.41k
    if (arg == NULL)
5997
2.41k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
2.41k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
2.41k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
2.41k
    CAST_TO_NUMBER;
6001
2.41k
    CHECK_TYPE(XPATH_NUMBER);
6002
2.41k
    ctxt->value->floatval += val;
6003
2.41k
}
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
151k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
151k
    xmlXPathObjectPtr arg;
6015
151k
    double val;
6016
6017
151k
    arg = xmlXPathValuePop(ctxt);
6018
151k
    if (arg == NULL)
6019
151k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
151k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
151k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
151k
    CAST_TO_NUMBER;
6023
151k
    CHECK_TYPE(XPATH_NUMBER);
6024
151k
    ctxt->value->floatval -= val;
6025
151k
}
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
27.1k
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
27.1k
    xmlXPathObjectPtr arg;
6037
27.1k
    double val;
6038
6039
27.1k
    arg = xmlXPathValuePop(ctxt);
6040
27.1k
    if (arg == NULL)
6041
27.1k
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
27.1k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
27.1k
    xmlXPathReleaseObject(ctxt->context, arg);
6044
27.1k
    CAST_TO_NUMBER;
6045
27.1k
    CHECK_TYPE(XPATH_NUMBER);
6046
27.1k
    ctxt->value->floatval *= val;
6047
27.1k
}
6048
6049
/**
6050
 * Implement the div operation on XPath objects `arg1` / `arg2`.
6051
 * The numeric operators convert their operands to numbers as if
6052
 * by calling the number function.
6053
 *
6054
 * @param ctxt  the XPath Parser context
6055
 */
6056
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6057
void
6058
2.20k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
2.20k
    xmlXPathObjectPtr arg;
6060
2.20k
    double val;
6061
6062
2.20k
    arg = xmlXPathValuePop(ctxt);
6063
2.20k
    if (arg == NULL)
6064
2.20k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
2.20k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
2.20k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
2.20k
    CAST_TO_NUMBER;
6068
2.20k
    CHECK_TYPE(XPATH_NUMBER);
6069
2.20k
    ctxt->value->floatval /= val;
6070
2.20k
}
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
729
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
729
    xmlXPathObjectPtr arg;
6082
729
    double arg1, arg2;
6083
6084
729
    arg = xmlXPathValuePop(ctxt);
6085
729
    if (arg == NULL)
6086
729
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
729
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
729
    xmlXPathReleaseObject(ctxt->context, arg);
6089
729
    CAST_TO_NUMBER;
6090
729
    CHECK_TYPE(XPATH_NUMBER);
6091
727
    arg1 = ctxt->value->floatval;
6092
727
    if (arg2 == 0)
6093
334
  ctxt->value->floatval = xmlXPathNAN;
6094
393
    else {
6095
393
  ctxt->value->floatval = fmod(arg1, arg2);
6096
393
    }
6097
727
}
6098
6099
/************************************************************************
6100
 *                  *
6101
 *    The traversal functions         *
6102
 *                  *
6103
 ************************************************************************/
6104
6105
/*
6106
 * A traversal function enumerates nodes along an axis.
6107
 * Initially it must be called with NULL, and it indicates
6108
 * termination on the axis by returning NULL.
6109
 */
6110
typedef xmlNode *(*xmlXPathTraversalFunction)
6111
                    (xmlXPathParserContext *ctxt, xmlNode *cur);
6112
6113
/*
6114
 * A traversal function enumerates nodes along an axis.
6115
 * Initially it must be called with NULL, and it indicates
6116
 * termination on the axis by returning NULL.
6117
 * The context node of the traversal is specified via `contextNode`.
6118
 */
6119
typedef xmlNode *(*xmlXPathTraversalFunctionExt)
6120
                    (xmlNode *cur, xmlNode *contextNode);
6121
6122
/*
6123
 * Used for merging node sets in #xmlXPathCollectAndTest.
6124
 */
6125
typedef xmlNodeSet *(*xmlXPathNodeSetMergeFunction)
6126
        (xmlNodeSet *, xmlNodeSet *);
6127
6128
6129
/**
6130
 * Traversal function for the "self" direction
6131
 * The self axis contains just the context node itself
6132
 *
6133
 * @param ctxt  the XPath Parser context
6134
 * @param cur  the current node in the traversal
6135
 * @returns the next element following that axis
6136
 */
6137
xmlNode *
6138
1.29k
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
1.29k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
1.29k
    if (cur == NULL)
6141
751
        return(ctxt->context->node);
6142
540
    return(NULL);
6143
1.29k
}
6144
6145
/**
6146
 * Traversal function for the "child" direction
6147
 * The child axis contains the children of the context node in document order.
6148
 *
6149
 * @param ctxt  the XPath Parser context
6150
 * @param cur  the current node in the traversal
6151
 * @returns the next element following that axis
6152
 */
6153
xmlNode *
6154
1.56M
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
1.56M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
1.56M
    if (cur == NULL) {
6157
685k
  if (ctxt->context->node == NULL) return(NULL);
6158
685k
  switch (ctxt->context->node->type) {
6159
486k
            case XML_ELEMENT_NODE:
6160
678k
            case XML_TEXT_NODE:
6161
678k
            case XML_CDATA_SECTION_NODE:
6162
678k
            case XML_ENTITY_REF_NODE:
6163
678k
            case XML_ENTITY_NODE:
6164
680k
            case XML_PI_NODE:
6165
680k
            case XML_COMMENT_NODE:
6166
680k
            case XML_NOTATION_NODE:
6167
680k
            case XML_DTD_NODE:
6168
680k
    return(ctxt->context->node->children);
6169
4.10k
            case XML_DOCUMENT_NODE:
6170
4.10k
            case XML_DOCUMENT_TYPE_NODE:
6171
4.10k
            case XML_DOCUMENT_FRAG_NODE:
6172
4.10k
            case XML_HTML_DOCUMENT_NODE:
6173
4.10k
    return(((xmlDocPtr) ctxt->context->node)->children);
6174
0
      case XML_ELEMENT_DECL:
6175
0
      case XML_ATTRIBUTE_DECL:
6176
0
      case XML_ENTITY_DECL:
6177
0
            case XML_ATTRIBUTE_NODE:
6178
359
      case XML_NAMESPACE_DECL:
6179
359
      case XML_XINCLUDE_START:
6180
359
      case XML_XINCLUDE_END:
6181
359
    return(NULL);
6182
685k
  }
6183
0
  return(NULL);
6184
685k
    }
6185
881k
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
881k
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
881k
    return(cur->next);
6189
881k
}
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
3.10M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
3.10M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
3.10M
    if (cur == NULL) {
6203
1.81M
  cur = ctxt->context->node;
6204
1.81M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
1.81M
  switch (cur->type) {
6209
1.28M
            case XML_ELEMENT_NODE:
6210
1.28M
      case XML_DOCUMENT_FRAG_NODE:
6211
1.28M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
1.28M
            case XML_ENTITY_NODE:
6213
1.28M
    cur = cur->children;
6214
1.28M
    if (cur != NULL) {
6215
401k
        if (cur->type == XML_ELEMENT_NODE)
6216
341k
      return(cur);
6217
61.3k
        do {
6218
61.3k
      cur = cur->next;
6219
61.3k
        } while ((cur != NULL) &&
6220
57.8k
      (cur->type != XML_ELEMENT_NODE));
6221
60.7k
        return(cur);
6222
401k
    }
6223
885k
    return(NULL);
6224
66.2k
            case XML_DOCUMENT_NODE:
6225
66.2k
            case XML_HTML_DOCUMENT_NODE:
6226
66.2k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
466k
      default:
6228
466k
    return(NULL);
6229
1.81M
  }
6230
0
  return(NULL);
6231
1.81M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
1.28M
    switch (cur->type) {
6236
1.28M
  case XML_ELEMENT_NODE:
6237
1.28M
  case XML_TEXT_NODE:
6238
1.28M
  case XML_ENTITY_REF_NODE:
6239
1.28M
  case XML_ENTITY_NODE:
6240
1.28M
  case XML_CDATA_SECTION_NODE:
6241
1.28M
  case XML_PI_NODE:
6242
1.28M
  case XML_COMMENT_NODE:
6243
1.28M
  case XML_XINCLUDE_END:
6244
1.28M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
1.28M
    }
6249
1.28M
    if (cur->next != NULL) {
6250
841k
  if (cur->next->type == XML_ELEMENT_NODE)
6251
387k
      return(cur->next);
6252
453k
  cur = cur->next;
6253
454k
  do {
6254
454k
      cur = cur->next;
6255
454k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
453k
  return(cur);
6257
841k
    }
6258
440k
    return(NULL);
6259
1.28M
}
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
29.9M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
29.9M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
29.9M
    if (cur == NULL) {
6274
28.1k
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
28.1k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
27.8k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
474
      return(NULL);
6279
6280
27.6k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
25.1k
      return(ctxt->context->doc->children);
6282
2.48k
        return(ctxt->context->node->children);
6283
27.6k
    }
6284
6285
29.9M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
29.9M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
2.73M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
2.73M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
2.73M
      if (cur->type != XML_DTD_NODE)
6297
2.73M
    return(cur);
6298
2.73M
  }
6299
2.73M
    }
6300
6301
27.1M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
26.9M
    while (cur->next != NULL) {
6304
26.5M
  cur = cur->next;
6305
26.5M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
26.5M
      (cur->type != XML_DTD_NODE))
6307
26.5M
      return(cur);
6308
26.5M
    }
6309
6310
2.75M
    do {
6311
2.75M
        cur = cur->parent;
6312
2.75M
  if (cur == NULL) break;
6313
2.75M
  if (cur == ctxt->context->node) return(NULL);
6314
2.50M
  if (cur->next != NULL) {
6315
134k
      cur = cur->next;
6316
134k
      return(cur);
6317
134k
  }
6318
2.50M
    } while (cur != NULL);
6319
0
    return(cur);
6320
385k
}
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
30.0M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
30.0M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
30.0M
    if (cur == NULL)
6337
606k
        return(ctxt->context->node);
6338
6339
29.4M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
29.4M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
29.4M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
128k
        return(NULL);
6344
6345
29.2M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
29.4M
}
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
611k
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
611k
    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
611k
    if (cur == NULL) {
6365
313k
  if (ctxt->context->node == NULL) return(NULL);
6366
313k
  switch (ctxt->context->node->type) {
6367
288k
            case XML_ELEMENT_NODE:
6368
300k
            case XML_TEXT_NODE:
6369
300k
            case XML_CDATA_SECTION_NODE:
6370
300k
            case XML_ENTITY_REF_NODE:
6371
300k
            case XML_ENTITY_NODE:
6372
300k
            case XML_PI_NODE:
6373
301k
            case XML_COMMENT_NODE:
6374
301k
            case XML_NOTATION_NODE:
6375
301k
            case XML_DTD_NODE:
6376
301k
      case XML_ELEMENT_DECL:
6377
301k
      case XML_ATTRIBUTE_DECL:
6378
301k
      case XML_XINCLUDE_START:
6379
301k
      case XML_XINCLUDE_END:
6380
301k
      case XML_ENTITY_DECL:
6381
301k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
301k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
293k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
293k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
293k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
301k
    return(ctxt->context->node->parent);
6389
196
            case XML_ATTRIBUTE_NODE: {
6390
196
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
196
    return(att->parent);
6393
301k
      }
6394
8.58k
            case XML_DOCUMENT_NODE:
6395
8.58k
            case XML_DOCUMENT_TYPE_NODE:
6396
8.58k
            case XML_DOCUMENT_FRAG_NODE:
6397
8.58k
            case XML_HTML_DOCUMENT_NODE:
6398
8.58k
                return(NULL);
6399
3.05k
      case XML_NAMESPACE_DECL: {
6400
3.05k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
3.05k
    if ((ns->next != NULL) &&
6403
3.05k
        (ns->next->type != XML_NAMESPACE_DECL))
6404
3.05k
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
3.05k
      }
6407
313k
  }
6408
313k
    }
6409
298k
    return(NULL);
6410
611k
}
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
276k
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
276k
    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
276k
    if (cur == NULL) {
6433
38.3k
  if (ctxt->context->node == NULL) return(NULL);
6434
38.3k
  switch (ctxt->context->node->type) {
6435
33.6k
            case XML_ELEMENT_NODE:
6436
35.8k
            case XML_TEXT_NODE:
6437
36.1k
            case XML_CDATA_SECTION_NODE:
6438
36.1k
            case XML_ENTITY_REF_NODE:
6439
36.1k
            case XML_ENTITY_NODE:
6440
36.3k
            case XML_PI_NODE:
6441
36.5k
            case XML_COMMENT_NODE:
6442
36.5k
      case XML_DTD_NODE:
6443
36.5k
      case XML_ELEMENT_DECL:
6444
36.5k
      case XML_ATTRIBUTE_DECL:
6445
36.5k
      case XML_ENTITY_DECL:
6446
36.5k
            case XML_NOTATION_NODE:
6447
36.5k
      case XML_XINCLUDE_START:
6448
36.5k
      case XML_XINCLUDE_END:
6449
36.5k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
36.5k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
34.8k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
34.8k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
34.8k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
36.5k
    return(ctxt->context->node->parent);
6457
204
            case XML_ATTRIBUTE_NODE: {
6458
204
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
204
    return(tmp->parent);
6461
36.5k
      }
6462
1.37k
            case XML_DOCUMENT_NODE:
6463
1.37k
            case XML_DOCUMENT_TYPE_NODE:
6464
1.37k
            case XML_DOCUMENT_FRAG_NODE:
6465
1.37k
            case XML_HTML_DOCUMENT_NODE:
6466
1.37k
                return(NULL);
6467
217
      case XML_NAMESPACE_DECL: {
6468
217
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
217
    if ((ns->next != NULL) &&
6471
217
        (ns->next->type != XML_NAMESPACE_DECL))
6472
217
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
217
      }
6476
38.3k
  }
6477
0
  return(NULL);
6478
38.3k
    }
6479
237k
    if (cur == ctxt->context->doc->children)
6480
43.9k
  return((xmlNodePtr) ctxt->context->doc);
6481
193k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
47.3k
  return(NULL);
6483
146k
    switch (cur->type) {
6484
143k
  case XML_ELEMENT_NODE:
6485
144k
  case XML_TEXT_NODE:
6486
144k
  case XML_CDATA_SECTION_NODE:
6487
144k
  case XML_ENTITY_REF_NODE:
6488
144k
  case XML_ENTITY_NODE:
6489
144k
  case XML_PI_NODE:
6490
144k
  case XML_COMMENT_NODE:
6491
144k
  case XML_NOTATION_NODE:
6492
145k
  case XML_DTD_NODE:
6493
145k
        case XML_ELEMENT_DECL:
6494
145k
        case XML_ATTRIBUTE_DECL:
6495
145k
        case XML_ENTITY_DECL:
6496
145k
  case XML_XINCLUDE_START:
6497
145k
  case XML_XINCLUDE_END:
6498
145k
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
145k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
143k
    ((cur->parent->name[0] == ' ') ||
6502
143k
     (xmlStrEqual(cur->parent->name,
6503
143k
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
145k
      return(cur->parent);
6506
198
  case XML_ATTRIBUTE_NODE: {
6507
198
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
198
      return(att->parent);
6510
145k
  }
6511
427
  case XML_NAMESPACE_DECL: {
6512
427
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
427
      if ((ns->next != NULL) &&
6515
427
          (ns->next->type != XML_NAMESPACE_DECL))
6516
427
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
427
  }
6520
0
  case XML_DOCUMENT_NODE:
6521
0
  case XML_DOCUMENT_TYPE_NODE:
6522
0
  case XML_DOCUMENT_FRAG_NODE:
6523
0
  case XML_HTML_DOCUMENT_NODE:
6524
0
      return(NULL);
6525
146k
    }
6526
0
    return(NULL);
6527
146k
}
6528
6529
/**
6530
 * Traversal function for the "ancestor-or-self" direction
6531
 * he ancestor-or-self axis contains the context node and ancestors of
6532
 * the context node in reverse document order; thus the context node is
6533
 * the first node on the axis, and the context node's parent the second;
6534
 * parent here is defined the same as with the parent axis.
6535
 *
6536
 * @param ctxt  the XPath Parser context
6537
 * @param cur  the current node in the traversal
6538
 * @returns the next element following that axis
6539
 */
6540
xmlNode *
6541
66.0k
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
66.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
66.0k
    if (cur == NULL)
6544
10.4k
        return(ctxt->context->node);
6545
55.6k
    return(xmlXPathNextAncestor(ctxt, cur));
6546
66.0k
}
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
7.26k
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
7.26k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
7.26k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
7.07k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
410
        return(NULL);
6563
6564
6.85k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6565
0
        return(NULL);
6566
6567
6.85k
    if (cur == NULL)
6568
3.44k
        cur = ctxt->context->node;
6569
6570
6.85k
    if (cur->type == XML_DOCUMENT_NODE)
6571
274
        return(NULL);
6572
6573
6.58k
    return(cur->next);
6574
6.85k
}
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
30.4k
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6588
30.4k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589
30.4k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6590
30.2k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6591
424
        return(NULL);
6592
6593
30.0k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6594
0
        return(NULL);
6595
6596
30.0k
    if (cur == NULL) {
6597
4.66k
        cur = ctxt->context->node;
6598
25.3k
    } else if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6599
194
        cur = cur->prev;
6600
194
        if (cur == NULL)
6601
0
            cur = ctxt->context->node;
6602
194
    }
6603
6604
30.0k
    if (cur->type == XML_DOCUMENT_NODE)
6605
293
        return(NULL);
6606
6607
29.7k
    return(cur->prev);
6608
30.0k
}
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
1.52M
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6623
1.52M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6624
1.52M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6625
1.52M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6626
960k
        return(cur->children);
6627
6628
566k
    if (cur == NULL) {
6629
3.86k
        cur = ctxt->context->node;
6630
3.86k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6631
202
            cur = cur->parent;
6632
3.66k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6633
229
            xmlNsPtr ns = (xmlNsPtr) cur;
6634
6635
229
            if ((ns->next == NULL) ||
6636
229
                (ns->next->type == XML_NAMESPACE_DECL))
6637
0
                return (NULL);
6638
229
            cur = (xmlNodePtr) ns->next;
6639
229
        }
6640
3.86k
    }
6641
6642
    /* ERROR */
6643
566k
    if (cur == NULL)
6644
0
        return(NULL);
6645
6646
566k
    if (cur->type == XML_DOCUMENT_NODE)
6647
476
        return(NULL);
6648
6649
566k
    if (cur->next != NULL)
6650
292k
        return(cur->next);
6651
6652
425k
    do {
6653
425k
        cur = cur->parent;
6654
425k
        if (cur == NULL)
6655
0
            break;
6656
425k
        if (cur == (xmlNodePtr) ctxt->context->doc)
6657
3.35k
            return(NULL);
6658
422k
        if (cur->next != NULL && cur->type != XML_DOCUMENT_NODE)
6659
270k
            return(cur->next);
6660
422k
    } while (cur != NULL);
6661
6662
0
    return(cur);
6663
274k
}
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
44.4k
{
6757
44.4k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6758
44.4k
    if (cur == NULL) {
6759
7.78k
        cur = ctxt->context->node;
6760
7.78k
        if (cur == NULL)
6761
0
            return (NULL);
6762
7.78k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6763
216
            cur = cur->parent;
6764
7.56k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6765
215
            xmlNsPtr ns = (xmlNsPtr) cur;
6766
6767
215
            if ((ns->next == NULL) ||
6768
215
                (ns->next->type == XML_NAMESPACE_DECL))
6769
0
                return (NULL);
6770
215
            cur = (xmlNodePtr) ns->next;
6771
215
        }
6772
7.78k
        ctxt->ancestor = cur->parent;
6773
7.78k
    }
6774
6775
44.4k
    if (cur->type == XML_NAMESPACE_DECL || cur->type == XML_DOCUMENT_NODE)
6776
591
        return(NULL);
6777
6778
43.8k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6779
278
  cur = cur->prev;
6780
6781
68.1k
    while (cur->prev == NULL) {
6782
32.0k
        cur = cur->parent;
6783
32.0k
        if (cur == NULL)
6784
1.08k
            return (NULL);
6785
30.9k
        if (cur == ctxt->context->doc->children)
6786
5.87k
            return (NULL);
6787
25.0k
        if (cur != ctxt->ancestor)
6788
823
            return (cur);
6789
24.2k
        ctxt->ancestor = cur->parent;
6790
24.2k
    }
6791
6792
36.0k
    if (cur->type == XML_DOCUMENT_NODE)
6793
0
        return(NULL);
6794
6795
36.0k
    cur = cur->prev;
6796
36.9k
    while (cur->last != NULL)
6797
877
        cur = cur->last;
6798
36.0k
    return (cur);
6799
36.0k
}
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
1.92M
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6815
1.92M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6816
1.92M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6817
1.83M
    if (cur == NULL) {
6818
444k
        if (ctxt->context->tmpNsList != NULL)
6819
304
      xmlFree(ctxt->context->tmpNsList);
6820
444k
  ctxt->context->tmpNsNr = 0;
6821
444k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6822
444k
                             &ctxt->context->tmpNsList) < 0) {
6823
1
            xmlXPathPErrMemory(ctxt);
6824
1
            return(NULL);
6825
1
        }
6826
444k
        if (ctxt->context->tmpNsList != NULL) {
6827
1.37M
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6828
949k
                ctxt->context->tmpNsNr++;
6829
949k
            }
6830
429k
        }
6831
444k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6832
444k
    }
6833
1.39M
    if (ctxt->context->tmpNsNr > 0) {
6834
949k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6835
949k
    } else {
6836
442k
  if (ctxt->context->tmpNsList != NULL)
6837
429k
      xmlFree(ctxt->context->tmpNsList);
6838
442k
  ctxt->context->tmpNsList = NULL;
6839
442k
  return(NULL);
6840
442k
    }
6841
1.39M
}
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
71.9k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6853
71.9k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854
71.9k
    if (ctxt->context->node == NULL)
6855
0
  return(NULL);
6856
71.9k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6857
17.5k
  return(NULL);
6858
54.4k
    if (cur == NULL) {
6859
47.4k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6860
0
      return(NULL);
6861
47.4k
        return((xmlNodePtr)ctxt->context->node->properties);
6862
47.4k
    }
6863
6.92k
    return((xmlNodePtr)cur->next);
6864
54.4k
}
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
206k
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6888
206k
    if ((ctxt == NULL) || (ctxt->context == NULL))
6889
0
  return;
6890
206k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6891
206k
                                            (xmlNodePtr) ctxt->context->doc));
6892
206k
}
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
27.9k
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6912
83.7k
    CHECK_ARITY(0);
6913
83.7k
    if (ctxt->context->contextSize >= 0) {
6914
27.9k
  xmlXPathValuePush(ctxt,
6915
27.9k
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6916
27.9k
    } else {
6917
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6918
0
    }
6919
83.7k
}
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
8.69k
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6933
26.0k
    CHECK_ARITY(0);
6934
26.0k
    if (ctxt->context->proximityPosition >= 0) {
6935
8.69k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6936
8.69k
            (double) ctxt->context->proximityPosition));
6937
8.69k
    } else {
6938
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6939
0
    }
6940
26.0k
}
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
633
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6951
633
    xmlXPathObjectPtr cur;
6952
6953
1.89k
    CHECK_ARITY(1);
6954
1.89k
    if ((ctxt->value == NULL) ||
6955
629
  ((ctxt->value->type != XPATH_NODESET) &&
6956
2
   (ctxt->value->type != XPATH_XSLT_TREE)))
6957
627
  XP_ERROR(XPATH_INVALID_TYPE);
6958
627
    cur = xmlXPathValuePop(ctxt);
6959
6960
627
    if ((cur == NULL) || (cur->nodesetval == NULL))
6961
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6962
627
    else
6963
627
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6964
627
      (double) cur->nodesetval->nodeNr));
6965
627
    xmlXPathReleaseObject(ctxt->context, cur);
6966
627
}
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
708k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6977
708k
    xmlNodeSetPtr ret;
6978
708k
    const xmlChar *cur = ids;
6979
708k
    xmlChar *ID;
6980
708k
    xmlAttrPtr attr;
6981
708k
    xmlNodePtr elem = NULL;
6982
6983
708k
    if (ids == NULL) return(NULL);
6984
6985
708k
    ret = xmlXPathNodeSetCreate(NULL);
6986
708k
    if (ret == NULL)
6987
7
        return(ret);
6988
6989
708k
    while (IS_BLANK_CH(*cur)) cur++;
6990
10.8M
    while (*cur != 0) {
6991
72.5M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6992
62.3M
      cur++;
6993
6994
10.1M
        ID = xmlStrndup(ids, cur - ids);
6995
10.1M
  if (ID == NULL) {
6996
21
            xmlXPathFreeNodeSet(ret);
6997
21
            return(NULL);
6998
21
        }
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
10.1M
        attr = xmlGetID(doc, ID);
7007
10.1M
        xmlFree(ID);
7008
10.1M
        if (attr != NULL) {
7009
3.55k
            if (attr->type == XML_ATTRIBUTE_NODE)
7010
3.55k
                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
3.55k
            if (elem != NULL) {
7016
3.55k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7017
7
                    xmlXPathFreeNodeSet(ret);
7018
7
                    return(NULL);
7019
7
                }
7020
3.55k
            }
7021
3.55k
        }
7022
7023
11.7M
  while (IS_BLANK_CH(*cur)) cur++;
7024
10.1M
  ids = cur;
7025
10.1M
    }
7026
708k
    return(ret);
7027
708k
}
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
20.2k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7048
20.2k
    xmlChar *tokens;
7049
20.2k
    xmlNodeSetPtr ret;
7050
20.2k
    xmlXPathObjectPtr obj;
7051
7052
60.7k
    CHECK_ARITY(1);
7053
60.7k
    obj = xmlXPathValuePop(ctxt);
7054
60.7k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7055
20.2k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7056
15.1k
  xmlNodeSetPtr ns;
7057
15.1k
  int i;
7058
7059
15.1k
  ret = xmlXPathNodeSetCreate(NULL);
7060
15.1k
        if (ret == NULL)
7061
1
            xmlXPathPErrMemory(ctxt);
7062
7063
15.1k
  if (obj->nodesetval != NULL) {
7064
718k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7065
702k
    tokens =
7066
702k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7067
702k
                if (tokens == NULL)
7068
6
                    xmlXPathPErrMemory(ctxt);
7069
702k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7070
702k
                if (ns == NULL)
7071
28
                    xmlXPathPErrMemory(ctxt);
7072
702k
    ret = xmlXPathNodeSetMerge(ret, ns);
7073
702k
                if (ret == NULL)
7074
1
                    xmlXPathPErrMemory(ctxt);
7075
702k
    xmlXPathFreeNodeSet(ns);
7076
702k
    if (tokens != NULL)
7077
702k
        xmlFree(tokens);
7078
702k
      }
7079
15.1k
  }
7080
15.1k
  xmlXPathReleaseObject(ctxt->context, obj);
7081
15.1k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7082
15.1k
  return;
7083
15.1k
    }
7084
5.14k
    tokens = xmlXPathCastToString(obj);
7085
5.14k
    if (tokens == NULL)
7086
7
        xmlXPathPErrMemory(ctxt);
7087
5.14k
    xmlXPathReleaseObject(ctxt->context, obj);
7088
5.14k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7089
5.14k
    if (ret == NULL)
7090
20
        xmlXPathPErrMemory(ctxt);
7091
5.14k
    xmlFree(tokens);
7092
5.14k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7093
5.14k
}
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
7.40k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7109
7.40k
    xmlXPathObjectPtr cur;
7110
7111
7.40k
    if (ctxt == NULL) return;
7112
7113
7.40k
    if (nargs == 0) {
7114
394
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7115
394
  nargs = 1;
7116
394
    }
7117
7118
22.2k
    CHECK_ARITY(1);
7119
22.2k
    if ((ctxt->value == NULL) ||
7120
7.40k
  ((ctxt->value->type != XPATH_NODESET) &&
7121
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7122
7.40k
  XP_ERROR(XPATH_INVALID_TYPE);
7123
7.40k
    cur = xmlXPathValuePop(ctxt);
7124
7125
7.40k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7126
214
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7127
7.19k
    } else {
7128
7.19k
  int i = 0; /* Should be first in document order !!!!! */
7129
7.19k
  switch (cur->nodesetval->nodeTab[i]->type) {
7130
200
  case XML_ELEMENT_NODE:
7131
394
  case XML_ATTRIBUTE_NODE:
7132
609
  case XML_PI_NODE:
7133
609
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7134
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7135
609
      else
7136
609
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7137
609
      cur->nodesetval->nodeTab[i]->name));
7138
609
      break;
7139
1.04k
  case XML_NAMESPACE_DECL:
7140
1.04k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7141
1.04k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7142
1.04k
      break;
7143
5.53k
  default:
7144
5.53k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7145
7.19k
  }
7146
7.19k
    }
7147
7.40k
    xmlXPathReleaseObject(ctxt->context, cur);
7148
7.40k
}
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
1.11k
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7165
1.11k
    xmlXPathObjectPtr cur;
7166
7167
1.11k
    if (ctxt == NULL) return;
7168
7169
1.11k
    if (nargs == 0) {
7170
536
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7171
536
  nargs = 1;
7172
536
    }
7173
3.33k
    CHECK_ARITY(1);
7174
3.33k
    if ((ctxt->value == NULL) ||
7175
1.11k
  ((ctxt->value->type != XPATH_NODESET) &&
7176
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7177
1.10k
  XP_ERROR(XPATH_INVALID_TYPE);
7178
1.10k
    cur = xmlXPathValuePop(ctxt);
7179
7180
1.10k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7181
215
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7182
894
    } else {
7183
894
  int i = 0; /* Should be first in document order !!!!! */
7184
894
  switch (cur->nodesetval->nodeTab[i]->type) {
7185
535
  case XML_ELEMENT_NODE:
7186
535
  case XML_ATTRIBUTE_NODE:
7187
535
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7188
336
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7189
199
      else
7190
199
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7191
199
        cur->nodesetval->nodeTab[i]->ns->href));
7192
535
      break;
7193
359
  default:
7194
359
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7195
894
  }
7196
894
    }
7197
1.10k
    xmlXPathReleaseObject(ctxt->context, cur);
7198
1.10k
}
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
21.7k
{
7224
21.7k
    xmlXPathObjectPtr cur;
7225
7226
21.7k
    if (nargs == 0) {
7227
21.0k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7228
21.0k
        nargs = 1;
7229
21.0k
    }
7230
7231
65.3k
    CHECK_ARITY(1);
7232
65.3k
    if ((ctxt->value == NULL) ||
7233
21.7k
        ((ctxt->value->type != XPATH_NODESET) &&
7234
1
         (ctxt->value->type != XPATH_XSLT_TREE)))
7235
21.7k
        XP_ERROR(XPATH_INVALID_TYPE);
7236
21.7k
    cur = xmlXPathValuePop(ctxt);
7237
7238
21.7k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7239
678
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7240
21.1k
    } else {
7241
21.1k
        int i = 0;              /* Should be first in document order !!!!! */
7242
7243
21.1k
        switch (cur->nodesetval->nodeTab[i]->type) {
7244
14.3k
            case XML_ELEMENT_NODE:
7245
14.3k
            case XML_ATTRIBUTE_NODE:
7246
14.3k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7247
0
        xmlXPathValuePush(ctxt,
7248
0
      xmlXPathCacheNewCString(ctxt, ""));
7249
14.3k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7250
13.8k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7251
13.8k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7252
13.8k
          cur->nodesetval->nodeTab[i]->name));
7253
13.8k
    } else {
7254
421
        xmlChar *fullname;
7255
7256
421
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7257
421
             cur->nodesetval->nodeTab[i]->ns->prefix,
7258
421
             NULL, 0);
7259
421
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7260
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7261
421
        if (fullname == NULL)
7262
1
                        xmlXPathPErrMemory(ctxt);
7263
421
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7264
421
                }
7265
14.3k
                break;
7266
6.79k
            default:
7267
6.79k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7268
6.79k
        cur->nodesetval->nodeTab[i]));
7269
6.79k
                xmlXPathLocalNameFunction(ctxt, 1);
7270
21.1k
        }
7271
21.1k
    }
7272
21.7k
    xmlXPathReleaseObject(ctxt->context, cur);
7273
21.7k
}
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
30.9k
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7313
30.9k
    xmlXPathObjectPtr cur;
7314
30.9k
    xmlChar *stringval;
7315
7316
30.9k
    if (ctxt == NULL) return;
7317
30.9k
    if (nargs == 0) {
7318
664
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7319
664
        if (stringval == NULL)
7320
1
            xmlXPathPErrMemory(ctxt);
7321
664
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7322
664
  return;
7323
664
    }
7324
7325
121k
    CHECK_ARITY(1);
7326
121k
    cur = xmlXPathValuePop(ctxt);
7327
121k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7328
30.3k
    if (cur->type != XPATH_STRING) {
7329
30.0k
        stringval = xmlXPathCastToString(cur);
7330
30.0k
        if (stringval == NULL)
7331
31
            xmlXPathPErrMemory(ctxt);
7332
30.0k
        xmlXPathReleaseObject(ctxt->context, cur);
7333
30.0k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7334
30.0k
    }
7335
30.3k
    xmlXPathValuePush(ctxt, cur);
7336
30.3k
}
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
1.48k
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7351
1.48k
    xmlXPathObjectPtr cur;
7352
7353
1.48k
    if (nargs == 0) {
7354
623
        if ((ctxt == NULL) || (ctxt->context == NULL))
7355
0
      return;
7356
623
  if (ctxt->context->node == NULL) {
7357
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7358
623
  } else {
7359
623
      xmlChar *content;
7360
7361
623
      content = xmlXPathCastNodeToString(ctxt->context->node);
7362
623
            if (content == NULL)
7363
1
                xmlXPathPErrMemory(ctxt);
7364
623
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7365
623
    xmlUTF8Strlen(content)));
7366
623
      xmlFree(content);
7367
623
  }
7368
623
  return;
7369
623
    }
7370
3.43k
    CHECK_ARITY(1);
7371
3.43k
    CAST_TO_STRING;
7372
3.43k
    CHECK_TYPE(XPATH_STRING);
7373
856
    cur = xmlXPathValuePop(ctxt);
7374
856
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7375
856
  xmlUTF8Strlen(cur->stringval)));
7376
856
    xmlXPathReleaseObject(ctxt->context, cur);
7377
856
}
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
1.30k
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7389
1.30k
    xmlXPathObjectPtr cur, newobj;
7390
1.30k
    xmlChar *tmp;
7391
7392
1.30k
    if (ctxt == NULL) return;
7393
1.30k
    if (nargs < 2) {
7394
1
  CHECK_ARITY(2);
7395
1
    }
7396
7397
1.30k
    CAST_TO_STRING;
7398
1.30k
    cur = xmlXPathValuePop(ctxt);
7399
1.30k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7400
1
  xmlXPathReleaseObject(ctxt->context, cur);
7401
1
  return;
7402
1
    }
7403
1.29k
    nargs--;
7404
7405
3.74k
    while (nargs > 0) {
7406
2.44k
  CAST_TO_STRING;
7407
2.44k
  newobj = xmlXPathValuePop(ctxt);
7408
2.44k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7409
3
      xmlXPathReleaseObject(ctxt->context, newobj);
7410
3
      xmlXPathReleaseObject(ctxt->context, cur);
7411
3
      XP_ERROR(XPATH_INVALID_TYPE);
7412
0
  }
7413
2.44k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7414
2.44k
        if (tmp == NULL)
7415
1
            xmlXPathPErrMemory(ctxt);
7416
2.44k
  newobj->stringval = cur->stringval;
7417
2.44k
  cur->stringval = tmp;
7418
2.44k
  xmlXPathReleaseObject(ctxt->context, newobj);
7419
2.44k
  nargs--;
7420
2.44k
    }
7421
1.29k
    xmlXPathValuePush(ctxt, cur);
7422
1.29k
}
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
1.10k
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7435
1.10k
    xmlXPathObjectPtr hay, needle;
7436
7437
3.30k
    CHECK_ARITY(2);
7438
3.30k
    CAST_TO_STRING;
7439
3.30k
    CHECK_TYPE(XPATH_STRING);
7440
1.10k
    needle = xmlXPathValuePop(ctxt);
7441
1.10k
    CAST_TO_STRING;
7442
1.10k
    hay = xmlXPathValuePop(ctxt);
7443
7444
1.10k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7445
2
  xmlXPathReleaseObject(ctxt->context, hay);
7446
2
  xmlXPathReleaseObject(ctxt->context, needle);
7447
2
  XP_ERROR(XPATH_INVALID_TYPE);
7448
0
    }
7449
1.09k
    if (xmlStrstr(hay->stringval, needle->stringval))
7450
711
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7451
388
    else
7452
388
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7453
1.09k
    xmlXPathReleaseObject(ctxt->context, hay);
7454
1.09k
    xmlXPathReleaseObject(ctxt->context, needle);
7455
1.09k
}
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
864
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7468
864
    xmlXPathObjectPtr hay, needle;
7469
864
    int n;
7470
7471
2.59k
    CHECK_ARITY(2);
7472
2.59k
    CAST_TO_STRING;
7473
2.59k
    CHECK_TYPE(XPATH_STRING);
7474
862
    needle = xmlXPathValuePop(ctxt);
7475
862
    CAST_TO_STRING;
7476
862
    hay = xmlXPathValuePop(ctxt);
7477
7478
862
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7479
2
  xmlXPathReleaseObject(ctxt->context, hay);
7480
2
  xmlXPathReleaseObject(ctxt->context, needle);
7481
2
  XP_ERROR(XPATH_INVALID_TYPE);
7482
0
    }
7483
860
    n = xmlStrlen(needle->stringval);
7484
860
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7485
514
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7486
346
    else
7487
346
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7488
860
    xmlXPathReleaseObject(ctxt->context, hay);
7489
860
    xmlXPathReleaseObject(ctxt->context, needle);
7490
860
}
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
2.39k
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7521
2.39k
    xmlXPathObjectPtr str, start, len;
7522
2.39k
    double le=0, in;
7523
2.39k
    int i = 1, j = INT_MAX;
7524
7525
2.39k
    if (nargs < 2) {
7526
1
  CHECK_ARITY(2);
7527
1
    }
7528
2.39k
    if (nargs > 3) {
7529
1
  CHECK_ARITY(3);
7530
1
    }
7531
    /*
7532
     * take care of possible last (position) argument
7533
    */
7534
2.39k
    if (nargs == 3) {
7535
1.11k
  CAST_TO_NUMBER;
7536
1.11k
  CHECK_TYPE(XPATH_NUMBER);
7537
1.11k
  len = xmlXPathValuePop(ctxt);
7538
1.11k
  le = len->floatval;
7539
1.11k
  xmlXPathReleaseObject(ctxt->context, len);
7540
1.11k
    }
7541
7542
2.38k
    CAST_TO_NUMBER;
7543
2.38k
    CHECK_TYPE(XPATH_NUMBER);
7544
2.38k
    start = xmlXPathValuePop(ctxt);
7545
2.38k
    in = start->floatval;
7546
2.38k
    xmlXPathReleaseObject(ctxt->context, start);
7547
2.38k
    CAST_TO_STRING;
7548
2.38k
    CHECK_TYPE(XPATH_STRING);
7549
2.38k
    str = xmlXPathValuePop(ctxt);
7550
7551
2.38k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7552
856
        i = INT_MAX;
7553
1.53k
    } else if (in >= 1.0) {
7554
981
        i = (int)in;
7555
981
        if (in - floor(in) >= 0.5)
7556
227
            i += 1;
7557
981
    }
7558
7559
2.38k
    if (nargs == 3) {
7560
1.11k
        double rin, rle, end;
7561
7562
1.11k
        rin = floor(in);
7563
1.11k
        if (in - rin >= 0.5)
7564
194
            rin += 1.0;
7565
7566
1.11k
        rle = floor(le);
7567
1.11k
        if (le - rle >= 0.5)
7568
194
            rle += 1.0;
7569
7570
1.11k
        end = rin + rle;
7571
1.11k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7572
298
            j = 1;
7573
813
        } else if (end < INT_MAX) {
7574
596
            j = (int)end;
7575
596
        }
7576
1.11k
    }
7577
7578
2.38k
    i -= 1;
7579
2.38k
    j -= 1;
7580
7581
2.38k
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7582
760
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7583
760
        if (ret == NULL)
7584
4
            xmlXPathPErrMemory(ctxt);
7585
760
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7586
760
  xmlFree(ret);
7587
1.62k
    } else {
7588
1.62k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7589
1.62k
    }
7590
7591
2.38k
    xmlXPathReleaseObject(ctxt->context, str);
7592
2.38k
}
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
1.32k
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7608
1.32k
    xmlXPathObjectPtr str = NULL;
7609
1.32k
    xmlXPathObjectPtr find = NULL;
7610
1.32k
    const xmlChar *point;
7611
1.32k
    xmlChar *result;
7612
7613
3.98k
    CHECK_ARITY(2);
7614
3.98k
    CAST_TO_STRING;
7615
3.98k
    find = xmlXPathValuePop(ctxt);
7616
3.98k
    CAST_TO_STRING;
7617
3.98k
    str = xmlXPathValuePop(ctxt);
7618
3.98k
    if (ctxt->error != 0)
7619
2
        goto error;
7620
7621
1.32k
    point = xmlStrstr(str->stringval, find->stringval);
7622
1.32k
    if (point == NULL) {
7623
951
        result = xmlStrdup(BAD_CAST "");
7624
951
    } else {
7625
375
        result = xmlStrndup(str->stringval, point - str->stringval);
7626
375
    }
7627
1.32k
    if (result == NULL) {
7628
1
        xmlXPathPErrMemory(ctxt);
7629
1
        goto error;
7630
1
    }
7631
1.32k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7632
7633
1.32k
error:
7634
1.32k
    xmlXPathReleaseObject(ctxt->context, str);
7635
1.32k
    xmlXPathReleaseObject(ctxt->context, find);
7636
1.32k
}
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
1.57k
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7653
1.57k
    xmlXPathObjectPtr str = NULL;
7654
1.57k
    xmlXPathObjectPtr find = NULL;
7655
1.57k
    const xmlChar *point;
7656
1.57k
    xmlChar *result;
7657
7658
4.70k
    CHECK_ARITY(2);
7659
4.70k
    CAST_TO_STRING;
7660
4.70k
    find = xmlXPathValuePop(ctxt);
7661
4.70k
    CAST_TO_STRING;
7662
4.70k
    str = xmlXPathValuePop(ctxt);
7663
4.70k
    if (ctxt->error != 0)
7664
3
        goto error;
7665
7666
1.56k
    point = xmlStrstr(str->stringval, find->stringval);
7667
1.56k
    if (point == NULL) {
7668
396
        result = xmlStrdup(BAD_CAST "");
7669
1.17k
    } else {
7670
1.17k
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7671
1.17k
    }
7672
1.56k
    if (result == NULL) {
7673
5
        xmlXPathPErrMemory(ctxt);
7674
5
        goto error;
7675
5
    }
7676
1.56k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7677
7678
1.56k
error:
7679
1.56k
    xmlXPathReleaseObject(ctxt->context, str);
7680
1.56k
    xmlXPathReleaseObject(ctxt->context, find);
7681
1.56k
}
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
19.6k
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7698
19.6k
    xmlChar *source, *target;
7699
19.6k
    int blank;
7700
7701
19.6k
    if (ctxt == NULL) return;
7702
19.6k
    if (nargs == 0) {
7703
        /* Use current context node */
7704
18.9k
        source = xmlXPathCastNodeToString(ctxt->context->node);
7705
18.9k
        if (source == NULL)
7706
2
            xmlXPathPErrMemory(ctxt);
7707
18.9k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7708
18.9k
        nargs = 1;
7709
18.9k
    }
7710
7711
59.0k
    CHECK_ARITY(1);
7712
59.0k
    CAST_TO_STRING;
7713
59.0k
    CHECK_TYPE(XPATH_STRING);
7714
19.6k
    source = ctxt->value->stringval;
7715
19.6k
    if (source == NULL)
7716
3
        return;
7717
19.6k
    target = source;
7718
7719
    /* Skip leading whitespaces */
7720
19.6k
    while (IS_BLANK_CH(*source))
7721
477
        source++;
7722
7723
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7724
19.6k
    blank = 0;
7725
165k
    while (*source) {
7726
145k
        if (IS_BLANK_CH(*source)) {
7727
838
      blank = 1;
7728
145k
        } else {
7729
145k
            if (blank) {
7730
358
                *target++ = 0x20;
7731
358
                blank = 0;
7732
358
            }
7733
145k
            *target++ = *source;
7734
145k
        }
7735
145k
        source++;
7736
145k
    }
7737
19.6k
    *target = 0;
7738
19.6k
}
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
4.45k
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7763
4.45k
    xmlXPathObjectPtr str = NULL;
7764
4.45k
    xmlXPathObjectPtr from = NULL;
7765
4.45k
    xmlXPathObjectPtr to = NULL;
7766
4.45k
    xmlBufPtr target;
7767
4.45k
    int offset, max;
7768
4.45k
    int ch;
7769
4.45k
    const xmlChar *point;
7770
4.45k
    xmlChar *cptr, *content;
7771
7772
13.3k
    CHECK_ARITY(3);
7773
7774
13.3k
    CAST_TO_STRING;
7775
13.3k
    to = xmlXPathValuePop(ctxt);
7776
13.3k
    CAST_TO_STRING;
7777
13.3k
    from = xmlXPathValuePop(ctxt);
7778
13.3k
    CAST_TO_STRING;
7779
13.3k
    str = xmlXPathValuePop(ctxt);
7780
13.3k
    if (ctxt->error != 0)
7781
7
        goto error;
7782
7783
    /*
7784
     * Account for quadratic runtime
7785
     */
7786
4.44k
    if (ctxt->context->opLimit != 0) {
7787
4.44k
        unsigned long f1 = xmlStrlen(from->stringval);
7788
4.44k
        unsigned long f2 = xmlStrlen(str->stringval);
7789
7790
4.44k
        if ((f1 > 0) && (f2 > 0)) {
7791
3.31k
            unsigned long p;
7792
7793
3.31k
            f1 = f1 / 10 + 1;
7794
3.31k
            f2 = f2 / 10 + 1;
7795
3.31k
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7796
3.31k
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7797
52
                goto error;
7798
3.31k
        }
7799
4.44k
    }
7800
7801
4.39k
    target = xmlBufCreate(50);
7802
4.39k
    if (target == NULL) {
7803
2
        xmlXPathPErrMemory(ctxt);
7804
2
        goto error;
7805
2
    }
7806
7807
4.39k
    max = xmlUTF8Strlen(to->stringval);
7808
692k
    for (cptr = str->stringval; (ch=*cptr); ) {
7809
688k
        offset = xmlUTF8Strloc(from->stringval, cptr);
7810
688k
        if (offset >= 0) {
7811
372k
            if (offset < max) {
7812
279k
                point = xmlUTF8Strpos(to->stringval, offset);
7813
279k
                if (point)
7814
279k
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7815
279k
            }
7816
372k
        } else
7817
315k
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7818
7819
        /* Step to next character in input */
7820
688k
        cptr++;
7821
688k
        if ( ch & 0x80 ) {
7822
            /* if not simple ascii, verify proper format */
7823
323k
            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
968k
            while ( (ch <<= 1) & 0x80 )
7829
645k
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7830
1
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7831
1
                    break;
7832
1
                }
7833
323k
            if (ch & 0x80) /* must have had error encountered */
7834
1
                break;
7835
323k
        }
7836
688k
    }
7837
7838
4.39k
    content = xmlBufDetach(target);
7839
4.39k
    if (content == NULL)
7840
9
        xmlXPathPErrMemory(ctxt);
7841
4.38k
    else
7842
4.38k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7843
4.39k
    xmlBufFree(target);
7844
4.45k
error:
7845
4.45k
    xmlXPathReleaseObject(ctxt->context, str);
7846
4.45k
    xmlXPathReleaseObject(ctxt->context, from);
7847
4.45k
    xmlXPathReleaseObject(ctxt->context, to);
7848
4.45k
}
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
106k
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7864
106k
    xmlXPathObjectPtr cur;
7865
7866
318k
    CHECK_ARITY(1);
7867
318k
    cur = xmlXPathValuePop(ctxt);
7868
318k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7869
106k
    if (cur->type != XPATH_BOOLEAN) {
7870
103k
        int boolval = xmlXPathCastToBoolean(cur);
7871
7872
103k
        xmlXPathReleaseObject(ctxt->context, cur);
7873
103k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7874
103k
    }
7875
106k
    xmlXPathValuePush(ctxt, cur);
7876
106k
}
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
602
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7889
1.80k
    CHECK_ARITY(1);
7890
1.80k
    CAST_TO_BOOLEAN;
7891
1.80k
    CHECK_TYPE(XPATH_BOOLEAN);
7892
599
    ctxt->value->boolval = ! ctxt->value->boolval;
7893
599
}
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
776
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7904
2.32k
    CHECK_ARITY(0);
7905
2.32k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7906
2.32k
}
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
694
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7917
2.08k
    CHECK_ARITY(0);
7918
2.08k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7919
2.08k
}
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
5.38k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7943
5.38k
    xmlXPathObjectPtr val;
7944
5.38k
    xmlNodePtr cur;
7945
5.38k
    xmlChar *theLang = NULL;
7946
5.38k
    const xmlChar *lang;
7947
5.38k
    int ret = 0;
7948
5.38k
    int i;
7949
7950
16.1k
    CHECK_ARITY(1);
7951
16.1k
    CAST_TO_STRING;
7952
16.1k
    CHECK_TYPE(XPATH_STRING);
7953
5.37k
    val = xmlXPathValuePop(ctxt);
7954
5.37k
    lang = val->stringval;
7955
5.37k
    cur = ctxt->context->node;
7956
22.0k
    while (cur != NULL) {
7957
17.4k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7958
17.4k
                                &theLang) < 0)
7959
1
            xmlXPathPErrMemory(ctxt);
7960
17.4k
        if (theLang != NULL)
7961
807
            break;
7962
16.6k
        cur = cur->parent;
7963
16.6k
    }
7964
5.37k
    if ((theLang != NULL) && (lang != NULL)) {
7965
1.25k
        for (i = 0;lang[i] != 0;i++)
7966
654
            if (toupper(lang[i]) != toupper(theLang[i]))
7967
206
                goto not_equal;
7968
599
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7969
392
            ret = 1;
7970
599
    }
7971
5.37k
not_equal:
7972
5.37k
    if (theLang != NULL)
7973
807
  xmlFree((void *)theLang);
7974
7975
5.37k
    xmlXPathReleaseObject(ctxt->context, val);
7976
5.37k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7977
5.37k
}
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
1.19M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7988
1.19M
    xmlXPathObjectPtr cur;
7989
1.19M
    double res;
7990
7991
1.19M
    if (ctxt == NULL) return;
7992
1.19M
    if (nargs == 0) {
7993
1.58k
  if (ctxt->context->node == NULL) {
7994
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7995
1.58k
  } else {
7996
1.58k
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7997
1.58k
            if (content == NULL)
7998
3
                xmlXPathPErrMemory(ctxt);
7999
8000
1.58k
      res = xmlXPathStringEvalNumber(content);
8001
1.58k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8002
1.58k
      xmlFree(content);
8003
1.58k
  }
8004
1.58k
  return;
8005
1.58k
    }
8006
8007
4.79M
    CHECK_ARITY(1);
8008
4.79M
    cur = xmlXPathValuePop(ctxt);
8009
4.79M
    if (cur->type != XPATH_NUMBER) {
8010
1.19M
        double floatval;
8011
8012
1.19M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8013
1.19M
        xmlXPathReleaseObject(ctxt->context, cur);
8014
1.19M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8015
1.19M
    }
8016
4.79M
    xmlXPathValuePush(ctxt, cur);
8017
4.79M
}
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
22.6k
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
22.6k
    xmlXPathObjectPtr cur;
8031
22.6k
    int i;
8032
22.6k
    double res = 0.0;
8033
8034
67.9k
    CHECK_ARITY(1);
8035
67.9k
    if ((ctxt->value == NULL) ||
8036
22.6k
  ((ctxt->value->type != XPATH_NODESET) &&
8037
5
   (ctxt->value->type != XPATH_XSLT_TREE)))
8038
22.6k
  XP_ERROR(XPATH_INVALID_TYPE);
8039
22.6k
    cur = xmlXPathValuePop(ctxt);
8040
8041
22.6k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8042
5.81M
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8043
5.79M
      res += xmlXPathNodeToNumberInternal(ctxt,
8044
5.79M
                                                cur->nodesetval->nodeTab[i]);
8045
5.79M
  }
8046
22.2k
    }
8047
22.6k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8048
22.6k
    xmlXPathReleaseObject(ctxt->context, cur);
8049
22.6k
}
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
619
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8062
1.85k
    CHECK_ARITY(1);
8063
1.85k
    CAST_TO_NUMBER;
8064
1.85k
    CHECK_TYPE(XPATH_NUMBER);
8065
8066
616
    ctxt->value->floatval = floor(ctxt->value->floatval);
8067
616
}
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
412
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8080
1.23k
    CHECK_ARITY(1);
8081
1.23k
    CAST_TO_NUMBER;
8082
1.23k
    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
409
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8089
409
#endif
8090
409
}
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
818
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8104
818
    double f;
8105
8106
2.45k
    CHECK_ARITY(1);
8107
2.45k
    CAST_TO_NUMBER;
8108
2.45k
    CHECK_TYPE(XPATH_NUMBER);
8109
8110
815
    f = ctxt->value->floatval;
8111
8112
815
    if ((f >= -0.5) && (f < 0.5)) {
8113
        /* Handles negative zero. */
8114
196
        ctxt->value->floatval *= 0.0;
8115
196
    }
8116
619
    else {
8117
619
        double rounded = floor(f);
8118
619
        if (f - rounded >= 0.5)
8119
198
            rounded += 1.0;
8120
619
        ctxt->value->floatval = rounded;
8121
619
    }
8122
815
}
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
68.8k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8148
68.8k
    const xmlChar *end;
8149
68.8k
    xmlChar *ret;
8150
8151
68.8k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8152
8153
68.8k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8154
68.8k
    if (end == NULL) {
8155
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8156
0
    }
8157
68.8k
    if (end == ctxt->cur)
8158
3.45k
        return(NULL);
8159
8160
65.4k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8161
65.4k
    if (ret == NULL)
8162
30
        xmlXPathPErrMemory(ctxt);
8163
65.4k
    ctxt->cur = end;
8164
65.4k
    return(ret);
8165
68.8k
}
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
6.92k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8179
6.92k
    xmlChar *ret = NULL;
8180
8181
6.92k
    *prefix = NULL;
8182
6.92k
    ret = xmlXPathParseNCName(ctxt);
8183
6.92k
    if (ret && CUR == ':') {
8184
476
        *prefix = ret;
8185
476
  NEXT;
8186
476
  ret = xmlXPathParseNCName(ctxt);
8187
476
    }
8188
6.92k
    return(ret);
8189
6.92k
}
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
36.4k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8200
36.4k
    const xmlChar *end;
8201
36.4k
    xmlChar *ret;
8202
8203
36.4k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8204
8205
36.4k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8206
36.4k
    if (end == NULL) {
8207
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8208
0
    }
8209
36.4k
    if (end == ctxt->cur)
8210
19.0k
        return(NULL);
8211
8212
17.4k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8213
17.4k
    if (ret == NULL)
8214
10
        xmlXPathPErrMemory(ctxt);
8215
17.4k
    ctxt->cur = end;
8216
17.4k
    return(ret);
8217
36.4k
}
8218
8219
3.10k
#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
7.04M
xmlXPathStringEvalNumber(const xmlChar *str) {
8237
7.04M
    const xmlChar *cur = str;
8238
7.04M
    double ret;
8239
7.04M
    int ok = 0;
8240
7.04M
    int isneg = 0;
8241
7.04M
    int exponent = 0;
8242
7.04M
    int is_exponent_negative = 0;
8243
7.04M
#ifdef __GNUC__
8244
7.04M
    unsigned long tmp = 0;
8245
7.04M
    double temp;
8246
7.04M
#endif
8247
7.04M
    if (cur == NULL) return(0);
8248
7.04M
    while (IS_BLANK_CH(*cur)) cur++;
8249
7.04M
    if (*cur == '-') {
8250
7.18k
  isneg = 1;
8251
7.18k
  cur++;
8252
7.18k
    }
8253
7.04M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8254
7.01M
        return(xmlXPathNAN);
8255
7.01M
    }
8256
8257
31.9k
#ifdef __GNUC__
8258
    /*
8259
     * tmp/temp is a workaround against a gcc compiler bug
8260
     * http://veillard.com/gcc.bug
8261
     */
8262
31.9k
    ret = 0;
8263
64.6k
    while ((*cur >= '0') && (*cur <= '9')) {
8264
32.6k
  ret = ret * 10;
8265
32.6k
  tmp = (*cur - '0');
8266
32.6k
  ok = 1;
8267
32.6k
  cur++;
8268
32.6k
  temp = (double) tmp;
8269
32.6k
  ret = ret + temp;
8270
32.6k
    }
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
31.9k
    if (*cur == '.') {
8281
2.97k
  int v, frac = 0, max;
8282
2.97k
  double fraction = 0;
8283
8284
2.97k
        cur++;
8285
2.97k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8286
1.42k
      return(xmlXPathNAN);
8287
1.42k
  }
8288
2.40k
        while (*cur == '0') {
8289
859
      frac = frac + 1;
8290
859
      cur++;
8291
859
        }
8292
1.55k
        max = frac + MAX_FRAC;
8293
3.50k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8294
1.95k
      v = (*cur - '0');
8295
1.95k
      fraction = fraction * 10 + v;
8296
1.95k
      frac = frac + 1;
8297
1.95k
      cur++;
8298
1.95k
  }
8299
1.55k
  fraction /= pow(10.0, frac);
8300
1.55k
  ret = ret + fraction;
8301
1.75k
  while ((*cur >= '0') && (*cur <= '9'))
8302
201
      cur++;
8303
1.55k
    }
8304
30.5k
    if ((*cur == 'e') || (*cur == 'E')) {
8305
2.15k
      cur++;
8306
2.15k
      if (*cur == '-') {
8307
221
  is_exponent_negative = 1;
8308
221
  cur++;
8309
1.93k
      } else if (*cur == '+') {
8310
224
        cur++;
8311
224
      }
8312
5.67k
      while ((*cur >= '0') && (*cur <= '9')) {
8313
3.52k
        if (exponent < 1000000)
8314
3.26k
    exponent = exponent * 10 + (*cur - '0');
8315
3.52k
  cur++;
8316
3.52k
      }
8317
2.15k
    }
8318
30.5k
    while (IS_BLANK_CH(*cur)) cur++;
8319
30.5k
    if (*cur != 0) return(xmlXPathNAN);
8320
17.0k
    if (isneg) ret = -ret;
8321
17.0k
    if (is_exponent_negative) exponent = -exponent;
8322
17.0k
    ret *= pow(10.0, (double)exponent);
8323
17.0k
    return(ret);
8324
30.5k
}
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
11.5k
{
8338
11.5k
    double ret = 0.0;
8339
11.5k
    int ok = 0;
8340
11.5k
    int exponent = 0;
8341
11.5k
    int is_exponent_negative = 0;
8342
11.5k
    xmlXPathObjectPtr num;
8343
11.5k
#ifdef __GNUC__
8344
11.5k
    unsigned long tmp = 0;
8345
11.5k
    double temp;
8346
11.5k
#endif
8347
8348
11.5k
    CHECK_ERROR;
8349
11.5k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8350
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8351
0
    }
8352
11.5k
#ifdef __GNUC__
8353
    /*
8354
     * tmp/temp is a workaround against a gcc compiler bug
8355
     * http://veillard.com/gcc.bug
8356
     */
8357
11.5k
    ret = 0;
8358
28.5k
    while ((CUR >= '0') && (CUR <= '9')) {
8359
16.9k
  ret = ret * 10;
8360
16.9k
  tmp = (CUR - '0');
8361
16.9k
        ok = 1;
8362
16.9k
        NEXT;
8363
16.9k
  temp = (double) tmp;
8364
16.9k
  ret = ret + temp;
8365
16.9k
    }
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
11.5k
    if (CUR == '.') {
8375
1.55k
  int v, frac = 0, max;
8376
1.55k
  double fraction = 0;
8377
8378
1.55k
        NEXT;
8379
1.55k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8380
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8381
0
        }
8382
2.18k
        while (CUR == '0') {
8383
629
            frac = frac + 1;
8384
629
            NEXT;
8385
629
        }
8386
1.55k
        max = frac + MAX_FRAC;
8387
2.56k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8388
1.00k
      v = (CUR - '0');
8389
1.00k
      fraction = fraction * 10 + v;
8390
1.00k
      frac = frac + 1;
8391
1.00k
            NEXT;
8392
1.00k
        }
8393
1.55k
        fraction /= pow(10.0, frac);
8394
1.55k
        ret = ret + fraction;
8395
1.75k
        while ((CUR >= '0') && (CUR <= '9'))
8396
194
            NEXT;
8397
1.55k
    }
8398
11.5k
    if ((CUR == 'e') || (CUR == 'E')) {
8399
1.50k
        NEXT;
8400
1.50k
        if (CUR == '-') {
8401
346
            is_exponent_negative = 1;
8402
346
            NEXT;
8403
1.15k
        } else if (CUR == '+') {
8404
196
      NEXT;
8405
196
  }
8406
4.27k
        while ((CUR >= '0') && (CUR <= '9')) {
8407
2.77k
            if (exponent < 1000000)
8408
2.37k
                exponent = exponent * 10 + (CUR - '0');
8409
2.77k
            NEXT;
8410
2.77k
        }
8411
1.50k
        if (is_exponent_negative)
8412
346
            exponent = -exponent;
8413
1.50k
        ret *= pow(10.0, (double) exponent);
8414
1.50k
    }
8415
11.5k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8416
11.5k
    if (num == NULL) {
8417
3
  ctxt->error = XPATH_MEMORY_ERROR;
8418
11.5k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8419
11.5k
                              NULL) == -1) {
8420
1
        xmlXPathReleaseObject(ctxt->context, num);
8421
1
    }
8422
11.5k
}
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
2.45k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8435
2.45k
    const xmlChar *q;
8436
2.45k
    xmlChar *ret = NULL;
8437
2.45k
    int quote;
8438
8439
2.45k
    if (CUR == '"') {
8440
1.01k
        quote = '"';
8441
1.44k
    } else if (CUR == '\'') {
8442
1.43k
        quote = '\'';
8443
1.43k
    } else {
8444
10
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8445
0
    }
8446
8447
2.44k
    NEXT;
8448
2.44k
    q = CUR_PTR;
8449
9.01k
    while (CUR != quote) {
8450
6.66k
        int ch;
8451
6.66k
        int len = 4;
8452
8453
6.66k
        if (CUR == 0)
8454
6.58k
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8455
6.58k
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8456
6.58k
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8457
6.57k
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8458
6.57k
        CUR_PTR += len;
8459
6.57k
    }
8460
2.34k
    ret = xmlStrndup(q, CUR_PTR - q);
8461
2.34k
    if (ret == NULL)
8462
2
        xmlXPathPErrMemory(ctxt);
8463
2.34k
    NEXT;
8464
2.34k
    return(ret);
8465
2.44k
}
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
2.28k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8479
2.28k
    xmlChar *ret = NULL;
8480
2.28k
    xmlXPathObjectPtr lit;
8481
8482
2.28k
    ret = xmlXPathParseLiteral(ctxt);
8483
2.28k
    if (ret == NULL)
8484
96
        return;
8485
2.19k
    lit = xmlXPathCacheNewString(ctxt, ret);
8486
2.19k
    if (lit == NULL) {
8487
1
        ctxt->error = XPATH_MEMORY_ERROR;
8488
2.19k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8489
2.19k
                              NULL) == -1) {
8490
1
        xmlXPathReleaseObject(ctxt->context, lit);
8491
1
    }
8492
2.19k
    xmlFree(ret);
8493
2.19k
}
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
722
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8512
722
    xmlChar *name;
8513
722
    xmlChar *prefix;
8514
8515
722
    SKIP_BLANKS;
8516
722
    if (CUR != '$') {
8517
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8518
0
    }
8519
722
    NEXT;
8520
722
    name = xmlXPathParseQName(ctxt, &prefix);
8521
722
    if (name == NULL) {
8522
212
        xmlFree(prefix);
8523
212
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8524
0
    }
8525
510
    ctxt->comp->last = -1;
8526
510
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8527
1
        xmlFree(prefix);
8528
1
        xmlFree(name);
8529
1
    }
8530
510
    SKIP_BLANKS;
8531
510
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8532
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8533
0
    }
8534
510
}
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
7.14k
xmlXPathIsNodeType(const xmlChar *name) {
8549
7.14k
    if (name == NULL)
8550
0
  return(0);
8551
8552
7.14k
    if (xmlStrEqual(name, BAD_CAST "node"))
8553
270
  return(1);
8554
6.87k
    if (xmlStrEqual(name, BAD_CAST "text"))
8555
244
  return(1);
8556
6.63k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8557
197
  return(1);
8558
6.43k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8559
232
  return(1);
8560
6.20k
    return(0);
8561
6.43k
}
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
6.20k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8574
6.20k
    xmlChar *name;
8575
6.20k
    xmlChar *prefix;
8576
6.20k
    int nbargs = 0;
8577
6.20k
    int sort = 1;
8578
8579
6.20k
    name = xmlXPathParseQName(ctxt, &prefix);
8580
6.20k
    if (name == NULL) {
8581
1
  xmlFree(prefix);
8582
1
  XP_ERROR(XPATH_EXPR_ERROR);
8583
0
    }
8584
6.20k
    SKIP_BLANKS;
8585
8586
6.20k
    if (CUR != '(') {
8587
1
  xmlFree(name);
8588
1
  xmlFree(prefix);
8589
1
  XP_ERROR(XPATH_EXPR_ERROR);
8590
0
    }
8591
6.19k
    NEXT;
8592
6.19k
    SKIP_BLANKS;
8593
8594
    /*
8595
    * Optimization for count(): we don't need the node-set to be sorted.
8596
    */
8597
6.19k
    if ((prefix == NULL) && (name[0] == 'c') &&
8598
819
  xmlStrEqual(name, BAD_CAST "count"))
8599
270
    {
8600
270
  sort = 0;
8601
270
    }
8602
6.19k
    ctxt->comp->last = -1;
8603
6.19k
    if (CUR != ')') {
8604
23.5k
  while (CUR != 0) {
8605
23.5k
      int op1 = ctxt->comp->last;
8606
23.5k
      ctxt->comp->last = -1;
8607
23.5k
      xmlXPathCompileExpr(ctxt, sort);
8608
23.5k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8609
156
    xmlFree(name);
8610
156
    xmlFree(prefix);
8611
156
    return;
8612
156
      }
8613
23.3k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8614
23.3k
      nbargs++;
8615
23.3k
      if (CUR == ')') break;
8616
20.0k
      if (CUR != ',') {
8617
8
    xmlFree(name);
8618
8
    xmlFree(prefix);
8619
8
    XP_ERROR(XPATH_EXPR_ERROR);
8620
0
      }
8621
20.0k
      NEXT;
8622
20.0k
      SKIP_BLANKS;
8623
20.0k
  }
8624
3.51k
    }
8625
6.03k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8626
1
        xmlFree(prefix);
8627
1
        xmlFree(name);
8628
1
    }
8629
6.03k
    NEXT;
8630
6.03k
    SKIP_BLANKS;
8631
6.03k
}
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
23.9k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8646
23.9k
    SKIP_BLANKS;
8647
23.9k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8648
23.2k
    else if (CUR == '(') {
8649
3.13k
  NEXT;
8650
3.13k
  SKIP_BLANKS;
8651
3.13k
  xmlXPathCompileExpr(ctxt, 1);
8652
3.13k
  CHECK_ERROR;
8653
2.98k
  if (CUR != ')') {
8654
4
      XP_ERROR(XPATH_EXPR_ERROR);
8655
0
  }
8656
2.98k
  NEXT;
8657
2.98k
  SKIP_BLANKS;
8658
20.0k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8659
11.5k
  xmlXPathCompNumber(ctxt);
8660
11.5k
    } else if ((CUR == '\'') || (CUR == '"')) {
8661
2.28k
  xmlXPathCompLiteral(ctxt);
8662
6.20k
    } else {
8663
6.20k
  xmlXPathCompFunctionCall(ctxt);
8664
6.20k
    }
8665
23.7k
    SKIP_BLANKS;
8666
23.7k
}
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
23.9k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8684
23.9k
    xmlXPathCompPrimaryExpr(ctxt);
8685
23.9k
    CHECK_ERROR;
8686
23.2k
    SKIP_BLANKS;
8687
8688
26.2k
    while (CUR == '[') {
8689
2.99k
  xmlXPathCompPredicate(ctxt, 1);
8690
2.99k
  SKIP_BLANKS;
8691
2.99k
    }
8692
8693
8694
23.2k
}
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
49.2k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8706
49.2k
    const xmlChar *end;
8707
49.2k
    xmlChar *ret;
8708
8709
49.2k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8710
49.2k
    if (end == NULL) {
8711
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8712
0
    }
8713
49.2k
    if (end == ctxt->cur)
8714
6.43k
        return(NULL);
8715
8716
42.8k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8717
42.8k
    if (ret == NULL)
8718
1
        xmlXPathPErrMemory(ctxt);
8719
42.8k
    return(ret);
8720
49.2k
}
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
123k
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8735
123k
    int lc = 1;           /* Should we branch to LocationPath ?         */
8736
123k
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8737
8738
123k
    SKIP_BLANKS;
8739
123k
    if ((CUR == '$') || (CUR == '(') ||
8740
120k
  (IS_ASCII_DIGIT(CUR)) ||
8741
109k
        (CUR == '\'') || (CUR == '"') ||
8742
106k
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8743
17.7k
  lc = 0;
8744
106k
    } else if (CUR == '*') {
8745
  /* relative or absolute location path */
8746
12.5k
  lc = 1;
8747
93.6k
    } else if (CUR == '/') {
8748
  /* relative or absolute location path */
8749
30.7k
  lc = 1;
8750
62.9k
    } else if (CUR == '@') {
8751
  /* relative abbreviated attribute location path */
8752
863
  lc = 1;
8753
62.0k
    } else if (CUR == '.') {
8754
  /* relative abbreviated attribute location path */
8755
12.8k
  lc = 1;
8756
49.2k
    } 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
49.2k
  SKIP_BLANKS;
8769
49.2k
  name = xmlXPathScanName(ctxt);
8770
49.2k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8771
1.22k
      lc = 1;
8772
1.22k
      xmlFree(name);
8773
48.0k
  } else if (name != NULL) {
8774
41.5k
      int len =xmlStrlen(name);
8775
8776
8777
47.4k
      while (NXT(len) != 0) {
8778
45.9k
    if (NXT(len) == '/') {
8779
        /* element name */
8780
2.38k
        lc = 1;
8781
2.38k
        break;
8782
43.5k
    } else if (IS_BLANK_CH(NXT(len))) {
8783
        /* ignore blanks */
8784
5.84k
        ;
8785
37.6k
    } else if (NXT(len) == ':') {
8786
66
        lc = 1;
8787
66
        break;
8788
37.6k
    } else if ((NXT(len) == '(')) {
8789
        /* Node Type or Function */
8790
7.14k
        if (xmlXPathIsNodeType(name)) {
8791
943
      lc = 1;
8792
6.20k
        } else {
8793
6.20k
      lc = 0;
8794
6.20k
        }
8795
7.14k
                    break;
8796
30.4k
    } else if ((NXT(len) == '[')) {
8797
        /* element name */
8798
563
        lc = 1;
8799
563
        break;
8800
29.9k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8801
28.0k
         (NXT(len) == '=')) {
8802
3.39k
        lc = 1;
8803
3.39k
        break;
8804
26.5k
    } else {
8805
26.5k
        lc = 1;
8806
26.5k
        break;
8807
26.5k
    }
8808
5.84k
    len++;
8809
5.84k
      }
8810
41.5k
      if (NXT(len) == 0) {
8811
    /* element name */
8812
1.50k
    lc = 1;
8813
1.50k
      }
8814
41.5k
      xmlFree(name);
8815
41.5k
  } else {
8816
      /* make sure all cases are covered explicitly */
8817
6.43k
      XP_ERROR(XPATH_EXPR_ERROR);
8818
0
  }
8819
49.2k
    }
8820
8821
117k
    if (lc) {
8822
93.6k
  if (CUR == '/') {
8823
30.7k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8824
62.8k
  } else {
8825
62.8k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8826
62.8k
  }
8827
93.6k
  xmlXPathCompLocationPath(ctxt);
8828
93.6k
    } else {
8829
23.9k
  xmlXPathCompFilterExpr(ctxt);
8830
23.9k
  CHECK_ERROR;
8831
23.0k
  if ((CUR == '/') && (NXT(1) == '/')) {
8832
517
      SKIP(2);
8833
517
      SKIP_BLANKS;
8834
8835
517
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8836
517
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8837
8838
517
      xmlXPathCompRelativeLocationPath(ctxt);
8839
22.4k
  } else if (CUR == '/') {
8840
750
      xmlXPathCompRelativeLocationPath(ctxt);
8841
750
  }
8842
23.0k
    }
8843
116k
    SKIP_BLANKS;
8844
116k
}
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
90.0k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8857
90.0k
    xmlXPathCompPathExpr(ctxt);
8858
90.0k
    CHECK_ERROR;
8859
85.7k
    SKIP_BLANKS;
8860
119k
    while (CUR == '|') {
8861
33.9k
  int op1 = ctxt->comp->last;
8862
33.9k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8863
8864
33.9k
  NEXT;
8865
33.9k
  SKIP_BLANKS;
8866
33.9k
  xmlXPathCompPathExpr(ctxt);
8867
8868
33.9k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8869
8870
33.9k
  SKIP_BLANKS;
8871
33.9k
    }
8872
85.7k
}
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
90.0k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8885
90.0k
    int minus = 0;
8886
90.0k
    int found = 0;
8887
8888
90.0k
    SKIP_BLANKS;
8889
93.8k
    while (CUR == '-') {
8890
3.79k
        minus = 1 - minus;
8891
3.79k
  found = 1;
8892
3.79k
  NEXT;
8893
3.79k
  SKIP_BLANKS;
8894
3.79k
    }
8895
8896
90.0k
    xmlXPathCompUnionExpr(ctxt);
8897
90.0k
    CHECK_ERROR;
8898
85.5k
    if (found) {
8899
3.03k
  if (minus)
8900
2.67k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8901
360
  else
8902
360
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8903
3.03k
    }
8904
85.5k
}
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
76.8k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8920
76.8k
    xmlXPathCompUnaryExpr(ctxt);
8921
76.8k
    CHECK_ERROR;
8922
72.5k
    SKIP_BLANKS;
8923
85.5k
    while ((CUR == '*') ||
8924
72.9k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8925
72.5k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8926
13.1k
  int op = -1;
8927
13.1k
  int op1 = ctxt->comp->last;
8928
8929
13.1k
        if (CUR == '*') {
8930
12.5k
      op = 0;
8931
12.5k
      NEXT;
8932
12.5k
  } else if (CUR == 'd') {
8933
454
      op = 1;
8934
454
      SKIP(3);
8935
454
  } else if (CUR == 'm') {
8936
95
      op = 2;
8937
95
      SKIP(3);
8938
95
  }
8939
13.1k
  SKIP_BLANKS;
8940
13.1k
        xmlXPathCompUnaryExpr(ctxt);
8941
13.1k
  CHECK_ERROR;
8942
13.0k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8943
13.0k
  SKIP_BLANKS;
8944
13.0k
    }
8945
72.5k
}
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
68.9k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8959
8960
68.9k
    xmlXPathCompMultiplicativeExpr(ctxt);
8961
68.9k
    CHECK_ERROR;
8962
64.7k
    SKIP_BLANKS;
8963
72.4k
    while ((CUR == '+') || (CUR == '-')) {
8964
7.91k
  int plus;
8965
7.91k
  int op1 = ctxt->comp->last;
8966
8967
7.91k
        if (CUR == '+') plus = 1;
8968
5.39k
  else plus = 0;
8969
7.91k
  NEXT;
8970
7.91k
  SKIP_BLANKS;
8971
7.91k
        xmlXPathCompMultiplicativeExpr(ctxt);
8972
7.91k
  CHECK_ERROR;
8973
7.67k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8974
7.67k
  SKIP_BLANKS;
8975
7.67k
    }
8976
64.7k
}
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
64.7k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8997
64.7k
    xmlXPathCompAdditiveExpr(ctxt);
8998
64.7k
    CHECK_ERROR;
8999
60.3k
    SKIP_BLANKS;
9000
64.5k
    while ((CUR == '<') || (CUR == '>')) {
9001
4.25k
  int inf, strict;
9002
4.25k
  int op1 = ctxt->comp->last;
9003
9004
4.25k
        if (CUR == '<') inf = 1;
9005
2.14k
  else inf = 0;
9006
4.25k
  if (NXT(1) == '=') strict = 0;
9007
3.78k
  else strict = 1;
9008
4.25k
  NEXT;
9009
4.25k
  if (!strict) NEXT;
9010
4.25k
  SKIP_BLANKS;
9011
4.25k
        xmlXPathCompAdditiveExpr(ctxt);
9012
4.25k
  CHECK_ERROR;
9013
4.11k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9014
4.11k
  SKIP_BLANKS;
9015
4.11k
    }
9016
60.3k
}
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
57.8k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9034
57.8k
    xmlXPathCompRelationalExpr(ctxt);
9035
57.8k
    CHECK_ERROR;
9036
53.6k
    SKIP_BLANKS;
9037
60.2k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9038
6.83k
  int eq;
9039
6.83k
  int op1 = ctxt->comp->last;
9040
9041
6.83k
        if (CUR == '=') eq = 1;
9042
816
  else eq = 0;
9043
6.83k
  NEXT;
9044
6.83k
  if (!eq) NEXT;
9045
6.83k
  SKIP_BLANKS;
9046
6.83k
        xmlXPathCompRelationalExpr(ctxt);
9047
6.83k
  CHECK_ERROR;
9048
6.62k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9049
6.62k
  SKIP_BLANKS;
9050
6.62k
    }
9051
53.6k
}
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
57.2k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9063
57.2k
    xmlXPathCompEqualityExpr(ctxt);
9064
57.2k
    CHECK_ERROR;
9065
52.8k
    SKIP_BLANKS;
9066
53.4k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9067
674
  int op1 = ctxt->comp->last;
9068
674
        SKIP(3);
9069
674
  SKIP_BLANKS;
9070
674
        xmlXPathCompEqualityExpr(ctxt);
9071
674
  CHECK_ERROR;
9072
588
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9073
588
  SKIP_BLANKS;
9074
588
    }
9075
52.8k
}
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
56.4k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9089
56.4k
    xmlXPathContextPtr xpctxt = ctxt->context;
9090
9091
56.4k
    if (xpctxt != NULL) {
9092
56.4k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9093
55.9k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9094
        /*
9095
         * Parsing a single '(' pushes about 10 functions on the call stack
9096
         * before recursing!
9097
         */
9098
55.9k
        xpctxt->depth += 10;
9099
55.9k
    }
9100
9101
55.9k
    xmlXPathCompAndExpr(ctxt);
9102
55.9k
    CHECK_ERROR;
9103
51.6k
    SKIP_BLANKS;
9104
52.7k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9105
1.26k
  int op1 = ctxt->comp->last;
9106
1.26k
        SKIP(2);
9107
1.26k
  SKIP_BLANKS;
9108
1.26k
        xmlXPathCompAndExpr(ctxt);
9109
1.26k
  CHECK_ERROR;
9110
1.12k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9111
1.12k
  SKIP_BLANKS;
9112
1.12k
    }
9113
51.4k
    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
36.8k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9121
36.8k
    }
9122
9123
51.4k
    if (xpctxt != NULL)
9124
51.4k
        xpctxt->depth -= 10;
9125
51.4k
}
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
16.8k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9138
16.8k
    int op1 = ctxt->comp->last;
9139
9140
16.8k
    SKIP_BLANKS;
9141
16.8k
    if (CUR != '[') {
9142
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9143
0
    }
9144
16.8k
    NEXT;
9145
16.8k
    SKIP_BLANKS;
9146
9147
16.8k
    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
16.8k
    if (! filter)
9158
13.8k
  xmlXPathCompileExpr(ctxt, 0);
9159
2.99k
    else
9160
2.99k
  xmlXPathCompileExpr(ctxt, 1);
9161
16.8k
    CHECK_ERROR;
9162
9163
13.2k
    if (CUR != ']') {
9164
81
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9165
0
    }
9166
9167
13.1k
    if (filter)
9168
2.33k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9169
10.8k
    else
9170
10.8k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9171
9172
13.1k
    NEXT;
9173
13.1k
    SKIP_BLANKS;
9174
13.1k
}
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
75.9k
         xmlChar *name) {
9202
75.9k
    int blanks;
9203
9204
75.9k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9205
0
  return(NULL);
9206
0
    }
9207
75.9k
    *type = (xmlXPathTypeVal) 0;
9208
75.9k
    *test = (xmlXPathTestVal) 0;
9209
75.9k
    *prefix = NULL;
9210
75.9k
    SKIP_BLANKS;
9211
9212
75.9k
    if ((name == NULL) && (CUR == '*')) {
9213
  /*
9214
   * All elements
9215
   */
9216
23.6k
  NEXT;
9217
23.6k
  *test = NODE_TEST_ALL;
9218
23.6k
  return(NULL);
9219
23.6k
    }
9220
9221
52.2k
    if (name == NULL)
9222
3.73k
  name = xmlXPathParseNCName(ctxt);
9223
52.2k
    if (name == NULL) {
9224
296
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9225
0
    }
9226
9227
51.9k
    blanks = IS_BLANK_CH(CUR);
9228
51.9k
    SKIP_BLANKS;
9229
51.9k
    if (CUR == '(') {
9230
2.59k
  NEXT;
9231
  /*
9232
   * NodeType or PI search
9233
   */
9234
2.59k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9235
537
      *type = NODE_TYPE_COMMENT;
9236
2.05k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9237
1.00k
      *type = NODE_TYPE_NODE;
9238
1.04k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9239
394
      *type = NODE_TYPE_PI;
9240
652
  else if (xmlStrEqual(name, BAD_CAST "text"))
9241
641
      *type = NODE_TYPE_TEXT;
9242
11
  else {
9243
11
      if (name != NULL)
9244
11
    xmlFree(name);
9245
11
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9246
0
  }
9247
9248
2.58k
  *test = NODE_TEST_TYPE;
9249
9250
2.58k
  SKIP_BLANKS;
9251
2.58k
  if (*type == NODE_TYPE_PI) {
9252
      /*
9253
       * Specific case: search a PI by name.
9254
       */
9255
394
      if (name != NULL)
9256
394
    xmlFree(name);
9257
394
      name = NULL;
9258
394
      if (CUR != ')') {
9259
165
    name = xmlXPathParseLiteral(ctxt);
9260
165
    *test = NODE_TEST_PI;
9261
165
    SKIP_BLANKS;
9262
165
      }
9263
394
  }
9264
2.58k
  if (CUR != ')') {
9265
20
      if (name != NULL)
9266
9
    xmlFree(name);
9267
20
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9268
0
  }
9269
2.56k
  NEXT;
9270
2.56k
  return(name);
9271
2.58k
    }
9272
49.3k
    *test = NODE_TEST_NAME;
9273
49.3k
    if ((!blanks) && (CUR == ':')) {
9274
1.93k
  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
1.93k
  *prefix = name;
9284
9285
1.93k
  if (CUR == '*') {
9286
      /*
9287
       * All elements
9288
       */
9289
464
      NEXT;
9290
464
      *test = NODE_TEST_ALL;
9291
464
      return(NULL);
9292
464
  }
9293
9294
1.47k
  name = xmlXPathParseNCName(ctxt);
9295
1.47k
  if (name == NULL) {
9296
40
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9297
0
  }
9298
1.47k
    }
9299
48.8k
    return(name);
9300
49.3k
}
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
52.8k
xmlXPathIsAxisName(const xmlChar *name) {
9322
52.8k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9323
52.8k
    switch (name[0]) {
9324
2.03k
  case 'a':
9325
2.03k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9326
819
    ret = AXIS_ANCESTOR;
9327
2.03k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9328
189
    ret = AXIS_ANCESTOR_OR_SELF;
9329
2.03k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9330
293
    ret = AXIS_ATTRIBUTE;
9331
2.03k
      break;
9332
2.28k
  case 'c':
9333
2.28k
      if (xmlStrEqual(name, BAD_CAST "child"))
9334
261
    ret = AXIS_CHILD;
9335
2.28k
      break;
9336
1.90k
  case 'd':
9337
1.90k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9338
205
    ret = AXIS_DESCENDANT;
9339
1.90k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9340
420
    ret = AXIS_DESCENDANT_OR_SELF;
9341
1.90k
      break;
9342
1.03k
  case 'f':
9343
1.03k
      if (xmlStrEqual(name, BAD_CAST "following"))
9344
332
    ret = AXIS_FOLLOWING;
9345
1.03k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9346
108
    ret = AXIS_FOLLOWING_SIBLING;
9347
1.03k
      break;
9348
4.12k
  case 'n':
9349
4.12k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9350
1.02k
    ret = AXIS_NAMESPACE;
9351
4.12k
      break;
9352
17.4k
  case 'p':
9353
17.4k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9354
215
    ret = AXIS_PARENT;
9355
17.4k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9356
457
    ret = AXIS_PRECEDING;
9357
17.4k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9358
265
    ret = AXIS_PRECEDING_SIBLING;
9359
17.4k
      break;
9360
4.10k
  case 's':
9361
4.10k
      if (xmlStrEqual(name, BAD_CAST "self"))
9362
870
    ret = AXIS_SELF;
9363
4.10k
      break;
9364
52.8k
    }
9365
52.8k
    return(ret);
9366
52.8k
}
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
95.1k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9391
95.1k
    SKIP_BLANKS;
9392
95.1k
    if ((CUR == '.') && (NXT(1) == '.')) {
9393
1.64k
  SKIP(2);
9394
1.64k
  SKIP_BLANKS;
9395
1.64k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9396
1.64k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9397
93.4k
    } else if (CUR == '.') {
9398
15.8k
  NEXT;
9399
15.8k
  SKIP_BLANKS;
9400
77.6k
    } else {
9401
77.6k
  xmlChar *name = NULL;
9402
77.6k
  xmlChar *prefix = NULL;
9403
77.6k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9404
77.6k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9405
77.6k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9406
77.6k
  int op1;
9407
9408
77.6k
  if (CUR == '*') {
9409
21.8k
      axis = AXIS_CHILD;
9410
55.7k
  } else {
9411
55.7k
      if (name == NULL)
9412
55.7k
    name = xmlXPathParseNCName(ctxt);
9413
55.7k
      if (name != NULL) {
9414
52.8k
    axis = xmlXPathIsAxisName(name);
9415
52.8k
    if (axis != 0) {
9416
5.46k
        SKIP_BLANKS;
9417
5.46k
        if ((CUR == ':') && (NXT(1) == ':')) {
9418
3.61k
      SKIP(2);
9419
3.61k
      xmlFree(name);
9420
3.61k
      name = NULL;
9421
3.61k
        } else {
9422
      /* an element name can conflict with an axis one :-\ */
9423
1.84k
      axis = AXIS_CHILD;
9424
1.84k
        }
9425
47.3k
    } else {
9426
47.3k
        axis = AXIS_CHILD;
9427
47.3k
    }
9428
52.8k
      } else if (CUR == '@') {
9429
1.96k
    NEXT;
9430
1.96k
    axis = AXIS_ATTRIBUTE;
9431
1.96k
      } else {
9432
975
    axis = AXIS_CHILD;
9433
975
      }
9434
55.7k
  }
9435
9436
77.6k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9437
1.67k
            xmlFree(name);
9438
1.67k
            return;
9439
1.67k
        }
9440
9441
75.9k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9442
75.9k
  if (test == 0)
9443
307
      return;
9444
9445
75.6k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9446
1.93k
      (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
75.6k
  op1 = ctxt->comp->last;
9454
75.6k
  ctxt->comp->last = -1;
9455
9456
75.6k
  SKIP_BLANKS;
9457
89.4k
  while (CUR == '[') {
9458
13.8k
      xmlXPathCompPredicate(ctxt, 0);
9459
13.8k
  }
9460
9461
75.6k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9462
75.6k
                           test, type, (void *)prefix, (void *)name) == -1) {
9463
3
            xmlFree(prefix);
9464
3
            xmlFree(name);
9465
3
        }
9466
75.6k
    }
9467
95.1k
}
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
83.3k
(xmlXPathParserContextPtr ctxt) {
9482
83.3k
    SKIP_BLANKS;
9483
83.3k
    if ((CUR == '/') && (NXT(1) == '/')) {
9484
338
  SKIP(2);
9485
338
  SKIP_BLANKS;
9486
338
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9487
338
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9488
82.9k
    } else if (CUR == '/') {
9489
1.07k
      NEXT;
9490
1.07k
  SKIP_BLANKS;
9491
1.07k
    }
9492
83.3k
    xmlXPathCompStep(ctxt);
9493
83.3k
    CHECK_ERROR;
9494
80.5k
    SKIP_BLANKS;
9495
92.3k
    while (CUR == '/') {
9496
11.7k
  if ((CUR == '/') && (NXT(1) == '/')) {
9497
3.26k
      SKIP(2);
9498
3.26k
      SKIP_BLANKS;
9499
3.26k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9500
3.26k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9501
3.26k
      xmlXPathCompStep(ctxt);
9502
8.51k
  } else if (CUR == '/') {
9503
8.51k
      NEXT;
9504
8.51k
      SKIP_BLANKS;
9505
8.51k
      xmlXPathCompStep(ctxt);
9506
8.51k
  }
9507
11.7k
  SKIP_BLANKS;
9508
11.7k
    }
9509
80.5k
}
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
93.6k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9525
93.6k
    SKIP_BLANKS;
9526
93.6k
    if (CUR != '/') {
9527
62.8k
        xmlXPathCompRelativeLocationPath(ctxt);
9528
62.8k
    } else {
9529
60.4k
  while (CUR == '/') {
9530
30.8k
      if ((CUR == '/') && (NXT(1) == '/')) {
9531
15.3k
    SKIP(2);
9532
15.3k
    SKIP_BLANKS;
9533
15.3k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9534
15.3k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9535
15.3k
    xmlXPathCompRelativeLocationPath(ctxt);
9536
15.4k
      } else if (CUR == '/') {
9537
15.4k
    NEXT;
9538
15.4k
    SKIP_BLANKS;
9539
15.4k
    if ((CUR != 0) &&
9540
15.3k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9541
13.7k
                     (CUR == '_') || (CUR == '.') ||
9542
12.6k
         (CUR == '@') || (CUR == '*')))
9543
3.88k
        xmlXPathCompRelativeLocationPath(ctxt);
9544
15.4k
      }
9545
30.8k
      CHECK_ERROR;
9546
30.8k
  }
9547
30.7k
    }
9548
93.6k
}
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
345k
{
9578
345k
    xmlXPathContextPtr xpctxt;
9579
345k
    xmlNodePtr oldnode;
9580
345k
    xmlDocPtr olddoc;
9581
345k
    xmlXPathStepOpPtr filterOp;
9582
345k
    int oldcs, oldpp;
9583
345k
    int i, j, pos;
9584
9585
345k
    if ((set == NULL) || (set->nodeNr == 0))
9586
21.3k
        return;
9587
9588
    /*
9589
    * Check if the node set contains a sufficient number of nodes for
9590
    * the requested range.
9591
    */
9592
323k
    if (set->nodeNr < minPos) {
9593
1.17k
        xmlXPathNodeSetClear(set, hasNsNodes);
9594
1.17k
        return;
9595
1.17k
    }
9596
9597
322k
    xpctxt = ctxt->context;
9598
322k
    oldnode = xpctxt->node;
9599
322k
    olddoc = xpctxt->doc;
9600
322k
    oldcs = xpctxt->contextSize;
9601
322k
    oldpp = xpctxt->proximityPosition;
9602
322k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9603
9604
322k
    xpctxt->contextSize = set->nodeNr;
9605
9606
1.75M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9607
1.44M
        xmlNodePtr node = set->nodeTab[i];
9608
1.44M
        int res;
9609
9610
1.44M
        xpctxt->node = node;
9611
1.44M
        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
1.44M
        if ((node->type != XML_NAMESPACE_DECL) &&
9620
1.23M
            (node->doc != NULL))
9621
1.23M
            xpctxt->doc = node->doc;
9622
9623
1.44M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9624
9625
1.44M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9626
1.05k
            break;
9627
1.44M
        if (res < 0) {
9628
            /* Shouldn't happen */
9629
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9630
0
            break;
9631
0
        }
9632
9633
1.44M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9634
175k
            if (i != j) {
9635
16.4k
                set->nodeTab[j] = node;
9636
16.4k
                set->nodeTab[i] = NULL;
9637
16.4k
            }
9638
9639
175k
            j += 1;
9640
1.26M
        } else {
9641
            /* Remove the entry from the initial node set. */
9642
1.26M
            set->nodeTab[i] = NULL;
9643
1.26M
            if (node->type == XML_NAMESPACE_DECL)
9644
82.8k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9645
1.26M
        }
9646
9647
1.44M
        if (res != 0) {
9648
386k
            if (pos == maxPos) {
9649
11.9k
                i += 1;
9650
11.9k
                break;
9651
11.9k
            }
9652
9653
374k
            pos += 1;
9654
374k
        }
9655
1.44M
    }
9656
9657
    /* Free remaining nodes. */
9658
322k
    if (hasNsNodes) {
9659
40.8k
        for (; i < set->nodeNr; i++) {
9660
5.33k
            xmlNodePtr node = set->nodeTab[i];
9661
5.33k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9662
568
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9663
5.33k
        }
9664
35.5k
    }
9665
9666
322k
    set->nodeNr = j;
9667
9668
    /* If too many elements were removed, shrink table to preserve memory. */
9669
322k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9670
30.9k
        (set->nodeNr < set->nodeMax / 2)) {
9671
29.8k
        xmlNodePtr *tmp;
9672
29.8k
        int nodeMax = set->nodeNr;
9673
9674
29.8k
        if (nodeMax < XML_NODESET_DEFAULT)
9675
29.4k
            nodeMax = XML_NODESET_DEFAULT;
9676
29.8k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9677
29.8k
                nodeMax * sizeof(xmlNodePtr));
9678
29.8k
        if (tmp == NULL) {
9679
1
            xmlXPathPErrMemory(ctxt);
9680
29.8k
        } else {
9681
29.8k
            set->nodeTab = tmp;
9682
29.8k
            set->nodeMax = nodeMax;
9683
29.8k
        }
9684
29.8k
    }
9685
9686
322k
    xpctxt->node = oldnode;
9687
322k
    xpctxt->doc = olddoc;
9688
322k
    xpctxt->contextSize = oldcs;
9689
322k
    xpctxt->proximityPosition = oldpp;
9690
322k
}
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
293k
{
9711
293k
    if (op->ch1 != -1) {
9712
911
  xmlXPathCompExprPtr comp = ctxt->comp;
9713
  /*
9714
  * Process inner predicates first.
9715
  */
9716
911
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9717
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9718
0
  }
9719
911
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9720
911
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9721
911
        ctxt->context->depth += 1;
9722
911
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9723
911
                                    1, set->nodeNr, hasNsNodes);
9724
911
        ctxt->context->depth -= 1;
9725
911
  CHECK_ERROR;
9726
911
    }
9727
9728
293k
    if (op->ch2 != -1)
9729
293k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9730
293k
}
9731
9732
static int
9733
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9734
          xmlXPathStepOpPtr op,
9735
          int *maxPos)
9736
257k
{
9737
9738
257k
    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
257k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9754
0
  return(0);
9755
9756
257k
    if (op->ch2 != -1) {
9757
257k
  exprOp = &ctxt->comp->steps[op->ch2];
9758
257k
    } else
9759
0
  return(0);
9760
9761
257k
    if ((exprOp != NULL) &&
9762
257k
  (exprOp->op == XPATH_OP_VALUE) &&
9763
210k
  (exprOp->value4 != NULL) &&
9764
210k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9765
209k
    {
9766
209k
        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
209k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9780
209k
      *maxPos = (int) floatval;
9781
209k
            if (floatval == (double) *maxPos)
9782
208k
                return(1);
9783
209k
        }
9784
209k
    }
9785
48.6k
    return(0);
9786
257k
}
9787
9788
static int
9789
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9790
                           xmlXPathStepOpPtr op,
9791
         xmlNodePtr * first, xmlNodePtr * last,
9792
         int toBool)
9793
1.25M
{
9794
9795
1.25M
#define XP_TEST_HIT \
9796
32.5M
    if (hasAxisRange != 0) { \
9797
533k
  if (++pos == maxPos) { \
9798
4.38k
      if (addNode(seq, cur) < 0) \
9799
4.38k
          xmlXPathPErrMemory(ctxt); \
9800
4.38k
      goto axis_range_end; } \
9801
31.9M
    } else { \
9802
31.9M
  if (addNode(seq, cur) < 0) \
9803
31.9M
      xmlXPathPErrMemory(ctxt); \
9804
31.9M
  if (breakOnFirstHit) goto first_hit; }
9805
9806
1.25M
#define XP_TEST_HIT_NS \
9807
1.38M
    if (hasAxisRange != 0) { \
9808
2.02k
  if (++pos == maxPos) { \
9809
1.05k
      hasNsNodes = 1; \
9810
1.05k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9811
1.05k
          xmlXPathPErrMemory(ctxt); \
9812
1.05k
  goto axis_range_end; } \
9813
1.38M
    } else { \
9814
1.38M
  hasNsNodes = 1; \
9815
1.38M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9816
1.38M
      xmlXPathPErrMemory(ctxt); \
9817
1.38M
  if (breakOnFirstHit) goto first_hit; }
9818
9819
1.25M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9820
1.25M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9821
1.25M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9822
1.25M
    const xmlChar *prefix = op->value4;
9823
1.25M
    const xmlChar *name = op->value5;
9824
1.25M
    const xmlChar *URI = NULL;
9825
9826
1.25M
    int total = 0, hasNsNodes = 0;
9827
    /* The popped object holding the context nodes */
9828
1.25M
    xmlXPathObjectPtr obj;
9829
    /* The set of context nodes for the node tests */
9830
1.25M
    xmlNodeSetPtr contextSeq;
9831
1.25M
    int contextIdx;
9832
1.25M
    xmlNodePtr contextNode;
9833
    /* The final resulting node set wrt to all context nodes */
9834
1.25M
    xmlNodeSetPtr outSeq;
9835
    /*
9836
    * The temporary resulting node set wrt 1 context node.
9837
    * Used to feed predicate evaluation.
9838
    */
9839
1.25M
    xmlNodeSetPtr seq;
9840
1.25M
    xmlNodePtr cur;
9841
    /* First predicate operator */
9842
1.25M
    xmlXPathStepOpPtr predOp;
9843
1.25M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9844
1.25M
    int hasPredicateRange, hasAxisRange, pos;
9845
1.25M
    int breakOnFirstHit;
9846
9847
1.25M
    xmlXPathTraversalFunction next = NULL;
9848
1.25M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9849
1.25M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9850
1.25M
    xmlNodePtr oldContextNode;
9851
1.25M
    xmlXPathContextPtr xpctxt = ctxt->context;
9852
9853
9854
1.25M
    CHECK_TYPE0(XPATH_NODESET);
9855
1.25M
    obj = xmlXPathValuePop(ctxt);
9856
    /*
9857
    * Setup namespaces.
9858
    */
9859
1.25M
    if (prefix != NULL) {
9860
6.30k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9861
6.30k
        if (URI == NULL) {
9862
41
      xmlXPathReleaseObject(xpctxt, obj);
9863
41
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9864
41
                           "Undefined namespace prefix: %s\n", prefix);
9865
41
            return 0;
9866
41
  }
9867
6.30k
    }
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
1.25M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9882
1.25M
    switch (axis) {
9883
24.5k
        case AXIS_ANCESTOR:
9884
24.5k
            first = NULL;
9885
24.5k
            next = xmlXPathNextAncestor;
9886
24.5k
            break;
9887
1.57k
        case AXIS_ANCESTOR_OR_SELF:
9888
1.57k
            first = NULL;
9889
1.57k
            next = xmlXPathNextAncestorOrSelf;
9890
1.57k
            break;
9891
6.10k
        case AXIS_ATTRIBUTE:
9892
6.10k
            first = NULL;
9893
6.10k
      last = NULL;
9894
6.10k
            next = xmlXPathNextAttribute;
9895
6.10k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9896
6.10k
            break;
9897
1.00M
        case AXIS_CHILD:
9898
1.00M
      last = NULL;
9899
1.00M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9900
795k
    (type == NODE_TYPE_NODE))
9901
795k
      {
9902
    /*
9903
    * Optimization if an element node type is 'element'.
9904
    */
9905
795k
    next = xmlXPathNextChildElement;
9906
795k
      } else
9907
211k
    next = xmlXPathNextChild;
9908
1.00M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9909
1.00M
            break;
9910
27.5k
        case AXIS_DESCENDANT:
9911
27.5k
      last = NULL;
9912
27.5k
            next = xmlXPathNextDescendant;
9913
27.5k
            break;
9914
152k
        case AXIS_DESCENDANT_OR_SELF:
9915
152k
      last = NULL;
9916
152k
            next = xmlXPathNextDescendantOrSelf;
9917
152k
            break;
9918
997
        case AXIS_FOLLOWING:
9919
997
      last = NULL;
9920
997
            next = xmlXPathNextFollowing;
9921
997
            break;
9922
692
        case AXIS_FOLLOWING_SIBLING:
9923
692
      last = NULL;
9924
692
            next = xmlXPathNextFollowingSibling;
9925
692
            break;
9926
6.17k
        case AXIS_NAMESPACE:
9927
6.17k
            first = NULL;
9928
6.17k
      last = NULL;
9929
6.17k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9930
6.17k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9931
6.17k
            break;
9932
23.0k
        case AXIS_PARENT:
9933
23.0k
            first = NULL;
9934
23.0k
            next = xmlXPathNextParent;
9935
23.0k
            break;
9936
1.29k
        case AXIS_PRECEDING:
9937
1.29k
            first = NULL;
9938
1.29k
            next = xmlXPathNextPrecedingInternal;
9939
1.29k
            break;
9940
980
        case AXIS_PRECEDING_SIBLING:
9941
980
            first = NULL;
9942
980
            next = xmlXPathNextPrecedingSibling;
9943
980
            break;
9944
388
        case AXIS_SELF:
9945
388
            first = NULL;
9946
388
      last = NULL;
9947
388
            next = xmlXPathNextSelf;
9948
388
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9949
388
            break;
9950
1.25M
    }
9951
9952
1.25M
    if (next == NULL) {
9953
0
  xmlXPathReleaseObject(xpctxt, obj);
9954
0
        return(0);
9955
0
    }
9956
1.25M
    contextSeq = obj->nodesetval;
9957
1.25M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9958
7.30k
        xmlXPathValuePush(ctxt, obj);
9959
7.30k
        return(0);
9960
7.30k
    }
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
1.24M
    maxPos = 0;
9980
1.24M
    predOp = NULL;
9981
1.24M
    hasPredicateRange = 0;
9982
1.24M
    hasAxisRange = 0;
9983
1.24M
    if (op->ch2 != -1) {
9984
  /*
9985
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9986
  */
9987
257k
  predOp = &ctxt->comp->steps[op->ch2];
9988
257k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9989
208k
      if (predOp->ch1 != -1) {
9990
    /*
9991
    * Use the next inner predicate operator.
9992
    */
9993
1.89k
    predOp = &ctxt->comp->steps[predOp->ch1];
9994
1.89k
    hasPredicateRange = 1;
9995
206k
      } else {
9996
    /*
9997
    * There's no other predicate than the [n] predicate.
9998
    */
9999
206k
    predOp = NULL;
10000
206k
    hasAxisRange = 1;
10001
206k
      }
10002
208k
  }
10003
257k
    }
10004
1.24M
    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
1.24M
    oldContextNode = xpctxt->node;
10019
1.24M
    addNode = xmlXPathNodeSetAddUnique;
10020
1.24M
    outSeq = NULL;
10021
1.24M
    seq = NULL;
10022
1.24M
    contextNode = NULL;
10023
1.24M
    contextIdx = 0;
10024
10025
10026
5.35M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10027
4.12M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
10028
4.12M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
10029
10030
4.12M
  if (seq == NULL) {
10031
1.28M
      seq = xmlXPathNodeSetCreate(NULL);
10032
1.28M
      if (seq == NULL) {
10033
74
                xmlXPathPErrMemory(ctxt);
10034
74
    total = 0;
10035
74
    goto error;
10036
74
      }
10037
1.28M
  }
10038
  /*
10039
  * Traverse the axis and test the nodes.
10040
  */
10041
4.12M
  pos = 0;
10042
4.12M
  cur = NULL;
10043
4.12M
  hasNsNodes = 0;
10044
39.8M
        do {
10045
39.8M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10046
46
                goto error;
10047
10048
39.8M
            cur = next(ctxt, cur);
10049
39.8M
            if (cur == NULL)
10050
4.10M
                break;
10051
10052
      /*
10053
      * QUESTION TODO: What does the "first" and "last" stuff do?
10054
      */
10055
35.7M
            if ((first != NULL) && (*first != NULL)) {
10056
2.30k
    if (*first == cur)
10057
362
        break;
10058
1.93k
    if (((total % 256) == 0) &&
10059
1.27k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10060
1.27k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10061
#else
10062
        (xmlXPathCmpNodes(*first, cur) >= 0))
10063
#endif
10064
963
    {
10065
963
        break;
10066
963
    }
10067
1.93k
      }
10068
35.7M
      if ((last != NULL) && (*last != NULL)) {
10069
6.53k
    if (*last == cur)
10070
691
        break;
10071
5.83k
    if (((total % 256) == 0) &&
10072
4.43k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10073
4.43k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10074
#else
10075
        (xmlXPathCmpNodes(cur, *last) >= 0))
10076
#endif
10077
4.02k
    {
10078
4.02k
        break;
10079
4.02k
    }
10080
5.83k
      }
10081
10082
35.7M
            total++;
10083
10084
35.7M
      switch (test) {
10085
0
                case NODE_TEST_NONE:
10086
0
        total = 0;
10087
0
        goto error;
10088
31.1M
                case NODE_TEST_TYPE:
10089
31.1M
        if (type == NODE_TYPE_NODE) {
10090
30.9M
      switch (cur->type) {
10091
122k
          case XML_DOCUMENT_NODE:
10092
122k
          case XML_HTML_DOCUMENT_NODE:
10093
17.8M
          case XML_ELEMENT_NODE:
10094
17.8M
          case XML_ATTRIBUTE_NODE:
10095
17.8M
          case XML_PI_NODE:
10096
17.8M
          case XML_COMMENT_NODE:
10097
17.8M
          case XML_CDATA_SECTION_NODE:
10098
30.7M
          case XML_TEXT_NODE:
10099
30.7M
        XP_TEST_HIT
10100
30.7M
        break;
10101
30.7M
          case XML_NAMESPACE_DECL: {
10102
132k
        if (axis == AXIS_NAMESPACE) {
10103
3.76k
            XP_TEST_HIT_NS
10104
128k
        } else {
10105
128k
                              hasNsNodes = 1;
10106
128k
            XP_TEST_HIT
10107
128k
        }
10108
131k
        break;
10109
132k
                            }
10110
131k
          default:
10111
1.89k
        break;
10112
30.9M
      }
10113
30.9M
        } else if (cur->type == (xmlElementType) type) {
10114
126k
      if (cur->type == XML_NAMESPACE_DECL)
10115
0
          XP_TEST_HIT_NS
10116
126k
      else
10117
126k
          XP_TEST_HIT
10118
146k
        } else if ((type == NODE_TYPE_TEXT) &&
10119
146k
       (cur->type == XML_CDATA_SECTION_NODE))
10120
1.03k
        {
10121
1.03k
      XP_TEST_HIT
10122
1.03k
        }
10123
31.1M
        break;
10124
31.1M
                case NODE_TEST_PI:
10125
11.8k
                    if ((cur->type == XML_PI_NODE) &&
10126
999
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10127
800
        {
10128
800
      XP_TEST_HIT
10129
800
                    }
10130
11.4k
                    break;
10131
3.83M
                case NODE_TEST_ALL:
10132
3.83M
                    if (axis == AXIS_ATTRIBUTE) {
10133
5.47k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10134
5.47k
      {
10135
5.47k
                            if (prefix == NULL)
10136
4.13k
          {
10137
4.13k
        XP_TEST_HIT
10138
4.13k
                            } else if ((cur->ns != NULL) &&
10139
1.11k
        (xmlStrEqual(URI, cur->ns->href)))
10140
916
          {
10141
916
        XP_TEST_HIT
10142
916
                            }
10143
5.47k
                        }
10144
3.82M
                    } else if (axis == AXIS_NAMESPACE) {
10145
1.38M
                        if (cur->type == XML_NAMESPACE_DECL)
10146
1.38M
      {
10147
1.38M
          XP_TEST_HIT_NS
10148
1.38M
                        }
10149
2.44M
                    } else {
10150
2.44M
                        if (cur->type == XML_ELEMENT_NODE) {
10151
1.43M
                            if (prefix == NULL)
10152
1.43M
          {
10153
1.43M
        XP_TEST_HIT
10154
10155
1.43M
                            } else if ((cur->ns != NULL) &&
10156
1.09k
        (xmlStrEqual(URI, cur->ns->href)))
10157
881
          {
10158
881
        XP_TEST_HIT
10159
881
                            }
10160
1.43M
                        }
10161
2.44M
                    }
10162
3.82M
                    break;
10163
3.82M
                case NODE_TEST_NS:{
10164
                        /* TODO */
10165
0
                        break;
10166
3.83M
                    }
10167
707k
                case NODE_TEST_NAME:
10168
707k
                    if (axis == AXIS_ATTRIBUTE) {
10169
2.79k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10170
0
          break;
10171
704k
        } else if (axis == AXIS_NAMESPACE) {
10172
4.96k
                        if (cur->type != XML_NAMESPACE_DECL)
10173
0
          break;
10174
699k
        } else {
10175
699k
            if (cur->type != XML_ELEMENT_NODE)
10176
44.0k
          break;
10177
699k
        }
10178
663k
                    switch (cur->type) {
10179
655k
                        case XML_ELEMENT_NODE:
10180
655k
                            if (xmlStrEqual(name, cur->name)) {
10181
14.5k
                                if (prefix == NULL) {
10182
12.8k
                                    if (cur->ns == NULL)
10183
12.5k
            {
10184
12.5k
          XP_TEST_HIT
10185
12.5k
                                    }
10186
12.8k
                                } else {
10187
1.78k
                                    if ((cur->ns != NULL) &&
10188
1.03k
                                        (xmlStrEqual(URI, cur->ns->href)))
10189
830
            {
10190
830
          XP_TEST_HIT
10191
830
                                    }
10192
1.78k
                                }
10193
14.5k
                            }
10194
654k
                            break;
10195
654k
                        case XML_ATTRIBUTE_NODE:{
10196
2.79k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10197
10198
2.79k
                                if (xmlStrEqual(name, attr->name)) {
10199
2.55k
                                    if (prefix == NULL) {
10200
1.28k
                                        if ((attr->ns == NULL) ||
10201
214
                                            (attr->ns->prefix == NULL))
10202
1.07k
          {
10203
1.07k
              XP_TEST_HIT
10204
1.07k
                                        }
10205
1.28k
                                    } else {
10206
1.27k
                                        if ((attr->ns != NULL) &&
10207
1.06k
                                            (xmlStrEqual(URI,
10208
1.06k
                attr->ns->href)))
10209
873
          {
10210
873
              XP_TEST_HIT
10211
873
                                        }
10212
1.27k
                                    }
10213
2.55k
                                }
10214
1.91k
                                break;
10215
2.79k
                            }
10216
4.96k
                        case XML_NAMESPACE_DECL:
10217
4.96k
                            if (cur->type == XML_NAMESPACE_DECL) {
10218
4.96k
                                xmlNsPtr ns = (xmlNsPtr) cur;
10219
10220
4.96k
                                if ((ns->prefix != NULL) && (name != NULL)
10221
4.08k
                                    && (xmlStrEqual(ns->prefix, name)))
10222
830
        {
10223
830
            XP_TEST_HIT_NS
10224
830
                                }
10225
4.96k
                            }
10226
4.55k
                            break;
10227
4.55k
                        default:
10228
0
                            break;
10229
663k
                    }
10230
660k
                    break;
10231
35.7M
      } /* switch(test) */
10232
35.7M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10233
10234
4.10M
  goto apply_predicates;
10235
10236
4.10M
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
5.44k
  if (outSeq == NULL) {
10244
2.46k
      outSeq = seq;
10245
2.46k
      seq = NULL;
10246
2.97k
  } else {
10247
2.97k
      outSeq = mergeAndClear(outSeq, seq);
10248
2.97k
            if (outSeq == NULL)
10249
5
                xmlXPathPErrMemory(ctxt);
10250
2.97k
        }
10251
  /*
10252
  * Break if only a true/false result was requested.
10253
  */
10254
5.44k
  if (toBool)
10255
534
      break;
10256
4.90k
  continue;
10257
10258
7.56k
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
7.56k
  if (outSeq == NULL) {
10264
7.56k
      outSeq = seq;
10265
7.56k
      seq = NULL;
10266
7.56k
  } else {
10267
0
      outSeq = mergeAndClear(outSeq, seq);
10268
0
            if (outSeq == NULL)
10269
0
                xmlXPathPErrMemory(ctxt);
10270
0
        }
10271
7.56k
  break;
10272
10273
4.10M
apply_predicates: /* --------------------------------------------------- */
10274
4.10M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10275
118
      goto error;
10276
10277
        /*
10278
  * Apply predicates.
10279
  */
10280
4.10M
        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
292k
      if (hasPredicateRange != 0)
10310
7.90k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10311
7.90k
              hasNsNodes);
10312
285k
      else
10313
285k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10314
285k
              hasNsNodes);
10315
10316
292k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10317
1.02k
    total = 0;
10318
1.02k
    goto error;
10319
1.02k
      }
10320
292k
        }
10321
10322
4.10M
        if (seq->nodeNr > 0) {
10323
      /*
10324
      * Add to result set.
10325
      */
10326
1.42M
      if (outSeq == NULL) {
10327
247k
    outSeq = seq;
10328
247k
    seq = NULL;
10329
1.17M
      } else {
10330
1.17M
    outSeq = mergeAndClear(outSeq, seq);
10331
1.17M
                if (outSeq == NULL)
10332
96
                    xmlXPathPErrMemory(ctxt);
10333
1.17M
      }
10334
10335
1.42M
            if (toBool)
10336
868
                break;
10337
1.42M
  }
10338
4.10M
    }
10339
10340
1.24M
error:
10341
1.24M
    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
1.24M
    xmlXPathReleaseObject(xpctxt, obj);
10353
10354
    /*
10355
    * Ensure we return at least an empty set.
10356
    */
10357
1.24M
    if (outSeq == NULL) {
10358
988k
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10359
988k
      outSeq = seq;
10360
988k
        } else {
10361
161
      outSeq = xmlXPathNodeSetCreate(NULL);
10362
161
            if (outSeq == NULL)
10363
1
                xmlXPathPErrMemory(ctxt);
10364
161
        }
10365
988k
    }
10366
1.24M
    if ((seq != NULL) && (seq != outSeq)) {
10367
37.6k
   xmlXPathFreeNodeSet(seq);
10368
37.6k
    }
10369
    /*
10370
    * Hand over the result. Better to push the set also in
10371
    * case of errors.
10372
    */
10373
1.24M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10374
    /*
10375
    * Reset the context node.
10376
    */
10377
1.24M
    xpctxt->node = oldContextNode;
10378
    /*
10379
    * When traversing the namespace axis in "toBool" mode, it's
10380
    * possible that tmpNsList wasn't freed.
10381
    */
10382
1.24M
    if (xpctxt->tmpNsList != NULL) {
10383
247
        xmlFree(xpctxt->tmpNsList);
10384
247
        xpctxt->tmpNsList = NULL;
10385
247
    }
10386
10387
1.24M
    return(total);
10388
1.24M
}
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
48.1k
{
10407
48.1k
    int total = 0, cur;
10408
48.1k
    xmlXPathCompExprPtr comp;
10409
48.1k
    xmlXPathObjectPtr arg1, arg2;
10410
10411
48.1k
    CHECK_ERROR0;
10412
48.1k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10413
1
        return(0);
10414
48.1k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10415
48.1k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10416
48.1k
    ctxt->context->depth += 1;
10417
48.1k
    comp = ctxt->comp;
10418
48.1k
    switch (op->op) {
10419
0
        case XPATH_OP_END:
10420
0
            break;
10421
9.41k
        case XPATH_OP_UNION:
10422
9.41k
            total =
10423
9.41k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10424
9.41k
                                        first);
10425
9.41k
      CHECK_ERROR0;
10426
8.70k
            if ((ctxt->value != NULL)
10427
8.70k
                && (ctxt->value->type == XPATH_NODESET)
10428
8.69k
                && (ctxt->value->nodesetval != NULL)
10429
8.69k
                && (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
8.30k
    if (ctxt->value->nodesetval->nodeNr > 1)
10441
747
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10442
8.30k
                *first = ctxt->value->nodesetval->nodeTab[0];
10443
8.30k
            }
10444
8.70k
            cur =
10445
8.70k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10446
8.70k
                                        first);
10447
8.70k
      CHECK_ERROR0;
10448
10449
8.67k
            arg2 = xmlXPathValuePop(ctxt);
10450
8.67k
            arg1 = xmlXPathValuePop(ctxt);
10451
8.67k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10452
8.67k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10453
6
          xmlXPathReleaseObject(ctxt->context, arg1);
10454
6
          xmlXPathReleaseObject(ctxt->context, arg2);
10455
6
                XP_ERROR0(XPATH_INVALID_TYPE);
10456
0
            }
10457
8.67k
            if ((ctxt->context->opLimit != 0) &&
10458
8.67k
                (((arg1->nodesetval != NULL) &&
10459
8.67k
                  (xmlXPathCheckOpLimit(ctxt,
10460
8.67k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10461
8.67k
                 ((arg2->nodesetval != NULL) &&
10462
8.67k
                  (xmlXPathCheckOpLimit(ctxt,
10463
8.67k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10464
2
          xmlXPathReleaseObject(ctxt->context, arg1);
10465
2
          xmlXPathReleaseObject(ctxt->context, arg2);
10466
2
                break;
10467
2
            }
10468
10469
8.67k
            if ((arg2->nodesetval != NULL) &&
10470
8.67k
                (arg2->nodesetval->nodeNr != 0)) {
10471
6.79k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10472
6.79k
                                                        arg2->nodesetval);
10473
6.79k
                if (arg1->nodesetval == NULL)
10474
3
                    xmlXPathPErrMemory(ctxt);
10475
6.79k
            }
10476
8.67k
            xmlXPathValuePush(ctxt, arg1);
10477
8.67k
      xmlXPathReleaseObject(ctxt->context, arg2);
10478
8.67k
            total += cur;
10479
8.67k
            break;
10480
1.12k
        case XPATH_OP_ROOT:
10481
1.12k
            xmlXPathRoot(ctxt);
10482
1.12k
            break;
10483
7.08k
        case XPATH_OP_NODE:
10484
7.08k
            if (op->ch1 != -1)
10485
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10486
7.08k
      CHECK_ERROR0;
10487
7.08k
            if (op->ch2 != -1)
10488
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10489
7.08k
      CHECK_ERROR0;
10490
7.08k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10491
7.08k
    ctxt->context->node));
10492
7.08k
            break;
10493
8.77k
        case XPATH_OP_COLLECT:{
10494
8.77k
                if (op->ch1 == -1)
10495
0
                    break;
10496
10497
8.77k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10498
8.77k
    CHECK_ERROR0;
10499
10500
8.77k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10501
8.77k
                break;
10502
8.77k
            }
10503
16
        case XPATH_OP_VALUE:
10504
16
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10505
16
            break;
10506
9.46k
        case XPATH_OP_SORT:
10507
9.46k
            if (op->ch1 != -1)
10508
9.46k
                total +=
10509
9.46k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10510
9.46k
                                            first);
10511
9.46k
      CHECK_ERROR0;
10512
9.31k
            if ((ctxt->value != NULL)
10513
9.31k
                && (ctxt->value->type == XPATH_NODESET)
10514
8.27k
                && (ctxt->value->nodesetval != NULL)
10515
8.27k
    && (ctxt->value->nodesetval->nodeNr > 1))
10516
6.59k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10517
9.31k
            break;
10518
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10519
11.2k
  case XPATH_OP_FILTER:
10520
11.2k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10521
11.2k
            break;
10522
0
#endif
10523
1.05k
        default:
10524
1.05k
            total += xmlXPathCompOpEval(ctxt, op);
10525
1.05k
            break;
10526
48.1k
    }
10527
10528
47.2k
    ctxt->context->depth -= 1;
10529
47.2k
    return(total);
10530
48.1k
}
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
126k
{
10545
126k
    int total = 0, cur;
10546
126k
    xmlXPathCompExprPtr comp;
10547
126k
    xmlXPathObjectPtr arg1, arg2;
10548
10549
126k
    CHECK_ERROR0;
10550
126k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10551
1
        return(0);
10552
126k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10553
126k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10554
126k
    ctxt->context->depth += 1;
10555
126k
    comp = ctxt->comp;
10556
126k
    switch (op->op) {
10557
0
        case XPATH_OP_END:
10558
0
            break;
10559
50.0k
        case XPATH_OP_UNION:
10560
50.0k
            total =
10561
50.0k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10562
50.0k
      CHECK_ERROR0;
10563
48.7k
            if ((ctxt->value != NULL)
10564
48.7k
                && (ctxt->value->type == XPATH_NODESET)
10565
48.7k
                && (ctxt->value->nodesetval != NULL)
10566
48.7k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10567
                /*
10568
                 * limit tree traversing to first node in the result
10569
                 */
10570
48.1k
    if (ctxt->value->nodesetval->nodeNr > 1)
10571
36.0k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10572
48.1k
                *last =
10573
48.1k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10574
48.1k
                                                     nodesetval->nodeNr -
10575
48.1k
                                                     1];
10576
48.1k
            }
10577
48.7k
            cur =
10578
48.7k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10579
48.7k
      CHECK_ERROR0;
10580
48.7k
            if ((ctxt->value != NULL)
10581
48.7k
                && (ctxt->value->type == XPATH_NODESET)
10582
48.7k
                && (ctxt->value->nodesetval != NULL)
10583
48.7k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10584
46.3k
            }
10585
10586
48.7k
            arg2 = xmlXPathValuePop(ctxt);
10587
48.7k
            arg1 = xmlXPathValuePop(ctxt);
10588
48.7k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10589
48.7k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10590
8
          xmlXPathReleaseObject(ctxt->context, arg1);
10591
8
          xmlXPathReleaseObject(ctxt->context, arg2);
10592
8
                XP_ERROR0(XPATH_INVALID_TYPE);
10593
0
            }
10594
48.6k
            if ((ctxt->context->opLimit != 0) &&
10595
48.6k
                (((arg1->nodesetval != NULL) &&
10596
48.6k
                  (xmlXPathCheckOpLimit(ctxt,
10597
48.6k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10598
48.6k
                 ((arg2->nodesetval != NULL) &&
10599
48.6k
                  (xmlXPathCheckOpLimit(ctxt,
10600
48.6k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10601
5
          xmlXPathReleaseObject(ctxt->context, arg1);
10602
5
          xmlXPathReleaseObject(ctxt->context, arg2);
10603
5
                break;
10604
5
            }
10605
10606
48.6k
            if ((arg2->nodesetval != NULL) &&
10607
48.6k
                (arg2->nodesetval->nodeNr != 0)) {
10608
46.3k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10609
46.3k
                                                        arg2->nodesetval);
10610
46.3k
                if (arg1->nodesetval == NULL)
10611
5
                    xmlXPathPErrMemory(ctxt);
10612
46.3k
            }
10613
48.6k
            xmlXPathValuePush(ctxt, arg1);
10614
48.6k
      xmlXPathReleaseObject(ctxt->context, arg2);
10615
48.6k
            total += cur;
10616
48.6k
            break;
10617
12.7k
        case XPATH_OP_ROOT:
10618
12.7k
            xmlXPathRoot(ctxt);
10619
12.7k
            break;
10620
23.8k
        case XPATH_OP_NODE:
10621
23.8k
            if (op->ch1 != -1)
10622
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10623
23.8k
      CHECK_ERROR0;
10624
23.8k
            if (op->ch2 != -1)
10625
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10626
23.8k
      CHECK_ERROR0;
10627
23.8k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10628
23.8k
    ctxt->context->node));
10629
23.8k
            break;
10630
25.6k
        case XPATH_OP_COLLECT:{
10631
25.6k
                if (op->ch1 == -1)
10632
0
                    break;
10633
10634
25.6k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10635
25.6k
    CHECK_ERROR0;
10636
10637
25.6k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10638
25.6k
                break;
10639
25.6k
            }
10640
18
        case XPATH_OP_VALUE:
10641
18
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10642
18
            break;
10643
14.1k
        case XPATH_OP_SORT:
10644
14.1k
            if (op->ch1 != -1)
10645
14.1k
                total +=
10646
14.1k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10647
14.1k
                                           last);
10648
14.1k
      CHECK_ERROR0;
10649
13.9k
            if ((ctxt->value != NULL)
10650
13.9k
                && (ctxt->value->type == XPATH_NODESET)
10651
13.4k
                && (ctxt->value->nodesetval != NULL)
10652
13.4k
    && (ctxt->value->nodesetval->nodeNr > 1))
10653
11.9k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10654
13.9k
            break;
10655
445
        default:
10656
445
            total += xmlXPathCompOpEval(ctxt, op);
10657
445
            break;
10658
126k
    }
10659
10660
125k
    ctxt->context->depth -= 1;
10661
125k
    return (total);
10662
126k
}
10663
10664
#ifdef XP_OPTIMIZED_FILTER_FIRST
10665
static int
10666
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10667
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10668
11.2k
{
10669
11.2k
    int total = 0;
10670
11.2k
    xmlXPathCompExprPtr comp;
10671
11.2k
    xmlXPathObjectPtr obj;
10672
11.2k
    xmlNodeSetPtr set;
10673
10674
11.2k
    CHECK_ERROR0;
10675
11.2k
    comp = ctxt->comp;
10676
    /*
10677
    * Optimization for ()[last()] selection i.e. the last elem
10678
    */
10679
11.2k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10680
11.2k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10681
2.45k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10682
1.83k
  int f = comp->steps[op->ch2].ch1;
10683
10684
1.83k
  if ((f != -1) &&
10685
1.83k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10686
1.60k
      (comp->steps[f].value5 == NULL) &&
10687
1.32k
      (comp->steps[f].value == 0) &&
10688
1.10k
      (comp->steps[f].value4 != NULL) &&
10689
1.10k
      (xmlStrEqual
10690
1.10k
      (comp->steps[f].value4, BAD_CAST "last"))) {
10691
885
      xmlNodePtr last = NULL;
10692
10693
885
      total +=
10694
885
    xmlXPathCompOpEvalLast(ctxt,
10695
885
        &comp->steps[op->ch1],
10696
885
        &last);
10697
885
      CHECK_ERROR0;
10698
      /*
10699
      * The nodeset should be in document order,
10700
      * Keep only the last value
10701
      */
10702
872
      if ((ctxt->value != NULL) &&
10703
872
    (ctxt->value->type == XPATH_NODESET) &&
10704
657
    (ctxt->value->nodesetval != NULL) &&
10705
657
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10706
442
    (ctxt->value->nodesetval->nodeNr > 1)) {
10707
226
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10708
226
    *first = *(ctxt->value->nodesetval->nodeTab);
10709
226
      }
10710
872
      return (total);
10711
885
  }
10712
1.83k
    }
10713
10714
10.3k
    if (op->ch1 != -1)
10715
10.3k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10716
10.3k
    CHECK_ERROR0;
10717
10.1k
    if (op->ch2 == -1)
10718
0
  return (total);
10719
10.1k
    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
10.1k
    CHECK_TYPE0(XPATH_NODESET);
10728
10.1k
    obj = xmlXPathValuePop(ctxt);
10729
10.1k
    set = obj->nodesetval;
10730
10.1k
    if (set != NULL) {
10731
10.1k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10732
10.1k
        if (set->nodeNr > 0)
10733
262
            *first = set->nodeTab[0];
10734
10.1k
    }
10735
10.1k
    xmlXPathValuePush(ctxt, obj);
10736
10737
10.1k
    return (total);
10738
10.1k
}
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
4.07M
{
10751
4.07M
    int total = 0;
10752
4.07M
    int equal, ret;
10753
4.07M
    xmlXPathCompExprPtr comp;
10754
4.07M
    xmlXPathObjectPtr arg1, arg2;
10755
10756
4.07M
    CHECK_ERROR0;
10757
4.07M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10758
3
        return(0);
10759
4.07M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10760
4.07M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10761
4.07M
    ctxt->context->depth += 1;
10762
4.07M
    comp = ctxt->comp;
10763
4.07M
    switch (op->op) {
10764
0
        case XPATH_OP_END:
10765
0
            break;
10766
92.1k
        case XPATH_OP_AND:
10767
92.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10768
92.1k
      CHECK_ERROR0;
10769
91.9k
            xmlXPathBooleanFunction(ctxt, 1);
10770
91.9k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10771
91.2k
                break;
10772
646
            arg2 = xmlXPathValuePop(ctxt);
10773
646
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10774
646
      if (ctxt->error) {
10775
34
    xmlXPathFreeObject(arg2);
10776
34
    break;
10777
34
      }
10778
612
            xmlXPathBooleanFunction(ctxt, 1);
10779
612
            if (ctxt->value != NULL)
10780
611
                ctxt->value->boolval &= arg2->boolval;
10781
612
      xmlXPathReleaseObject(ctxt->context, arg2);
10782
612
            break;
10783
7.63k
        case XPATH_OP_OR:
10784
7.63k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10785
7.63k
      CHECK_ERROR0;
10786
7.18k
            xmlXPathBooleanFunction(ctxt, 1);
10787
7.18k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10788
3.60k
                break;
10789
3.57k
            arg2 = xmlXPathValuePop(ctxt);
10790
3.57k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10791
3.57k
      if (ctxt->error) {
10792
72
    xmlXPathFreeObject(arg2);
10793
72
    break;
10794
72
      }
10795
3.50k
            xmlXPathBooleanFunction(ctxt, 1);
10796
3.50k
            if (ctxt->value != NULL)
10797
3.50k
                ctxt->value->boolval |= arg2->boolval;
10798
3.50k
      xmlXPathReleaseObject(ctxt->context, arg2);
10799
3.50k
            break;
10800
250k
        case XPATH_OP_EQUAL:
10801
250k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10802
250k
      CHECK_ERROR0;
10803
249k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10804
249k
      CHECK_ERROR0;
10805
249k
      if (op->value)
10806
243k
    equal = xmlXPathEqualValues(ctxt);
10807
5.59k
      else
10808
5.59k
    equal = xmlXPathNotEqualValues(ctxt);
10809
249k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10810
249k
            break;
10811
256k
        case XPATH_OP_CMP:
10812
256k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10813
256k
      CHECK_ERROR0;
10814
256k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10815
256k
      CHECK_ERROR0;
10816
256k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10817
256k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10818
256k
            break;
10819
192k
        case XPATH_OP_PLUS:
10820
192k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10821
192k
      CHECK_ERROR0;
10822
191k
            if (op->ch2 != -1) {
10823
153k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10824
153k
      }
10825
191k
      CHECK_ERROR0;
10826
191k
            if (op->value == 0)
10827
151k
                xmlXPathSubValues(ctxt);
10828
40.0k
            else if (op->value == 1)
10829
2.41k
                xmlXPathAddValues(ctxt);
10830
37.5k
            else if (op->value == 2)
10831
34.7k
                xmlXPathValueFlipSign(ctxt);
10832
2.87k
            else if (op->value == 3) {
10833
2.87k
                CAST_TO_NUMBER;
10834
2.87k
                CHECK_TYPE0(XPATH_NUMBER);
10835
2.87k
            }
10836
191k
            break;
10837
191k
        case XPATH_OP_MULT:
10838
34.8k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10839
34.8k
      CHECK_ERROR0;
10840
30.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10841
30.1k
      CHECK_ERROR0;
10842
30.0k
            if (op->value == 0)
10843
27.1k
                xmlXPathMultValues(ctxt);
10844
2.93k
            else if (op->value == 1)
10845
2.20k
                xmlXPathDivValues(ctxt);
10846
729
            else if (op->value == 2)
10847
729
                xmlXPathModValues(ctxt);
10848
30.0k
            break;
10849
59.0k
        case XPATH_OP_UNION:
10850
59.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10851
59.0k
      CHECK_ERROR0;
10852
57.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10853
57.7k
      CHECK_ERROR0;
10854
10855
57.6k
            arg2 = xmlXPathValuePop(ctxt);
10856
57.6k
            arg1 = xmlXPathValuePop(ctxt);
10857
57.6k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10858
57.6k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10859
13
          xmlXPathReleaseObject(ctxt->context, arg1);
10860
13
          xmlXPathReleaseObject(ctxt->context, arg2);
10861
13
                XP_ERROR0(XPATH_INVALID_TYPE);
10862
0
            }
10863
57.6k
            if ((ctxt->context->opLimit != 0) &&
10864
57.6k
                (((arg1->nodesetval != NULL) &&
10865
57.6k
                  (xmlXPathCheckOpLimit(ctxt,
10866
57.6k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10867
57.6k
                 ((arg2->nodesetval != NULL) &&
10868
57.6k
                  (xmlXPathCheckOpLimit(ctxt,
10869
57.6k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10870
3
          xmlXPathReleaseObject(ctxt->context, arg1);
10871
3
          xmlXPathReleaseObject(ctxt->context, arg2);
10872
3
                break;
10873
3
            }
10874
10875
57.6k
      if (((arg2->nodesetval != NULL) &&
10876
57.6k
     (arg2->nodesetval->nodeNr != 0)))
10877
51.0k
      {
10878
51.0k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10879
51.0k
              arg2->nodesetval);
10880
51.0k
                if (arg1->nodesetval == NULL)
10881
32
                    xmlXPathPErrMemory(ctxt);
10882
51.0k
      }
10883
10884
57.6k
            xmlXPathValuePush(ctxt, arg1);
10885
57.6k
      xmlXPathReleaseObject(ctxt->context, arg2);
10886
57.6k
            break;
10887
192k
        case XPATH_OP_ROOT:
10888
192k
            xmlXPathRoot(ctxt);
10889
192k
            break;
10890
1.16M
        case XPATH_OP_NODE:
10891
1.16M
            if (op->ch1 != -1)
10892
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10893
1.16M
      CHECK_ERROR0;
10894
1.16M
            if (op->ch2 != -1)
10895
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10896
1.16M
      CHECK_ERROR0;
10897
1.16M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10898
1.16M
                                                    ctxt->context->node));
10899
1.16M
            break;
10900
834k
        case XPATH_OP_COLLECT:{
10901
834k
                if (op->ch1 == -1)
10902
0
                    break;
10903
10904
834k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10905
834k
    CHECK_ERROR0;
10906
10907
834k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10908
834k
                break;
10909
834k
            }
10910
553k
        case XPATH_OP_VALUE:
10911
553k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10912
553k
            break;
10913
62
        case XPATH_OP_VARIABLE:{
10914
62
    xmlXPathObjectPtr val;
10915
10916
62
                if (op->ch1 != -1)
10917
0
                    total +=
10918
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10919
62
                if (op->value5 == NULL) {
10920
59
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10921
59
        if (val == NULL) {
10922
59
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10923
59
                                       "Undefined variable: %s\n", op->value4);
10924
59
                        return 0;
10925
59
                    }
10926
0
                    xmlXPathValuePush(ctxt, val);
10927
3
    } else {
10928
3
                    const xmlChar *URI;
10929
10930
3
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10931
3
                    if (URI == NULL) {
10932
2
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10933
2
                                       "Undefined namespace prefix: %s\n",
10934
2
                                       op->value5);
10935
2
                        return 0;
10936
2
                    }
10937
1
        val = xmlXPathVariableLookupNS(ctxt->context,
10938
1
                                                       op->value4, URI);
10939
1
        if (val == NULL) {
10940
1
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10941
1
                                       "Undefined variable: %s:%s\n",
10942
1
                                       op->value5, op->value4);
10943
1
                        return 0;
10944
1
                    }
10945
0
                    xmlXPathValuePush(ctxt, val);
10946
0
                }
10947
0
                break;
10948
62
            }
10949
148k
        case XPATH_OP_FUNCTION:{
10950
148k
                xmlXPathFunction func;
10951
148k
                const xmlChar *oldFunc, *oldFuncURI;
10952
148k
    int i;
10953
148k
                int frame;
10954
10955
148k
                frame = ctxt->valueNr;
10956
148k
                if (op->ch1 != -1) {
10957
66.6k
                    total +=
10958
66.6k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10959
66.6k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10960
413
                        break;
10961
66.6k
                }
10962
148k
    if (ctxt->valueNr < frame + op->value)
10963
148k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10964
239k
    for (i = 0; i < op->value; i++) {
10965
91.0k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10966
91.0k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10967
91.0k
                }
10968
148k
                if (op->cache != NULL)
10969
144k
                    func = op->cache;
10970
3.78k
                else {
10971
3.78k
                    const xmlChar *URI = NULL;
10972
10973
3.78k
                    if (op->value5 == NULL) {
10974
3.78k
                        func = xmlXPathFunctionLookup(ctxt->context,
10975
3.78k
                                                      op->value4);
10976
3.78k
                        if (func == NULL) {
10977
315
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10978
315
                                           "Unregistered function: %s\n",
10979
315
                                           op->value4);
10980
315
                            return 0;
10981
315
                        }
10982
3.78k
                    } else {
10983
4
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10984
4
                        if (URI == NULL) {
10985
3
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10986
3
                                           "Undefined namespace prefix: %s\n",
10987
3
                                           op->value5);
10988
3
                            return 0;
10989
3
                        }
10990
1
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10991
1
                                                        op->value4, URI);
10992
1
                        if (func == NULL) {
10993
1
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10994
1
                                           "Unregistered function: %s:%s\n",
10995
1
                                           op->value5, op->value4);
10996
1
                            return 0;
10997
1
                        }
10998
1
                    }
10999
3.46k
                    op->cache = func;
11000
3.46k
                    op->cacheURI = (void *) URI;
11001
3.46k
                }
11002
148k
                oldFunc = ctxt->context->function;
11003
148k
                oldFuncURI = ctxt->context->functionURI;
11004
148k
                ctxt->context->function = op->value4;
11005
148k
                ctxt->context->functionURI = op->cacheURI;
11006
148k
                func(ctxt, op->value);
11007
148k
                ctxt->context->function = oldFunc;
11008
148k
                ctxt->context->functionURI = oldFuncURI;
11009
148k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11010
147k
                    (ctxt->valueNr != frame + 1))
11011
148k
                    XP_ERROR0(XPATH_STACK_ERROR);
11012
148k
                break;
11013
148k
            }
11014
98.1k
        case XPATH_OP_ARG:
11015
98.1k
            if (op->ch1 != -1) {
11016
31.5k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11017
31.5k
          CHECK_ERROR0;
11018
31.5k
            }
11019
92.7k
            if (op->ch2 != -1) {
11020
92.7k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11021
92.7k
          CHECK_ERROR0;
11022
92.7k
      }
11023
92.3k
            break;
11024
92.3k
        case XPATH_OP_PREDICATE:
11025
75.9k
        case XPATH_OP_FILTER:{
11026
75.9k
                xmlXPathObjectPtr obj;
11027
75.9k
                xmlNodeSetPtr set;
11028
11029
                /*
11030
                 * Optimization for ()[1] selection i.e. the first elem
11031
                 */
11032
75.9k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11033
75.9k
#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
75.9k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11044
41.1k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11045
#else
11046
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
#endif
11048
62.2k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11049
27.5k
                    xmlXPathObjectPtr val;
11050
11051
27.5k
                    val = comp->steps[op->ch2].value4;
11052
27.5k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11053
27.2k
                        (val->floatval == 1.0)) {
11054
20.5k
                        xmlNodePtr first = NULL;
11055
11056
20.5k
                        total +=
11057
20.5k
                            xmlXPathCompOpEvalFirst(ctxt,
11058
20.5k
                                                    &comp->steps[op->ch1],
11059
20.5k
                                                    &first);
11060
20.5k
      CHECK_ERROR0;
11061
                        /*
11062
                         * The nodeset should be in document order,
11063
                         * Keep only the first value
11064
                         */
11065
20.3k
                        if ((ctxt->value != NULL) &&
11066
20.3k
                            (ctxt->value->type == XPATH_NODESET) &&
11067
19.1k
                            (ctxt->value->nodesetval != NULL) &&
11068
19.1k
                            (ctxt->value->nodesetval->nodeNr > 1))
11069
6.59k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11070
6.59k
                                                        1, 1);
11071
20.3k
                        break;
11072
20.5k
                    }
11073
27.5k
                }
11074
                /*
11075
                 * Optimization for ()[last()] selection i.e. the last elem
11076
                 */
11077
55.3k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11078
55.3k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11079
25.4k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11080
21.0k
                    int f = comp->steps[op->ch2].ch1;
11081
11082
21.0k
                    if ((f != -1) &&
11083
21.0k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11084
15.4k
                        (comp->steps[f].value5 == NULL) &&
11085
15.2k
                        (comp->steps[f].value == 0) &&
11086
14.3k
                        (comp->steps[f].value4 != NULL) &&
11087
14.3k
                        (xmlStrEqual
11088
14.3k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11089
13.0k
                        xmlNodePtr last = NULL;
11090
11091
13.0k
                        total +=
11092
13.0k
                            xmlXPathCompOpEvalLast(ctxt,
11093
13.0k
                                                   &comp->steps[op->ch1],
11094
13.0k
                                                   &last);
11095
13.0k
      CHECK_ERROR0;
11096
                        /*
11097
                         * The nodeset should be in document order,
11098
                         * Keep only the last value
11099
                         */
11100
13.0k
                        if ((ctxt->value != NULL) &&
11101
13.0k
                            (ctxt->value->type == XPATH_NODESET) &&
11102
12.8k
                            (ctxt->value->nodesetval != NULL) &&
11103
12.8k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11104
12.4k
                            (ctxt->value->nodesetval->nodeNr > 1))
11105
11.7k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11106
13.0k
                        break;
11107
13.0k
                    }
11108
21.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
42.3k
                if (op->ch1 != -1)
11121
42.3k
                    total +=
11122
42.3k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11123
42.3k
    CHECK_ERROR0;
11124
41.8k
                if (op->ch2 == -1)
11125
0
                    break;
11126
41.8k
                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
41.8k
                CHECK_TYPE0(XPATH_NODESET);
11136
41.8k
                obj = xmlXPathValuePop(ctxt);
11137
41.8k
                set = obj->nodesetval;
11138
41.8k
                if (set != NULL)
11139
41.8k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11140
41.8k
                                          1, set->nodeNr, 1);
11141
41.8k
                xmlXPathValuePush(ctxt, obj);
11142
41.8k
                break;
11143
41.8k
            }
11144
108k
        case XPATH_OP_SORT:
11145
108k
            if (op->ch1 != -1)
11146
108k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11147
108k
      CHECK_ERROR0;
11148
106k
            if ((ctxt->value != NULL) &&
11149
106k
                (ctxt->value->type == XPATH_NODESET) &&
11150
99.0k
                (ctxt->value->nodesetval != NULL) &&
11151
99.0k
    (ctxt->value->nodesetval->nodeNr > 1))
11152
48.8k
      {
11153
48.8k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11154
48.8k
      }
11155
106k
            break;
11156
0
        default:
11157
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11158
0
            break;
11159
4.07M
    }
11160
11161
4.05M
    ctxt->context->depth -= 1;
11162
4.05M
    return (total);
11163
4.07M
}
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
1.44M
{
11178
1.44M
    xmlXPathObjectPtr resObj = NULL;
11179
11180
1.69M
start:
11181
1.69M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11182
1
        return(0);
11183
    /* comp = ctxt->comp; */
11184
1.69M
    switch (op->op) {
11185
0
        case XPATH_OP_END:
11186
0
            return (0);
11187
250k
  case XPATH_OP_VALUE:
11188
250k
      resObj = (xmlXPathObjectPtr) op->value4;
11189
250k
      if (isPredicate)
11190
250k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11191
0
      return(xmlXPathCastToBoolean(resObj));
11192
250k
  case XPATH_OP_SORT:
11193
      /*
11194
      * We don't need sorting for boolean results. Skip this one.
11195
      */
11196
250k
            if (op->ch1 != -1) {
11197
250k
    op = &ctxt->comp->steps[op->ch1];
11198
250k
    goto start;
11199
250k
      }
11200
0
      return(0);
11201
384k
  case XPATH_OP_COLLECT:
11202
384k
      if (op->ch1 == -1)
11203
0
    return(0);
11204
11205
384k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11206
384k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11207
54
    return(-1);
11208
11209
384k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11210
384k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11211
357
    return(-1);
11212
11213
384k
      resObj = xmlXPathValuePop(ctxt);
11214
384k
      if (resObj == NULL)
11215
0
    return(-1);
11216
384k
      break;
11217
808k
  default:
11218
      /*
11219
      * Fallback to call xmlXPathCompOpEval().
11220
      */
11221
808k
      xmlXPathCompOpEval(ctxt, op);
11222
808k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11223
647
    return(-1);
11224
11225
808k
      resObj = xmlXPathValuePop(ctxt);
11226
808k
      if (resObj == NULL)
11227
0
    return(-1);
11228
808k
      break;
11229
1.69M
    }
11230
11231
1.19M
    if (resObj) {
11232
1.19M
  int res;
11233
11234
1.19M
  if (resObj->type == XPATH_BOOLEAN) {
11235
383k
      res = resObj->boolval;
11236
808k
  } 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
808k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11246
808k
  } else {
11247
0
      res = xmlXPathCastToBoolean(resObj);
11248
0
  }
11249
1.19M
  xmlXPathReleaseObject(ctxt->context, resObj);
11250
1.19M
  return(res);
11251
1.19M
    }
11252
11253
0
    return(0);
11254
1.19M
}
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
11.6k
{
11497
11.6k
    xmlXPathCompExprPtr comp;
11498
11.6k
    int oldDepth;
11499
11500
11.6k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11501
0
  return(-1);
11502
11503
11.6k
    if (ctxt->valueTab == NULL) {
11504
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11505
0
        int valueMax = 1;
11506
#else
11507
        int valueMax = 10;
11508
#endif
11509
11510
  /* Allocate the value stack */
11511
0
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11512
0
  if (ctxt->valueTab == NULL) {
11513
0
      xmlXPathPErrMemory(ctxt);
11514
0
      return(-1);
11515
0
  }
11516
0
  ctxt->valueNr = 0;
11517
0
  ctxt->valueMax = valueMax;
11518
0
  ctxt->value = NULL;
11519
0
    }
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
11.6k
    comp = ctxt->comp;
11553
11.6k
    if (comp->last < 0) {
11554
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11555
0
  return(-1);
11556
0
    }
11557
11.6k
    oldDepth = ctxt->context->depth;
11558
11.6k
    if (toBool)
11559
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11560
0
      &comp->steps[comp->last], 0));
11561
11.6k
    else
11562
11.6k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11563
11.6k
    ctxt->context->depth = oldDepth;
11564
11565
11.6k
    return(0);
11566
11.6k
}
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
0
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11590
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
11591
0
    switch (res->type) {
11592
0
        case XPATH_BOOLEAN:
11593
0
      return(res->boolval);
11594
0
        case XPATH_NUMBER:
11595
0
      return(res->floatval == ctxt->proximityPosition);
11596
0
        case XPATH_NODESET:
11597
0
        case XPATH_XSLT_TREE:
11598
0
      if (res->nodesetval == NULL)
11599
0
    return(0);
11600
0
      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
0
    }
11607
0
    return(0);
11608
0
}
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
1.05M
                                xmlXPathObject *res) {
11627
1.05M
    if ((ctxt == NULL) || (res == NULL)) return(0);
11628
1.05M
    switch (res->type) {
11629
0
        case XPATH_BOOLEAN:
11630
0
      return(res->boolval);
11631
477k
        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
477k
      return(res->floatval == ctxt->context->proximityPosition);
11637
0
#endif
11638
555k
        case XPATH_NODESET:
11639
555k
        case XPATH_XSLT_TREE:
11640
555k
      if (res->nodesetval == NULL)
11641
0
    return(0);
11642
555k
      return(res->nodesetval->nodeNr != 0);
11643
26.6k
        case XPATH_STRING:
11644
26.6k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11645
0
        default:
11646
0
      break;
11647
1.05M
    }
11648
0
    return(0);
11649
1.05M
}
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
282k
{
11741
282k
    xmlXPathCompExprPtr comp = pctxt->comp;
11742
282k
    xmlXPathContextPtr ctxt;
11743
11744
    /*
11745
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11746
    * internal representation.
11747
    */
11748
11749
282k
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11750
74.8k
        (op->ch1 != -1) &&
11751
74.8k
        (op->ch2 == -1 /* no predicate */))
11752
65.3k
    {
11753
65.3k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11754
11755
65.3k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11756
15.1k
            ((xmlXPathAxisVal) prevop->value ==
11757
15.1k
                AXIS_DESCENDANT_OR_SELF) &&
11758
7.89k
            (prevop->ch2 == -1) &&
11759
7.77k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11760
7.71k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11761
7.51k
        {
11762
            /*
11763
            * This is a "descendant-or-self::node()" without predicates.
11764
            * Try to eliminate it.
11765
            */
11766
11767
7.51k
            switch ((xmlXPathAxisVal) op->value) {
11768
5.19k
                case AXIS_CHILD:
11769
5.19k
                case AXIS_DESCENDANT:
11770
                    /*
11771
                    * Convert "descendant-or-self::node()/child::" or
11772
                    * "descendant-or-self::node()/descendant::" to
11773
                    * "descendant::"
11774
                    */
11775
5.19k
                    op->ch1   = prevop->ch1;
11776
5.19k
                    op->value = AXIS_DESCENDANT;
11777
5.19k
                    break;
11778
1
                case AXIS_SELF:
11779
389
                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
389
                    op->ch1   = prevop->ch1;
11786
389
                    op->value = AXIS_DESCENDANT_OR_SELF;
11787
389
                    break;
11788
1.93k
                default:
11789
1.93k
                    break;
11790
7.51k
            }
11791
7.51k
  }
11792
65.3k
    }
11793
11794
    /* OP_VALUE has invalid ch1. */
11795
282k
    if (op->op == XPATH_OP_VALUE)
11796
10.5k
        return;
11797
11798
    /* Recurse */
11799
271k
    ctxt = pctxt->context;
11800
271k
    if (ctxt != NULL) {
11801
271k
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11802
109
            return;
11803
271k
        ctxt->depth += 1;
11804
271k
    }
11805
271k
    if (op->ch1 != -1)
11806
178k
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11807
271k
    if (op->ch2 != -1)
11808
91.4k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11809
271k
    if (ctxt != NULL)
11810
271k
        ctxt->depth -= 1;
11811
271k
}
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
0
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11823
0
    xmlXPathParserContextPtr pctxt;
11824
0
    xmlXPathContextPtr tmpctxt = NULL;
11825
0
    xmlXPathCompExprPtr comp;
11826
0
    int oldDepth = 0;
11827
11828
0
    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
0
    xmlInitParser();
11838
11839
    /*
11840
     * We need an xmlXPathContext for the depth check.
11841
     */
11842
0
    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
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
11850
0
    if (pctxt == NULL) {
11851
0
        if (tmpctxt != NULL)
11852
0
            xmlXPathFreeContext(tmpctxt);
11853
0
        return NULL;
11854
0
    }
11855
11856
0
    oldDepth = ctxt->depth;
11857
0
    xmlXPathCompileExpr(pctxt, 1);
11858
0
    ctxt->depth = oldDepth;
11859
11860
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
11861
0
    {
11862
0
        xmlXPathFreeParserContext(pctxt);
11863
0
        if (tmpctxt != NULL)
11864
0
            xmlXPathFreeContext(tmpctxt);
11865
0
        return(NULL);
11866
0
    }
11867
11868
0
    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
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11876
0
  comp = NULL;
11877
0
    } else {
11878
0
  comp = pctxt->comp;
11879
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11880
0
            if (ctxt != NULL)
11881
0
                oldDepth = ctxt->depth;
11882
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11883
0
            if (ctxt != NULL)
11884
0
                ctxt->depth = oldDepth;
11885
0
  }
11886
0
  pctxt->comp = NULL;
11887
0
    }
11888
0
    xmlXPathFreeParserContext(pctxt);
11889
0
    if (tmpctxt != NULL)
11890
0
        xmlXPathFreeContext(tmpctxt);
11891
11892
0
    if (comp != NULL) {
11893
0
  comp->expr = xmlStrdup(str);
11894
0
    }
11895
0
    return(comp);
11896
0
}
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
0
{
11927
0
    xmlXPathParserContextPtr pctxt;
11928
0
    xmlXPathObjectPtr resObj = NULL;
11929
0
    int res;
11930
11931
0
    if (comp == NULL)
11932
0
  return(-1);
11933
0
    xmlInitParser();
11934
11935
0
    xmlResetError(&ctxt->lastError);
11936
11937
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11938
0
    if (pctxt == NULL)
11939
0
        return(-1);
11940
0
    res = xmlXPathRunEval(pctxt, toBool);
11941
11942
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11943
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11944
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11945
0
        else if (!toBool)
11946
0
            resObj = xmlXPathValuePop(pctxt);
11947
0
    }
11948
11949
0
    if (resObjPtr)
11950
0
        *resObjPtr = resObj;
11951
0
    else
11952
0
        xmlXPathReleaseObject(ctxt, resObj);
11953
11954
0
    pctxt->comp = NULL;
11955
0
    xmlXPathFreeParserContext(pctxt);
11956
11957
0
    return(res);
11958
0
}
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
0
{
11971
0
    xmlXPathObjectPtr res = NULL;
11972
11973
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11974
0
    return(res);
11975
0
}
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
13.2k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
12003
#ifdef XPATH_STREAMING
12004
    xmlXPathCompExprPtr comp;
12005
#endif
12006
13.2k
    int oldDepth = 0;
12007
12008
13.2k
    if ((ctxt == NULL) || (ctxt->context == NULL))
12009
0
        return;
12010
13.2k
    if (ctxt->context->lastError.code != 0)
12011
320
        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
12.9k
    {
12027
12.9k
        if (ctxt->context != NULL)
12028
12.9k
            oldDepth = ctxt->context->depth;
12029
12.9k
  xmlXPathCompileExpr(ctxt, 1);
12030
12.9k
        if (ctxt->context != NULL)
12031
12.9k
            ctxt->context->depth = oldDepth;
12032
12.9k
        CHECK_ERROR;
12033
12034
        /* Check for trailing characters. */
12035
11.8k
        if (*ctxt->cur != 0)
12036
11.6k
            XP_ERROR(XPATH_EXPR_ERROR);
12037
12038
11.6k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12039
11.5k
            if (ctxt->context != NULL)
12040
11.5k
                oldDepth = ctxt->context->depth;
12041
11.5k
      xmlXPathOptimizeExpression(ctxt,
12042
11.5k
    &ctxt->comp->steps[ctxt->comp->last]);
12043
11.5k
            if (ctxt->context != NULL)
12044
11.5k
                ctxt->context->depth = oldDepth;
12045
11.5k
        }
12046
11.6k
    }
12047
12048
0
    xmlXPathRunEval(ctxt, 0);
12049
11.6k
}
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
0
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12061
0
    xmlXPathParserContextPtr ctxt;
12062
0
    xmlXPathObjectPtr res;
12063
12064
0
    if (ctx == NULL)
12065
0
        return(NULL);
12066
12067
0
    xmlInitParser();
12068
12069
0
    xmlResetError(&ctx->lastError);
12070
12071
0
    ctxt = xmlXPathNewParserContext(str, ctx);
12072
0
    if (ctxt == NULL)
12073
0
        return NULL;
12074
0
    xmlXPathEvalExpr(ctxt);
12075
12076
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12077
0
  res = NULL;
12078
0
    } else if (ctxt->valueNr != 1) {
12079
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12080
0
  res = NULL;
12081
0
    } else {
12082
0
  res = xmlXPathValuePop(ctxt);
12083
0
    }
12084
12085
0
    xmlXPathFreeParserContext(ctxt);
12086
0
    return(res);
12087
0
}
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
0
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12099
0
    if ((node == NULL) || (ctx == NULL))
12100
0
        return(-1);
12101
12102
0
    if (node->doc == ctx->doc) {
12103
0
        ctx->node = node;
12104
0
  return(0);
12105
0
    }
12106
0
    return(-1);
12107
0
}
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
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12138
0
    return(xmlXPathEval(str, ctxt));
12139
0
}
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 */