Coverage Report

Created: 2026-10-17 06:12

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
96.8k
#define XPATH_MAX_STEPS 1000000
89
90
/*
91
 * when evaluating an XPath expression we arbitrary limit the maximum
92
 * number of object allowed to be pushed on the stack. 1000000 is
93
 * an insanely large value which should never be reached under normal
94
 * circumstances
95
 */
96
24.8k
#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
36.0M
#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
40.3M
#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
28
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
4.51k
#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
4.28k
xmlXPathSFComputeHash(const xmlChar *name) {
187
4.28k
    unsigned hashValue = 5381;
188
4.28k
    const xmlChar *ptr;
189
190
27.7k
    for (ptr = name; *ptr; ptr++)
191
23.5k
        hashValue = hashValue * 33 + *ptr;
192
193
4.28k
    return(hashValue);
194
4.28k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
1
xmlInitXPathInternal(void) {
202
1
    size_t i;
203
204
1
#if defined(NAN) && defined(INFINITY)
205
1
    xmlXPathNAN = NAN;
206
1
    xmlXPathPINF = INFINITY;
207
1
    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
65
    for (i = 0; i < SF_HASH_SIZE; i++)
221
64
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
28
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
27
        const char *name = xmlXPathStandardFunctions[i].name;
225
27
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
34
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
7
            bucketIndex += 1;
229
7
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
7
        }
232
233
27
        xmlXPathSFHash[bucketIndex] = i;
234
27
    }
235
1
}
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
756k
xmlXPathIsNaN(double val) {
251
756k
#ifdef isnan
252
756k
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
756k
}
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
163k
xmlXPathIsInf(double val) {
266
163k
#ifdef isinf
267
163k
    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
163k
}
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
334M
#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
246M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
246M
    int depth1, depth2;
311
246M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
246M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
246M
    xmlNodePtr cur, root;
314
246M
    XML_INTPTR_T l1, l2;
315
316
246M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
246M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
246M
    switch (node1->type) {
326
180M
  case XML_ELEMENT_NODE:
327
180M
      if (node2->type == XML_ELEMENT_NODE) {
328
169M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
17.3k
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
17.3k
        (node1->doc == node2->doc))
331
17.3k
    {
332
17.3k
        l1 = -XML_NODE_SORT_VALUE(node1);
333
17.3k
        l2 = -XML_NODE_SORT_VALUE(node2);
334
17.3k
        if (l1 < l2)
335
17.3k
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
169M
        goto turtle_comparison;
340
169M
      }
341
11.2M
      break;
342
57.5M
  case XML_ATTRIBUTE_NODE:
343
57.5M
      precedence1 = 1; /* element is owner */
344
57.5M
      miscNode1 = node1;
345
57.5M
      node1 = node1->parent;
346
57.5M
      misc = 1;
347
57.5M
      break;
348
7.45M
  case XML_TEXT_NODE:
349
7.46M
  case XML_CDATA_SECTION_NODE:
350
7.69M
  case XML_COMMENT_NODE:
351
7.97M
  case XML_PI_NODE: {
352
7.97M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
7.97M
      if (node1->prev != NULL) {
357
17.3M
    do {
358
17.3M
        node1 = node1->prev;
359
17.3M
        if (node1->type == XML_ELEMENT_NODE) {
360
5.83M
      precedence1 = 3; /* element in prev-sibl axis */
361
5.83M
      break;
362
5.83M
        }
363
11.5M
        if (node1->prev == NULL) {
364
211k
      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
211k
      node1 = node1->parent;
370
211k
      break;
371
211k
        }
372
11.5M
    } while (1);
373
6.04M
      } else {
374
1.93M
    precedence1 = 2; /* element is parent */
375
1.93M
    node1 = node1->parent;
376
1.93M
      }
377
7.97M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
7.97M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
7.97M
    node1 = miscNode1;
383
7.97M
    precedence1 = 0;
384
7.97M
      } else
385
0
    misc = 1;
386
7.97M
  }
387
7.97M
      break;
388
1.08M
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
1.08M
      return(1);
393
57.1k
  default:
394
57.1k
      break;
395
246M
    }
396
76.7M
    switch (node2->type) {
397
52.3M
  case XML_ELEMENT_NODE:
398
52.3M
      break;
399
14.6M
  case XML_ATTRIBUTE_NODE:
400
14.6M
      precedence2 = 1; /* element is owner */
401
14.6M
      miscNode2 = node2;
402
14.6M
      node2 = node2->parent;
403
14.6M
      misc = 1;
404
14.6M
      break;
405
8.66M
  case XML_TEXT_NODE:
406
8.67M
  case XML_CDATA_SECTION_NODE:
407
8.90M
  case XML_COMMENT_NODE:
408
9.23M
  case XML_PI_NODE: {
409
9.23M
      miscNode2 = node2;
410
9.23M
      if (node2->prev != NULL) {
411
18.2M
    do {
412
18.2M
        node2 = node2->prev;
413
18.2M
        if (node2->type == XML_ELEMENT_NODE) {
414
6.71M
      precedence2 = 3; /* element in prev-sibl axis */
415
6.71M
      break;
416
6.71M
        }
417
11.4M
        if (node2->prev == NULL) {
418
320k
      precedence2 = 2; /* element is parent */
419
320k
      node2 = node2->parent;
420
320k
      break;
421
320k
        }
422
11.4M
    } while (1);
423
7.03M
      } else {
424
2.20M
    precedence2 = 2; /* element is parent */
425
2.20M
    node2 = node2->parent;
426
2.20M
      }
427
9.23M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
9.23M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
9.23M
      {
430
9.23M
    node2 = miscNode2;
431
9.23M
    precedence2 = 0;
432
9.23M
      } else
433
0
    misc = 1;
434
9.23M
  }
435
9.23M
      break;
436
60.2k
  case XML_NAMESPACE_DECL:
437
60.2k
      return(1);
438
420k
  default:
439
420k
      break;
440
76.7M
    }
441
76.7M
    if (misc) {
442
63.4M
  if (node1 == node2) {
443
6.32M
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
1.91M
    cur = miscNode2->prev;
449
1.92M
    while (cur != NULL) {
450
1.90M
        if (cur == miscNode1)
451
1.89M
      return(1);
452
8.98k
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
8.98k
        cur = cur->prev;
455
8.98k
    }
456
26.8k
    return (-1);
457
4.40M
      } else {
458
    /*
459
    * Evaluate based on higher precedence wrt to the element.
460
    * TODO: This assumes attributes are sorted before content.
461
    *   Is this 100% correct?
462
    */
463
4.40M
    if (precedence1 < precedence2)
464
352k
        return(1);
465
4.05M
    else
466
4.05M
        return(-1);
467
4.40M
      }
468
6.32M
  }
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
57.1M
  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
57.1M
  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
57.1M
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
70.4M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
62.4M
  (node2->type == XML_ELEMENT_NODE) &&
501
55.5M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
559
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
559
  (node1->doc == node2->doc)) {
504
505
559
  l1 = -XML_NODE_SORT_VALUE(node1);
506
559
  l2 = -XML_NODE_SORT_VALUE(node2);
507
559
  if (l1 < l2)
508
559
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
239M
turtle_comparison:
514
515
239M
    if (node1 == node2->prev)
516
56.0M
  return(1);
517
183M
    if (node1 == node2->next)
518
4.91M
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
1.12G
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
969M
  if (cur->parent == node1)
524
22.4M
      return(1);
525
947M
  depth2++;
526
947M
    }
527
156M
    root = cur;
528
950M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
805M
  if (cur->parent == node2)
530
10.4M
      return(-1);
531
794M
  depth1++;
532
794M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
145M
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
216M
    while (depth1 > depth2) {
543
71.3M
  depth1--;
544
71.3M
  node1 = node1->parent;
545
71.3M
    }
546
335M
    while (depth2 > depth1) {
547
189M
  depth2--;
548
189M
  node2 = node2->parent;
549
189M
    }
550
160M
    while (node1->parent != node2->parent) {
551
15.0M
  node1 = node1->parent;
552
15.0M
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
15.0M
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
15.0M
    }
557
    /*
558
     * Find who's first.
559
     */
560
145M
    if (node1 == node2->prev)
561
9.70M
  return(1);
562
135M
    if (node1 == node2->next)
563
41.8M
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
94.0M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
93.2M
  (node2->type == XML_ELEMENT_NODE) &&
569
92.7M
  (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
8.17G
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
8.12G
  if (cur == node2)
583
45.2M
      return(1);
584
48.7M
    return(-1); /* assume there is no sibling list corruption */
585
94.0M
}
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
21.1M
#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
246M
    {
607
246M
        int res = xmlXPathCmpNodesExt(x, y);
608
246M
        return res == -2 ? res : -res;
609
246M
    }
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
246M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
618
#include "timsort.h"
619
#endif /* WITH_TIM_SORT */
620
621
/************************************************************************
622
 *                  *
623
 *      Error handling routines       *
624
 *                  *
625
 ************************************************************************/
626
627
/**
628
 * Macro to raise an XPath error and return NULL.
629
 *
630
 * @param X  the error code
631
 */
632
#define XP_ERRORNULL(X)             \
633
3.06k
    { 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
16.7k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
16.7k
       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
21
{
678
21
    if (ctxt == NULL)
679
0
        return;
680
21
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
21
                        &ctxt->lastError);
682
21
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
21
{
692
21
    if (ctxt == NULL)
693
0
        return;
694
21
    ctxt->error = XPATH_MEMORY_ERROR;
695
21
    xmlXPathErrMemory(ctxt->context);
696
21
}
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
16.7k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
16.7k
    va_list ap;
709
16.7k
    xmlStructuredErrorFunc schannel = NULL;
710
16.7k
    xmlGenericErrorFunc channel = NULL;
711
16.7k
    void *data = NULL;
712
16.7k
    xmlNodePtr node = NULL;
713
16.7k
    int res;
714
715
16.7k
    if (ctxt == NULL)
716
0
        return;
717
16.7k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
16.7k
    if (ctxt->error != 0)
721
2.14k
        return;
722
723
14.5k
    ctxt->error = code;
724
725
14.5k
    if (ctxt->context != NULL) {
726
14.5k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
14.5k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
14.5k
        xmlResetError(err);
734
735
14.5k
        err->domain = XML_FROM_XPATH;
736
14.5k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
14.5k
        err->level = XML_ERR_ERROR;
738
14.5k
        if (ctxt->base != NULL) {
739
14.5k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
14.5k
            if (err->str1 == NULL) {
741
0
                xmlXPathPErrMemory(ctxt);
742
0
                return;
743
0
            }
744
14.5k
        }
745
14.5k
        err->int1 = ctxt->cur - ctxt->base;
746
14.5k
        err->node = ctxt->context->debugNode;
747
748
14.5k
        schannel = ctxt->context->error;
749
14.5k
        data = ctxt->context->userData;
750
14.5k
        node = ctxt->context->debugNode;
751
14.5k
    }
752
753
14.5k
    if (schannel == NULL) {
754
14.5k
        channel = xmlGenericError;
755
14.5k
        data = xmlGenericErrorContext;
756
14.5k
    }
757
758
14.5k
    va_start(ap, fmt);
759
14.5k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
14.5k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
14.5k
                         XML_ERR_ERROR, NULL, 0,
762
14.5k
                         (const char *) ctxt->base, NULL, NULL,
763
14.5k
                         ctxt->cur - ctxt->base, 0,
764
14.5k
                         fmt, ap);
765
14.5k
    va_end(ap);
766
14.5k
    if (res < 0)
767
0
        xmlXPathPErrMemory(ctxt);
768
14.5k
}
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
16.3k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
16.3k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
16.3k
}
780
781
/**
782
 * Formats an error message.
783
 *
784
 * @param ctxt  the XPath Parser context
785
 * @param file  the file name
786
 * @param line  the line number
787
 * @param no  the error number
788
 */
789
void
790
xmlXPatherror(xmlXPathParserContext *ctxt, const char *file ATTRIBUTE_UNUSED,
791
5.05k
              int line ATTRIBUTE_UNUSED, int no) {
792
5.05k
    xmlXPathErr(ctxt, no);
793
5.05k
}
794
795
/**
796
 * Adds opCount to the running total of operations and returns -1 if the
797
 * operation limit is exceeded. Returns 0 otherwise.
798
 *
799
 * @param ctxt  the XPath Parser context
800
 * @param opCount  the number of operations to be added
801
 */
802
static int
803
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
0
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
0
    if ((opCount > xpctxt->opLimit) ||
807
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
0
        xpctxt->opCount = xpctxt->opLimit;
809
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
0
        return(-1);
811
0
    }
812
813
0
    xpctxt->opCount += opCount;
814
0
    return(0);
815
0
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
695M
    ((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
28.6k
xmlXPathNewCompExpr(void) {
941
28.6k
    xmlXPathCompExprPtr cur;
942
943
28.6k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
28.6k
    if (cur == NULL)
945
0
  return(NULL);
946
28.6k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
28.6k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
28.6k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
28.6k
    cur->nbStep = 0;
953
28.6k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
28.6k
                                     sizeof(xmlXPathStepOp));
955
28.6k
    if (cur->steps == NULL) {
956
0
  xmlFree(cur);
957
0
  return(NULL);
958
0
    }
959
28.6k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
28.6k
    cur->last = -1;
961
28.6k
    return(cur);
962
28.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
28.6k
{
972
28.6k
    xmlXPathStepOpPtr op;
973
28.6k
    int i;
974
975
28.6k
    if (comp == NULL)
976
0
        return;
977
28.6k
    if (comp->dict == NULL) {
978
16.0M
  for (i = 0; i < comp->nbStep; i++) {
979
16.0M
      op = &comp->steps[i];
980
16.0M
      if (op->value4 != NULL) {
981
30.5k
    if (op->op == XPATH_OP_VALUE)
982
16.7k
        xmlXPathFreeObject(op->value4);
983
13.8k
    else
984
13.8k
        xmlFree(op->value4);
985
30.5k
      }
986
16.0M
      if (op->value5 != NULL)
987
40.1k
    xmlFree(op->value5);
988
16.0M
  }
989
23.4k
    } else {
990
465k
  for (i = 0; i < comp->nbStep; i++) {
991
441k
      op = &comp->steps[i];
992
441k
      if (op->value4 != NULL) {
993
8.41k
    if (op->op == XPATH_OP_VALUE)
994
6.37k
        xmlXPathFreeObject(op->value4);
995
8.41k
      }
996
441k
  }
997
23.4k
        xmlDictFree(comp->dict);
998
23.4k
    }
999
28.6k
    if (comp->steps != NULL) {
1000
28.6k
        xmlFree(comp->steps);
1001
28.6k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
28.6k
    if (comp->expr != NULL) {
1008
10.5k
        xmlFree(comp->expr);
1009
10.5k
    }
1010
1011
28.6k
    xmlFree(comp);
1012
28.6k
}
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
16.4M
   int value2, int value3, void *value4, void *value5) {
1032
16.4M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
16.4M
    if (comp->nbStep >= comp->maxStep) {
1034
96.8k
  xmlXPathStepOp *real;
1035
96.8k
        int newSize;
1036
1037
96.8k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
96.8k
                                  10, XPATH_MAX_STEPS);
1039
96.8k
        if (newSize < 0) {
1040
21
      xmlXPathPErrMemory(ctxt);
1041
21
      return(-1);
1042
21
        }
1043
96.8k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
96.8k
  if (real == NULL) {
1045
0
      xmlXPathPErrMemory(ctxt);
1046
0
      return(-1);
1047
0
  }
1048
96.8k
  comp->steps = real;
1049
96.8k
  comp->maxStep = newSize;
1050
96.8k
    }
1051
16.4M
    comp->last = comp->nbStep;
1052
16.4M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
16.4M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
16.4M
    comp->steps[comp->nbStep].op = op;
1055
16.4M
    comp->steps[comp->nbStep].value = value;
1056
16.4M
    comp->steps[comp->nbStep].value2 = value2;
1057
16.4M
    comp->steps[comp->nbStep].value3 = value3;
1058
16.4M
    if ((comp->dict != NULL) &&
1059
441k
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
440k
   (op == XPATH_OP_COLLECT))) {
1061
149k
        if (value4 != NULL) {
1062
2.03k
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
2.03k
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
2.03k
      xmlFree(value4);
1065
2.03k
  } else
1066
147k
      comp->steps[comp->nbStep].value4 = NULL;
1067
149k
        if (value5 != NULL) {
1068
23.2k
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
23.2k
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
23.2k
      xmlFree(value5);
1071
23.2k
  } else
1072
126k
      comp->steps[comp->nbStep].value5 = NULL;
1073
16.3M
    } else {
1074
16.3M
  comp->steps[comp->nbStep].value4 = value4;
1075
16.3M
  comp->steps[comp->nbStep].value5 = value5;
1076
16.3M
    }
1077
16.4M
    comp->steps[comp->nbStep].cache = NULL;
1078
16.4M
    return(comp->nbStep++);
1079
16.4M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
5.44M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
5.44M
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
59.5k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
59.5k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
5.45M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
5.45M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
52.7k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
52.7k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
5.44M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
5.44M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
5.44M
      (val), (val2), 0 ,NULL ,NULL)
1097
1098
/************************************************************************
1099
 *                  *
1100
 *    XPath object cache structures       *
1101
 *                  *
1102
 ************************************************************************/
1103
1104
/* #define XP_DEFAULT_CACHE_ON */
1105
1106
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1107
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1108
struct _xmlXPathContextCache {
1109
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1110
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1111
    int numNodeset;
1112
    int maxNodeset;
1113
    int numMisc;
1114
    int maxMisc;
1115
};
1116
1117
/************************************************************************
1118
 *                  *
1119
 *    Debugging related functions       *
1120
 *                  *
1121
 ************************************************************************/
1122
1123
#ifdef LIBXML_DEBUG_ENABLED
1124
static void
1125
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1126
0
    int i;
1127
0
    char shift[100];
1128
1129
0
    for (i = 0;((i < depth) && (i < 25));i++)
1130
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
0
    if (cur == NULL) {
1133
0
  fprintf(output, "%s", shift);
1134
0
  fprintf(output, "Node is NULL !\n");
1135
0
  return;
1136
1137
0
    }
1138
1139
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1140
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1141
0
  fprintf(output, "%s", shift);
1142
0
  fprintf(output, " /\n");
1143
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1144
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1145
0
    else
1146
0
  xmlDebugDumpOneNode(output, cur, depth);
1147
0
}
1148
static void
1149
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1150
0
    xmlNodePtr tmp;
1151
0
    int i;
1152
0
    char shift[100];
1153
1154
0
    for (i = 0;((i < depth) && (i < 25));i++)
1155
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1156
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1157
0
    if (cur == NULL) {
1158
0
  fprintf(output, "%s", shift);
1159
0
  fprintf(output, "Node is NULL !\n");
1160
0
  return;
1161
1162
0
    }
1163
1164
0
    while (cur != NULL) {
1165
0
  tmp = cur;
1166
0
  cur = cur->next;
1167
0
  xmlDebugDumpOneNode(output, tmp, depth);
1168
0
    }
1169
0
}
1170
1171
static void
1172
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1173
0
    int i;
1174
0
    char shift[100];
1175
1176
0
    for (i = 0;((i < depth) && (i < 25));i++)
1177
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1178
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1179
1180
0
    if (cur == NULL) {
1181
0
  fprintf(output, "%s", shift);
1182
0
  fprintf(output, "NodeSet is NULL !\n");
1183
0
  return;
1184
1185
0
    }
1186
1187
0
    if (cur != NULL) {
1188
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1189
0
  for (i = 0;i < cur->nodeNr;i++) {
1190
0
      fprintf(output, "%s", shift);
1191
0
      fprintf(output, "%d", i + 1);
1192
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1193
0
  }
1194
0
    }
1195
0
}
1196
1197
static void
1198
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1199
0
    int i;
1200
0
    char shift[100];
1201
1202
0
    for (i = 0;((i < depth) && (i < 25));i++)
1203
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1204
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1205
1206
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1207
0
  fprintf(output, "%s", shift);
1208
0
  fprintf(output, "Value Tree is NULL !\n");
1209
0
  return;
1210
1211
0
    }
1212
1213
0
    fprintf(output, "%s", shift);
1214
0
    fprintf(output, "%d", i + 1);
1215
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1216
0
}
1217
1218
/**
1219
 * Dump the content of the object for debugging purposes
1220
 *
1221
 * @param output  the FILE * to dump the output
1222
 * @param cur  the object to inspect
1223
 * @param depth  indentation level
1224
 */
1225
void
1226
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1227
0
    int i;
1228
0
    char shift[100];
1229
1230
0
    if (output == NULL) return;
1231
1232
0
    for (i = 0;((i < depth) && (i < 25));i++)
1233
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
0
    fprintf(output, "%s", shift);
1238
1239
0
    if (cur == NULL) {
1240
0
        fprintf(output, "Object is empty (NULL)\n");
1241
0
  return;
1242
0
    }
1243
0
    switch(cur->type) {
1244
0
        case XPATH_UNDEFINED:
1245
0
      fprintf(output, "Object is uninitialized\n");
1246
0
      break;
1247
0
        case XPATH_NODESET:
1248
0
      fprintf(output, "Object is a Node Set :\n");
1249
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
0
      break;
1251
0
  case XPATH_XSLT_TREE:
1252
0
      fprintf(output, "Object is an XSLT value tree :\n");
1253
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
0
      break;
1255
0
        case XPATH_BOOLEAN:
1256
0
      fprintf(output, "Object is a Boolean : ");
1257
0
      if (cur->boolval) fprintf(output, "true\n");
1258
0
      else fprintf(output, "false\n");
1259
0
      break;
1260
0
        case XPATH_NUMBER:
1261
0
      switch (xmlXPathIsInf(cur->floatval)) {
1262
0
      case 1:
1263
0
    fprintf(output, "Object is a number : Infinity\n");
1264
0
    break;
1265
0
      case -1:
1266
0
    fprintf(output, "Object is a number : -Infinity\n");
1267
0
    break;
1268
0
      default:
1269
0
    if (xmlXPathIsNaN(cur->floatval)) {
1270
0
        fprintf(output, "Object is a number : NaN\n");
1271
0
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
0
        fprintf(output, "Object is a number : 0\n");
1274
0
    } else {
1275
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
0
    }
1277
0
      }
1278
0
      break;
1279
0
        case XPATH_STRING:
1280
0
      fprintf(output, "Object is a string : ");
1281
0
      xmlDebugDumpString(output, cur->stringval);
1282
0
      fprintf(output, "\n");
1283
0
      break;
1284
0
  case XPATH_USERS:
1285
0
      fprintf(output, "Object is user defined\n");
1286
0
      break;
1287
0
    }
1288
0
}
1289
1290
static void
1291
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1292
0
                       xmlXPathStepOpPtr op, int depth) {
1293
0
    int i;
1294
0
    char shift[100];
1295
1296
0
    for (i = 0;((i < depth) && (i < 25));i++)
1297
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1298
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300
0
    fprintf(output, "%s", shift);
1301
0
    if (op == NULL) {
1302
0
  fprintf(output, "Step is NULL\n");
1303
0
  return;
1304
0
    }
1305
0
    switch (op->op) {
1306
0
        case XPATH_OP_END:
1307
0
      fprintf(output, "END"); break;
1308
0
        case XPATH_OP_AND:
1309
0
      fprintf(output, "AND"); break;
1310
0
        case XPATH_OP_OR:
1311
0
      fprintf(output, "OR"); break;
1312
0
        case XPATH_OP_EQUAL:
1313
0
       if (op->value)
1314
0
     fprintf(output, "EQUAL =");
1315
0
       else
1316
0
     fprintf(output, "EQUAL !=");
1317
0
       break;
1318
0
        case XPATH_OP_CMP:
1319
0
       if (op->value)
1320
0
     fprintf(output, "CMP <");
1321
0
       else
1322
0
     fprintf(output, "CMP >");
1323
0
       if (!op->value2)
1324
0
     fprintf(output, "=");
1325
0
       break;
1326
0
        case XPATH_OP_PLUS:
1327
0
       if (op->value == 0)
1328
0
     fprintf(output, "PLUS -");
1329
0
       else if (op->value == 1)
1330
0
     fprintf(output, "PLUS +");
1331
0
       else if (op->value == 2)
1332
0
     fprintf(output, "PLUS unary -");
1333
0
       else if (op->value == 3)
1334
0
     fprintf(output, "PLUS unary - -");
1335
0
       break;
1336
0
        case XPATH_OP_MULT:
1337
0
       if (op->value == 0)
1338
0
     fprintf(output, "MULT *");
1339
0
       else if (op->value == 1)
1340
0
     fprintf(output, "MULT div");
1341
0
       else
1342
0
     fprintf(output, "MULT mod");
1343
0
       break;
1344
0
        case XPATH_OP_UNION:
1345
0
       fprintf(output, "UNION"); break;
1346
0
        case XPATH_OP_ROOT:
1347
0
       fprintf(output, "ROOT"); break;
1348
0
        case XPATH_OP_NODE:
1349
0
       fprintf(output, "NODE"); break;
1350
0
        case XPATH_OP_SORT:
1351
0
       fprintf(output, "SORT"); break;
1352
0
        case XPATH_OP_COLLECT: {
1353
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1354
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1355
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1356
0
      const xmlChar *prefix = op->value4;
1357
0
      const xmlChar *name = op->value5;
1358
1359
0
      fprintf(output, "COLLECT ");
1360
0
      switch (axis) {
1361
0
    case AXIS_ANCESTOR:
1362
0
        fprintf(output, " 'ancestors' "); break;
1363
0
    case AXIS_ANCESTOR_OR_SELF:
1364
0
        fprintf(output, " 'ancestors-or-self' "); break;
1365
0
    case AXIS_ATTRIBUTE:
1366
0
        fprintf(output, " 'attributes' "); break;
1367
0
    case AXIS_CHILD:
1368
0
        fprintf(output, " 'child' "); break;
1369
0
    case AXIS_DESCENDANT:
1370
0
        fprintf(output, " 'descendant' "); break;
1371
0
    case AXIS_DESCENDANT_OR_SELF:
1372
0
        fprintf(output, " 'descendant-or-self' "); break;
1373
0
    case AXIS_FOLLOWING:
1374
0
        fprintf(output, " 'following' "); break;
1375
0
    case AXIS_FOLLOWING_SIBLING:
1376
0
        fprintf(output, " 'following-siblings' "); break;
1377
0
    case AXIS_NAMESPACE:
1378
0
        fprintf(output, " 'namespace' "); break;
1379
0
    case AXIS_PARENT:
1380
0
        fprintf(output, " 'parent' "); break;
1381
0
    case AXIS_PRECEDING:
1382
0
        fprintf(output, " 'preceding' "); break;
1383
0
    case AXIS_PRECEDING_SIBLING:
1384
0
        fprintf(output, " 'preceding-sibling' "); break;
1385
0
    case AXIS_SELF:
1386
0
        fprintf(output, " 'self' "); break;
1387
0
      }
1388
0
      switch (test) {
1389
0
                case NODE_TEST_NONE:
1390
0
        fprintf(output, "'none' "); break;
1391
0
                case NODE_TEST_TYPE:
1392
0
        fprintf(output, "'type' "); break;
1393
0
                case NODE_TEST_PI:
1394
0
        fprintf(output, "'PI' "); break;
1395
0
                case NODE_TEST_ALL:
1396
0
        fprintf(output, "'all' "); break;
1397
0
                case NODE_TEST_NS:
1398
0
        fprintf(output, "'namespace' "); break;
1399
0
                case NODE_TEST_NAME:
1400
0
        fprintf(output, "'name' "); break;
1401
0
      }
1402
0
      switch (type) {
1403
0
                case NODE_TYPE_NODE:
1404
0
        fprintf(output, "'node' "); break;
1405
0
                case NODE_TYPE_COMMENT:
1406
0
        fprintf(output, "'comment' "); break;
1407
0
                case NODE_TYPE_TEXT:
1408
0
        fprintf(output, "'text' "); break;
1409
0
                case NODE_TYPE_PI:
1410
0
        fprintf(output, "'PI' "); break;
1411
0
      }
1412
0
      if (prefix != NULL)
1413
0
    fprintf(output, "%s:", prefix);
1414
0
      if (name != NULL)
1415
0
    fprintf(output, "%s", (const char *) name);
1416
0
      break;
1417
1418
0
        }
1419
0
  case XPATH_OP_VALUE: {
1420
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1421
1422
0
      fprintf(output, "ELEM ");
1423
0
      xmlXPathDebugDumpObject(output, object, 0);
1424
0
      goto finish;
1425
0
  }
1426
0
  case XPATH_OP_VARIABLE: {
1427
0
      const xmlChar *prefix = op->value5;
1428
0
      const xmlChar *name = op->value4;
1429
1430
0
      if (prefix != NULL)
1431
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1432
0
      else
1433
0
    fprintf(output, "VARIABLE %s", name);
1434
0
      break;
1435
0
  }
1436
0
  case XPATH_OP_FUNCTION: {
1437
0
      int nbargs = op->value;
1438
0
      const xmlChar *prefix = op->value5;
1439
0
      const xmlChar *name = op->value4;
1440
1441
0
      if (prefix != NULL)
1442
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1443
0
      prefix, name, nbargs);
1444
0
      else
1445
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1446
0
      break;
1447
0
  }
1448
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1449
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1450
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1451
0
  default:
1452
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1453
0
    }
1454
0
    fprintf(output, "\n");
1455
0
finish:
1456
    /* OP_VALUE has invalid ch1. */
1457
0
    if (op->op == XPATH_OP_VALUE)
1458
0
        return;
1459
1460
0
    if (op->ch1 >= 0)
1461
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1462
0
    if (op->ch2 >= 0)
1463
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1464
0
}
1465
1466
/**
1467
 * Dumps the tree of the compiled XPath expression.
1468
 *
1469
 * @param output  the FILE * for the output
1470
 * @param comp  the precompiled XPath expression
1471
 * @param depth  the indentation level.
1472
 */
1473
void
1474
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExpr *comp,
1475
0
                    int depth) {
1476
0
    int i;
1477
0
    char shift[100];
1478
1479
0
    if ((output == NULL) || (comp == NULL)) return;
1480
1481
0
    for (i = 0;((i < depth) && (i < 25));i++)
1482
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1483
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1484
1485
0
    fprintf(output, "%s", shift);
1486
1487
#ifdef XPATH_STREAMING
1488
    if (comp->stream) {
1489
        fprintf(output, "Streaming Expression\n");
1490
    } else
1491
#endif
1492
0
    {
1493
0
        fprintf(output, "Compiled Expression : %d elements\n",
1494
0
                comp->nbStep);
1495
0
        i = comp->last;
1496
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1497
0
    }
1498
0
}
1499
1500
#endif /* LIBXML_DEBUG_ENABLED */
1501
1502
/************************************************************************
1503
 *                  *
1504
 *      XPath object caching        *
1505
 *                  *
1506
 ************************************************************************/
1507
1508
/**
1509
 * Create a new object cache
1510
 *
1511
 * @returns the xmlXPathCache just allocated.
1512
 */
1513
static xmlXPathContextCachePtr
1514
xmlXPathNewCache(void)
1515
9.98k
{
1516
9.98k
    xmlXPathContextCachePtr ret;
1517
1518
9.98k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
9.98k
    if (ret == NULL)
1520
0
  return(NULL);
1521
9.98k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
9.98k
    ret->maxNodeset = 100;
1523
9.98k
    ret->maxMisc = 100;
1524
9.98k
    return(ret);
1525
9.98k
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
905
{
1530
10.6k
    while (list != NULL) {
1531
9.76k
        xmlXPathObjectPtr next;
1532
1533
9.76k
        next = (void *) list->stringval;
1534
1535
9.76k
  if (list->nodesetval != NULL) {
1536
9.61k
      if (list->nodesetval->nodeTab != NULL)
1537
7.48k
    xmlFree(list->nodesetval->nodeTab);
1538
9.61k
      xmlFree(list->nodesetval);
1539
9.61k
  }
1540
9.76k
  xmlFree(list);
1541
1542
9.76k
        list = next;
1543
9.76k
    }
1544
905
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
9.98k
{
1549
9.98k
    if (cache == NULL)
1550
0
  return;
1551
9.98k
    if (cache->nodesetObjs)
1552
818
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
9.98k
    if (cache->miscObjs)
1554
87
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
9.98k
    xmlFree(cache);
1556
9.98k
}
1557
1558
/**
1559
 * Creates/frees an object cache on the XPath context.
1560
 * If activates XPath objects (xmlXPathObject) will be cached internally
1561
 * to be reused.
1562
 *
1563
 * `options` must be set to 0 to enable XPath object caching.
1564
 * Other values for `options` have currently no effect.
1565
 *
1566
 * `value` sets the maximum number of XPath objects to be cached per slot.
1567
 * There are two slots for node-set and misc objects.
1568
 * Use <0 for the default number (100).
1569
 *
1570
 * @param ctxt  the XPath context
1571
 * @param active  enables/disables (creates/frees) the cache
1572
 * @param value  a value with semantics dependent on `options`
1573
 * @param options  options (currently only the value 0 is used)
1574
 * @returns 0 if the setting succeeded, and -1 on API or internal errors.
1575
 */
1576
int
1577
xmlXPathContextSetCache(xmlXPathContext *ctxt,
1578
      int active,
1579
      int value,
1580
      int options)
1581
9.98k
{
1582
9.98k
    if (ctxt == NULL)
1583
0
  return(-1);
1584
9.98k
    if (active) {
1585
9.98k
  xmlXPathContextCachePtr cache;
1586
1587
9.98k
  if (ctxt->cache == NULL) {
1588
9.98k
      ctxt->cache = xmlXPathNewCache();
1589
9.98k
      if (ctxt->cache == NULL) {
1590
0
                xmlXPathErrMemory(ctxt);
1591
0
    return(-1);
1592
0
            }
1593
9.98k
  }
1594
9.98k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
9.98k
  if (options == 0) {
1596
9.98k
      if (value < 0)
1597
9.98k
    value = 100;
1598
9.98k
      cache->maxNodeset = value;
1599
9.98k
      cache->maxMisc = value;
1600
9.98k
  }
1601
9.98k
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
9.98k
    return(0);
1606
9.98k
}
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
10.1M
{
1621
10.1M
    xmlXPathObjectPtr ret;
1622
10.1M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
10.1M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
525k
  xmlXPathContextCachePtr cache =
1626
525k
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
525k
  if (cache->miscObjs != NULL) {
1629
31.0k
      ret = cache->miscObjs;
1630
31.0k
            cache->miscObjs = (void *) ret->stringval;
1631
31.0k
            cache->numMisc -= 1;
1632
31.0k
            ret->stringval = NULL;
1633
31.0k
      ret->type = XPATH_NODESET;
1634
31.0k
      ret->nodesetval = val;
1635
31.0k
      return(ret);
1636
31.0k
  }
1637
525k
    }
1638
1639
10.1M
    ret = xmlXPathWrapNodeSet(val);
1640
10.1M
    if (ret == NULL)
1641
0
        xmlXPathPErrMemory(pctxt);
1642
10.1M
    return(ret);
1643
10.1M
}
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
0
{
1656
0
    xmlXPathObjectPtr ret;
1657
0
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
0
  if (cache->miscObjs != NULL) {
1663
0
      ret = cache->miscObjs;
1664
0
            cache->miscObjs = (void *) ret->stringval;
1665
0
            cache->numMisc -= 1;
1666
0
      ret->type = XPATH_STRING;
1667
0
      ret->stringval = val;
1668
0
      return(ret);
1669
0
  }
1670
0
    }
1671
1672
0
    ret = xmlXPathWrapString(val);
1673
0
    if (ret == NULL)
1674
0
        xmlXPathPErrMemory(pctxt);
1675
0
    return(ret);
1676
0
}
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
9.84M
{
1690
9.84M
    xmlXPathObjectPtr ret;
1691
9.84M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
9.84M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
538k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
538k
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
537k
      ret = cache->nodesetObjs;
1701
537k
            cache->nodesetObjs = (void *) ret->stringval;
1702
537k
            cache->numNodeset -= 1;
1703
537k
            ret->stringval = NULL;
1704
537k
      ret->type = XPATH_NODESET;
1705
537k
      ret->boolval = 0;
1706
537k
      if (val) {
1707
537k
    if ((ret->nodesetval->nodeMax == 0) ||
1708
535k
        (val->type == XML_NAMESPACE_DECL))
1709
2.63k
    {
1710
2.63k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
0
                        xmlXPathPErrMemory(pctxt);
1712
535k
    } else {
1713
535k
        ret->nodesetval->nodeTab[0] = val;
1714
535k
        ret->nodesetval->nodeNr = 1;
1715
535k
    }
1716
537k
      }
1717
537k
      return(ret);
1718
537k
  } else if (cache->miscObjs != NULL) {
1719
0
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
0
      set = xmlXPathNodeSetCreate(val);
1725
0
      if (set == NULL) {
1726
0
                xmlXPathPErrMemory(pctxt);
1727
0
    return(NULL);
1728
0
      }
1729
1730
0
      ret = cache->miscObjs;
1731
0
            cache->miscObjs = (void *) ret->stringval;
1732
0
            cache->numMisc -= 1;
1733
0
            ret->stringval = NULL;
1734
0
      ret->type = XPATH_NODESET;
1735
0
      ret->boolval = 0;
1736
0
      ret->nodesetval = set;
1737
0
      return(ret);
1738
0
  }
1739
538k
    }
1740
9.30M
    ret = xmlXPathNewNodeSet(val);
1741
9.30M
    if (ret == NULL)
1742
0
        xmlXPathPErrMemory(pctxt);
1743
9.30M
    return(ret);
1744
9.84M
}
1745
1746
/**
1747
 * This is the cached version of #xmlXPathNewString.
1748
 * Acquire an xmlXPathObject of type string and of value `val`
1749
 *
1750
 * @param pctxt  the XPath context
1751
 * @param val  the xmlChar * value
1752
 * @returns the created or reused object.
1753
 */
1754
static xmlXPathObjectPtr
1755
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1756
173k
{
1757
173k
    xmlXPathObjectPtr ret;
1758
173k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
173k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
15.6k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
15.6k
  if (cache->miscObjs != NULL) {
1764
3.02k
            xmlChar *copy;
1765
1766
3.02k
            if (val == NULL)
1767
0
                val = BAD_CAST "";
1768
3.02k
            copy = xmlStrdup(val);
1769
3.02k
            if (copy == NULL) {
1770
0
                xmlXPathPErrMemory(pctxt);
1771
0
                return(NULL);
1772
0
            }
1773
1774
3.02k
      ret = cache->miscObjs;
1775
3.02k
            cache->miscObjs = (void *) ret->stringval;
1776
3.02k
            cache->numMisc -= 1;
1777
3.02k
      ret->type = XPATH_STRING;
1778
3.02k
            ret->stringval = copy;
1779
3.02k
      return(ret);
1780
3.02k
  }
1781
15.6k
    }
1782
1783
170k
    ret = xmlXPathNewString(val);
1784
170k
    if (ret == NULL)
1785
0
        xmlXPathPErrMemory(pctxt);
1786
170k
    return(ret);
1787
173k
}
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
0
{
1800
0
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
0
}
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
2.30M
{
1814
2.30M
    xmlXPathObjectPtr ret;
1815
2.30M
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
2.30M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
19.3k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
19.3k
  if (cache->miscObjs != NULL) {
1821
17.2k
      ret = cache->miscObjs;
1822
17.2k
            cache->miscObjs = (void *) ret->stringval;
1823
17.2k
            cache->numMisc -= 1;
1824
17.2k
            ret->stringval = NULL;
1825
17.2k
      ret->type = XPATH_BOOLEAN;
1826
17.2k
      ret->boolval = (val != 0);
1827
17.2k
      return(ret);
1828
17.2k
  }
1829
19.3k
    }
1830
1831
2.28M
    ret = xmlXPathNewBoolean(val);
1832
2.28M
    if (ret == NULL)
1833
0
        xmlXPathPErrMemory(pctxt);
1834
2.28M
    return(ret);
1835
2.30M
}
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.46M
{
1848
1.46M
    xmlXPathObjectPtr ret;
1849
1.46M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
1.46M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
11.5k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
11.5k
  if (cache->miscObjs != NULL) {
1855
4.99k
      ret = cache->miscObjs;
1856
4.99k
            cache->miscObjs = (void *) ret->stringval;
1857
4.99k
            cache->numMisc -= 1;
1858
4.99k
            ret->stringval = NULL;
1859
4.99k
      ret->type = XPATH_NUMBER;
1860
4.99k
      ret->floatval = val;
1861
4.99k
      return(ret);
1862
4.99k
  }
1863
11.5k
    }
1864
1865
1.46M
    ret = xmlXPathNewFloat(val);
1866
1.46M
    if (ret == NULL)
1867
0
        xmlXPathPErrMemory(pctxt);
1868
1.46M
    return(ret);
1869
1.46M
}
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
708k
{
1882
708k
    xmlXPathObjectPtr ret;
1883
708k
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
708k
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
708k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
2.02k
  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
126
      case XPATH_STRING:
1901
126
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
1.89k
      case XPATH_NUMBER:
1905
1.89k
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
2.02k
  }
1909
2.02k
    }
1910
706k
    ret = xmlXPathObjectCopy(val);
1911
706k
    if (ret == NULL)
1912
0
        xmlXPathPErrMemory(pctxt);
1913
706k
    return(ret);
1914
708k
}
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
7.99M
                             xmlXPathObjectPtr val) {
1932
7.99M
    double ret = 0.0;
1933
1934
7.99M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
7.99M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
6.94M
    case XPATH_NODESET:
1941
6.94M
    case XPATH_XSLT_TREE: {
1942
6.94M
        xmlChar *str;
1943
1944
6.94M
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
6.94M
        if (str == NULL) {
1946
0
            xmlXPathPErrMemory(ctxt);
1947
0
            ret = xmlXPathNAN;
1948
6.94M
        } else {
1949
6.94M
      ret = xmlXPathCastStringToNumber(str);
1950
6.94M
            xmlFree(str);
1951
6.94M
        }
1952
6.94M
  break;
1953
6.94M
    }
1954
482k
    case XPATH_STRING:
1955
482k
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
482k
  break;
1957
380k
    case XPATH_NUMBER:
1958
380k
  ret = val->floatval;
1959
380k
  break;
1960
180k
    case XPATH_BOOLEAN:
1961
180k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
180k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
7.99M
    }
1968
7.99M
    return(ret);
1969
7.99M
}
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
26.3M
{
1980
26.3M
    xmlXPathObjectPtr ret;
1981
1982
26.3M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
1.38k
        return (NULL);
1984
1985
26.3M
    ctxt->valueNr--;
1986
26.3M
    if (ctxt->valueNr > 0)
1987
20.3M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
6.01M
    else
1989
6.01M
        ctxt->value = NULL;
1990
26.3M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
26.3M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
26.3M
    return (ret);
1993
26.3M
}
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
26.3M
{
2008
26.3M
    if (ctxt == NULL) return(-1);
2009
26.3M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
0
        xmlXPathPErrMemory(ctxt);
2014
0
        return(-1);
2015
0
    }
2016
26.3M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
24.8k
        xmlXPathObjectPtr *tmp;
2018
24.8k
        int newSize;
2019
2020
24.8k
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
24.8k
                                  10, XPATH_MAX_STACK_DEPTH);
2022
24.8k
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
24.8k
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
24.8k
        if (tmp == NULL) {
2029
0
            xmlXPathPErrMemory(ctxt);
2030
0
            xmlXPathFreeObject(value);
2031
0
            return (-1);
2032
0
        }
2033
24.8k
  ctxt->valueTab = tmp;
2034
24.8k
        ctxt->valueMax = newSize;
2035
24.8k
    }
2036
26.3M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
26.3M
    ctxt->value = value;
2038
26.3M
    return (ctxt->valueNr++);
2039
26.3M
}
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
120M
#define CUR (*ctxt->cur)
2194
41.6k
#define SKIP(val) ctxt->cur += (val)
2195
4.21M
#define NXT(val) ctxt->cur[(val)]
2196
5.65M
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
66.2M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
61.3M
#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
0
#define UPPER_DOUBLE 1E9
2213
0
#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
0
#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
0
{
2230
0
    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
0
    default:
2240
0
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
0
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
0
                   (number == (int) number)) {
2248
0
      char work[30];
2249
0
      char *ptr, *cur;
2250
0
      int value = (int) number;
2251
2252
0
            ptr = &buffer[0];
2253
0
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
0
      } else {
2256
0
    snprintf(work, 29, "%d", value);
2257
0
    cur = &work[0];
2258
0
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
0
        *ptr++ = *cur++;
2260
0
    }
2261
0
      }
2262
0
      if (ptr - buffer < buffersize) {
2263
0
    *ptr = 0;
2264
0
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
0
  } 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
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
0
      int integer_place, fraction_place;
2280
0
      char *ptr;
2281
0
      char *after_fraction;
2282
0
      double absolute_value;
2283
0
      int size;
2284
2285
0
      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
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
0
      (absolute_value < LOWER_DOUBLE)) &&
2294
0
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
0
    fraction_place = DBL_DIG - 1;
2298
0
    size = snprintf(work, sizeof(work),"%*.*e",
2299
0
       integer_place, fraction_place, number);
2300
0
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
0
      }
2303
0
      else {
2304
    /* Use regular notation */
2305
0
    if (absolute_value > 0.0) {
2306
0
        integer_place = (int)log10(absolute_value);
2307
0
        if (integer_place > 0)
2308
0
            fraction_place = DBL_DIG - integer_place - 1;
2309
0
        else
2310
0
            fraction_place = DBL_DIG - integer_place;
2311
0
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
0
    size = snprintf(work, sizeof(work), "%0.*f",
2315
0
        fraction_place, number);
2316
0
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
0
      while (work[0] == ' ') {
2320
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
0
    size--;
2322
0
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
0
      after_fraction = work + size;
2326
0
      ptr = after_fraction;
2327
0
      while (*(--ptr) == '0')
2328
0
    ;
2329
0
      if (*ptr != '.')
2330
0
          ptr++;
2331
0
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
0
      size = strlen(work) + 1;
2335
0
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
0
      memmove(buffer, work, size);
2340
0
  }
2341
0
  break;
2342
0
    }
2343
0
}
2344
2345
2346
/************************************************************************
2347
 *                  *
2348
 *      Routines to handle NodeSets     *
2349
 *                  *
2350
 ************************************************************************/
2351
2352
/**
2353
 * Call this routine to speed up XPath computation on static documents.
2354
 * This stamps all the element nodes with the document order
2355
 * Like for line information, the order is kept in the element->content
2356
 * field, the value stored is actually - the node number (starting at -1)
2357
 * to be able to differentiate from line numbers.
2358
 *
2359
 * @param doc  an input document
2360
 * @returns the number of elements found in the document or -1 in case
2361
 *    of error.
2362
 */
2363
long
2364
2.16k
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
2.16k
    XML_INTPTR_T count = 0;
2366
2.16k
    xmlNodePtr cur;
2367
2368
2.16k
    if (doc == NULL)
2369
0
  return(-1);
2370
2.16k
    cur = doc->children;
2371
415k
    while (cur != NULL) {
2372
413k
  if (cur->type == XML_ELEMENT_NODE) {
2373
199k
            count += 1;
2374
199k
            cur->content = XML_INT_TO_PTR(-count);
2375
199k
      if (cur->children != NULL) {
2376
85.4k
    cur = cur->children;
2377
85.4k
    continue;
2378
85.4k
      }
2379
199k
  }
2380
328k
  if (cur->next != NULL) {
2381
271k
      cur = cur->next;
2382
271k
      continue;
2383
271k
  }
2384
87.6k
  do {
2385
87.6k
      cur = cur->parent;
2386
87.6k
      if (cur == NULL)
2387
0
    break;
2388
87.6k
      if (cur == (xmlNodePtr) doc) {
2389
2.16k
    cur = NULL;
2390
2.16k
    break;
2391
2.16k
      }
2392
85.4k
      if (cur->next != NULL) {
2393
54.8k
    cur = cur->next;
2394
54.8k
    break;
2395
54.8k
      }
2396
85.4k
  } while (cur != NULL);
2397
57.0k
    }
2398
2.16k
    return(count);
2399
2.16k
}
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
560k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
560k
    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
560k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
560k
#endif /* WITH_TIM_SORT */
2591
560k
}
2592
2593
64.1M
#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
5.60M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
5.60M
    xmlNsPtr cur;
2606
2607
5.60M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
5.60M
    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
5.60M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
5.60M
    if (cur == NULL)
2617
0
  return(NULL);
2618
5.60M
    memset(cur, 0, sizeof(xmlNs));
2619
5.60M
    cur->type = XML_NAMESPACE_DECL;
2620
5.60M
    if (ns->href != NULL) {
2621
5.60M
  cur->href = xmlStrdup(ns->href);
2622
5.60M
        if (cur->href == NULL) {
2623
0
            xmlFree(cur);
2624
0
            return(NULL);
2625
0
        }
2626
5.60M
    }
2627
5.60M
    if (ns->prefix != NULL) {
2628
5.06M
  cur->prefix = xmlStrdup(ns->prefix);
2629
5.06M
        if (cur->prefix == NULL) {
2630
0
            xmlFree((xmlChar *) cur->href);
2631
0
            xmlFree(cur);
2632
0
            return(NULL);
2633
0
        }
2634
5.06M
    }
2635
5.60M
    cur->next = (xmlNsPtr) node;
2636
5.60M
    return((xmlNodePtr) cur);
2637
5.60M
}
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
5.60M
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
5.60M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
5.60M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
5.60M
  if (ns->href != NULL)
2653
5.60M
      xmlFree((xmlChar *)ns->href);
2654
5.60M
  if (ns->prefix != NULL)
2655
5.06M
      xmlFree((xmlChar *)ns->prefix);
2656
5.60M
  xmlFree(ns);
2657
5.60M
    }
2658
5.60M
}
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
37.8M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
37.8M
    xmlNodeSetPtr ret;
2669
2670
37.8M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
37.8M
    if (ret == NULL)
2672
0
  return(NULL);
2673
37.8M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
37.8M
    if (val != NULL) {
2675
9.30M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
9.30M
               sizeof(xmlNodePtr));
2677
9.30M
  if (ret->nodeTab == NULL) {
2678
0
      xmlFree(ret);
2679
0
      return(NULL);
2680
0
  }
2681
9.30M
  memset(ret->nodeTab, 0 ,
2682
9.30M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
9.30M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
9.30M
  if (val->type == XML_NAMESPACE_DECL) {
2685
4.02M
      xmlNsPtr ns = (xmlNsPtr) val;
2686
4.02M
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
4.02M
            if (nsNode == NULL) {
2689
0
                xmlXPathFreeNodeSet(ret);
2690
0
                return(NULL);
2691
0
            }
2692
4.02M
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
4.02M
  } else
2694
5.28M
      ret->nodeTab[ret->nodeNr++] = val;
2695
9.30M
    }
2696
37.8M
    return(ret);
2697
37.8M
}
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
116M
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
116M
    int i;
2709
2710
116M
    if ((cur == NULL) || (val == NULL)) return(0);
2711
116M
    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
116M
    } else {
2726
884M
  for (i = 0; i < cur->nodeNr; i++) {
2727
787M
      if (cur->nodeTab[i] == val)
2728
19.2M
    return(1);
2729
787M
  }
2730
116M
    }
2731
97.2M
    return(0);
2732
116M
}
2733
2734
static int
2735
36.0M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
36.0M
    xmlNodePtr *temp;
2737
36.0M
    int newSize;
2738
2739
36.0M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
36.0M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
36.0M
    if (newSize < 0)
2742
0
        return(-1);
2743
36.0M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
36.0M
    if (temp == NULL)
2745
0
        return(-1);
2746
36.0M
    cur->nodeMax = newSize;
2747
36.0M
    cur->nodeTab = temp;
2748
2749
36.0M
    return(0);
2750
36.0M
}
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
774k
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
774k
    int i;
2763
774k
    xmlNodePtr nsNode;
2764
2765
774k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
774k
        (ns->type != XML_NAMESPACE_DECL) ||
2767
774k
  (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
1.49M
    for (i = 0;i < cur->nodeNr;i++) {
2775
723k
        if ((cur->nodeTab[i] != NULL) &&
2776
723k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
723k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
723k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
723k
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
774k
    if (cur->nodeNr >= cur->nodeMax) {
2786
13.2k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
0
            return(-1);
2788
13.2k
    }
2789
774k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
774k
    if(nsNode == NULL)
2791
0
        return(-1);
2792
774k
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
774k
    return(0);
2794
774k
}
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
37.4k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
37.4k
    int i;
2806
2807
37.4k
    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
775k
    for (i = 0;i < cur->nodeNr;i++)
2814
737k
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
37.4k
    if (cur->nodeNr >= cur->nodeMax) {
2820
34.6k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
0
            return(-1);
2822
34.6k
    }
2823
2824
37.4k
    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
37.4k
  cur->nodeTab[cur->nodeNr++] = val;
2833
37.4k
    return(0);
2834
37.4k
}
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
353M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
353M
    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
353M
    if (cur->nodeNr >= cur->nodeMax) {
2853
31.0M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
0
            return(-1);
2855
31.0M
    }
2856
2857
353M
    if (val->type == XML_NAMESPACE_DECL) {
2858
22.8k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
22.8k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
22.8k
        if (nsNode == NULL)
2862
0
            return(-1);
2863
22.8k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
22.8k
    } else
2865
353M
  cur->nodeTab[cur->nodeNr++] = val;
2866
353M
    return(0);
2867
353M
}
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
322k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
322k
    int i, j, initNr, skip;
2882
322k
    xmlNodePtr n1, n2;
2883
2884
322k
    if (val1 == NULL) {
2885
0
  val1 = xmlXPathNodeSetCreate(NULL);
2886
0
        if (val1 == NULL)
2887
0
            return (NULL);
2888
0
    }
2889
322k
    if (val2 == NULL)
2890
0
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
322k
    initNr = val1->nodeNr;
2894
2895
70.5M
    for (i = 0;i < val2->nodeNr;i++) {
2896
70.2M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
70.2M
  skip = 0;
2901
5.95G
  for (j = 0; j < initNr; j++) {
2902
5.88G
      n1 = val1->nodeTab[j];
2903
5.88G
      if (n1 == n2) {
2904
690k
    skip = 1;
2905
690k
    break;
2906
5.88G
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
252k
           (n2->type == XML_NAMESPACE_DECL)) {
2908
4.35k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
4.35k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
4.35k
      ((xmlNsPtr) n2)->prefix)))
2911
4.35k
    {
2912
4.35k
        skip = 1;
2913
4.35k
        break;
2914
4.35k
    }
2915
4.35k
      }
2916
5.88G
  }
2917
70.2M
  if (skip)
2918
694k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
69.5M
        if (val1->nodeNr >= val1->nodeMax) {
2924
1.72M
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
0
                goto error;
2926
1.72M
        }
2927
69.5M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
782k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
782k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
782k
            if (nsNode == NULL)
2932
0
                goto error;
2933
782k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
782k
  } else
2935
68.7M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
69.5M
    }
2937
2938
322k
    return(val1);
2939
2940
0
error:
2941
0
    xmlXPathFreeNodeSet(val1);
2942
0
    return(NULL);
2943
322k
}
2944
2945
2946
/**
2947
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
2948
 * Checks for duplicate nodes. Clears set2.
2949
 *
2950
 * Frees `set1` in case of error.
2951
 *
2952
 * @param set1  the first NodeSet or NULL
2953
 * @param set2  the second NodeSet
2954
 * @returns `set1` once extended or NULL in case of error.
2955
 */
2956
static xmlNodeSetPtr
2957
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2958
2.14M
{
2959
2.14M
    {
2960
2.14M
  int i, j, initNbSet1;
2961
2.14M
  xmlNodePtr n1, n2;
2962
2963
2.14M
  initNbSet1 = set1->nodeNr;
2964
18.4M
  for (i = 0;i < set2->nodeNr;i++) {
2965
16.2M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
1.67G
      for (j = 0; j < initNbSet1; j++) {
2970
1.67G
    n1 = set1->nodeTab[j];
2971
1.67G
    if (n1 == n2) {
2972
15.7M
        goto skip_node;
2973
1.65G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
0
        (n2->type == XML_NAMESPACE_DECL))
2975
0
    {
2976
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
0
      ((xmlNsPtr) n2)->prefix)))
2979
0
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
0
      goto skip_node;
2985
0
        }
2986
0
    }
2987
1.67G
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
484k
            if (set1->nodeNr >= set1->nodeMax) {
2992
102k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
0
                    goto error;
2994
102k
            }
2995
484k
      set1->nodeTab[set1->nodeNr++] = n2;
2996
16.2M
skip_node:
2997
16.2M
            set2->nodeTab[i] = NULL;
2998
16.2M
  }
2999
2.14M
    }
3000
2.14M
    set2->nodeNr = 0;
3001
2.14M
    return(set1);
3002
3003
0
error:
3004
0
    xmlXPathFreeNodeSet(set1);
3005
0
    xmlXPathNodeSetClear(set2, 1);
3006
0
    return(NULL);
3007
2.14M
}
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
12.4M
{
3022
12.4M
    {
3023
12.4M
  int i;
3024
12.4M
  xmlNodePtr n2;
3025
3026
80.3M
  for (i = 0;i < set2->nodeNr;i++) {
3027
67.9M
      n2 = set2->nodeTab[i];
3028
67.9M
            if (set1->nodeNr >= set1->nodeMax) {
3029
3.17M
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
0
                    goto error;
3031
3.17M
            }
3032
67.9M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
67.9M
            set2->nodeTab[i] = NULL;
3034
67.9M
  }
3035
12.4M
    }
3036
12.4M
    set2->nodeNr = 0;
3037
12.4M
    return(set1);
3038
3039
0
error:
3040
0
    xmlXPathFreeNodeSet(set1);
3041
0
    xmlXPathNodeSetClear(set2, 1);
3042
0
    return(NULL);
3043
12.4M
}
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
37.8M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
37.8M
    if (obj == NULL) return;
3103
37.8M
    if (obj->nodeTab != NULL) {
3104
17.7M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
433M
  for (i = 0;i < obj->nodeNr;i++)
3108
416M
      if ((obj->nodeTab[i] != NULL) &&
3109
416M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
5.13M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
17.7M
  xmlFree(obj->nodeTab);
3112
17.7M
    }
3113
37.8M
    xmlFree(obj);
3114
37.8M
}
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
2.34k
{
3128
2.34k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
2.34k
    else if ((hasNsNodes)) {
3131
0
  int i;
3132
0
  xmlNodePtr node;
3133
3134
0
  for (i = pos; i < set->nodeNr; i++) {
3135
0
      node = set->nodeTab[i];
3136
0
      if ((node != NULL) &&
3137
0
    (node->type == XML_NAMESPACE_DECL))
3138
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
0
  }
3140
0
    }
3141
2.34k
    set->nodeNr = pos;
3142
2.34k
}
3143
3144
/**
3145
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3146
 * are feed), but does *not* free the list itself. Sets the length of the
3147
 * list to 0.
3148
 *
3149
 * @param set  the node set to clear
3150
 * @param hasNsNodes  the node set might contain namespace nodes
3151
 */
3152
static void
3153
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3154
2.34k
{
3155
2.34k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
2.34k
}
3157
3158
/**
3159
 * Move the last node to the first position and clear temporary XPath objects
3160
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3161
 * to 1.
3162
 *
3163
 * @param set  the node set to be cleared
3164
 */
3165
static void
3166
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3167
0
{
3168
0
    int i;
3169
0
    xmlNodePtr node;
3170
3171
0
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
0
        node = set->nodeTab[i];
3175
0
        if ((node != NULL) &&
3176
0
            (node->type == XML_NAMESPACE_DECL))
3177
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
0
    }
3179
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
0
    set->nodeNr = 1;
3181
0
}
3182
3183
/**
3184
 * Create a new xmlXPathObject of type NodeSet and initialize
3185
 * it with the single Node `val`
3186
 *
3187
 * @param val  the NodePtr value
3188
 * @returns the newly created object.
3189
 */
3190
xmlXPathObject *
3191
9.30M
xmlXPathNewNodeSet(xmlNode *val) {
3192
9.30M
    xmlXPathObjectPtr ret;
3193
3194
9.30M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
9.30M
    if (ret == NULL)
3196
0
  return(NULL);
3197
9.30M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
9.30M
    ret->type = XPATH_NODESET;
3199
9.30M
    ret->boolval = 0;
3200
9.30M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
9.30M
    if (ret->nodesetval == NULL) {
3202
0
        xmlFree(ret);
3203
0
        return(NULL);
3204
0
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
9.30M
    return(ret);
3207
9.30M
}
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
10.1M
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
10.1M
    xmlXPathObjectPtr ret;
3269
3270
10.1M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
10.1M
    if (ret == NULL) {
3272
0
        xmlXPathFreeNodeSet(val);
3273
0
  return(NULL);
3274
0
    }
3275
10.1M
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
10.1M
    ret->type = XPATH_NODESET;
3277
10.1M
    ret->nodesetval = val;
3278
10.1M
    return(ret);
3279
10.1M
}
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
24.7k
         xmlXPathFunction f) {
3676
24.7k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
24.7k
}
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
24.7k
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
24.7k
    int ret;
3692
24.7k
    void *payload;
3693
3694
24.7k
    if (ctxt == NULL)
3695
0
  return(-1);
3696
24.7k
    if (name == NULL)
3697
0
  return(-1);
3698
3699
24.7k
    if (ctxt->funcHash == NULL)
3700
7.39k
  ctxt->funcHash = xmlHashCreate(0);
3701
24.7k
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
24.7k
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
24.7k
    memcpy(&payload, &f, sizeof(f));
3708
24.7k
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
24.7k
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
24.7k
    return(0);
3715
24.7k
}
3716
3717
/**
3718
 * Registers an external mechanism to do function lookup.
3719
 *
3720
 * @param ctxt  the XPath context
3721
 * @param f  the lookup function
3722
 * @param funcCtxt  the lookup data
3723
 */
3724
void
3725
xmlXPathRegisterFuncLookup (xmlXPathContext *ctxt,
3726
          xmlXPathFuncLookupFunc f,
3727
2.16k
          void *funcCtxt) {
3728
2.16k
    if (ctxt == NULL)
3729
0
  return;
3730
2.16k
    ctxt->funcLookupFunc = f;
3731
2.16k
    ctxt->funcLookupData = funcCtxt;
3732
2.16k
}
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
4.25k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
4.25k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
4.25k
}
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
4.25k
       const xmlChar *ns_uri) {
3759
4.25k
    xmlXPathFunction ret;
3760
4.25k
    void *payload;
3761
3762
4.25k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
4.25k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
4.25k
    if (ns_uri == NULL) {
3768
4.25k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
4.41k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
4.22k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
4.22k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
4.22k
                       (char *) name) == 0)
3775
4.05k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
165
            bucketIndex += 1;
3778
165
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
165
        }
3781
4.25k
    }
3782
3783
199
    if (ctxt->funcLookupFunc != NULL) {
3784
3
  xmlXPathFuncLookupFunc f;
3785
3786
3
  f = ctxt->funcLookupFunc;
3787
3
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
3
  if (ret != NULL)
3789
0
      return(ret);
3790
3
    }
3791
3792
199
    if (ctxt->funcHash == NULL)
3793
0
  return(NULL);
3794
3795
199
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
199
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
199
    return(ret);
3799
199
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
16.1k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
16.1k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
16.1k
    xmlHashFree(ctxt->funcHash, NULL);
3812
16.1k
    ctxt->funcHash = NULL;
3813
16.1k
}
3814
3815
/************************************************************************
3816
 *                  *
3817
 *      Routines to handle Variables      *
3818
 *                  *
3819
 ************************************************************************/
3820
3821
/**
3822
 * Register a new variable value. If `value` is NULL it unregisters
3823
 * the variable
3824
 *
3825
 * @param ctxt  the XPath context
3826
 * @param name  the variable name
3827
 * @param value  the variable value or NULL
3828
 * @returns 0 in case of success, -1 in case of error
3829
 */
3830
int
3831
xmlXPathRegisterVariable(xmlXPathContext *ctxt, const xmlChar *name,
3832
0
       xmlXPathObject *value) {
3833
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
0
}
3835
3836
/**
3837
 * Register a new variable value. If `value` is NULL it unregisters
3838
 * the variable
3839
 *
3840
 * @param ctxt  the XPath context
3841
 * @param name  the variable name
3842
 * @param ns_uri  the variable namespace URI
3843
 * @param value  the variable value or NULL
3844
 * @returns 0 in case of success, -1 in case of error
3845
 */
3846
int
3847
xmlXPathRegisterVariableNS(xmlXPathContext *ctxt, const xmlChar *name,
3848
         const xmlChar *ns_uri,
3849
0
         xmlXPathObject *value) {
3850
0
    if (ctxt == NULL)
3851
0
  return(-1);
3852
0
    if (name == NULL)
3853
0
  return(-1);
3854
3855
0
    if (ctxt->varHash == NULL)
3856
0
  ctxt->varHash = xmlHashCreate(0);
3857
0
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
0
    if (value == NULL)
3860
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
0
                             xmlXPathFreeObjectEntry));
3862
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
0
             (void *) value, xmlXPathFreeObjectEntry));
3864
0
}
3865
3866
/**
3867
 * register an external mechanism to do variable lookup
3868
 *
3869
 * @param ctxt  the XPath context
3870
 * @param f  the lookup function
3871
 * @param data  the lookup data
3872
 */
3873
void
3874
xmlXPathRegisterVariableLookup(xmlXPathContext *ctxt,
3875
2.16k
   xmlXPathVariableLookupFunc f, void *data) {
3876
2.16k
    if (ctxt == NULL)
3877
0
  return;
3878
2.16k
    ctxt->varLookupFunc = f;
3879
2.16k
    ctxt->varLookupData = data;
3880
2.16k
}
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
20
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
20
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
20
    if (ctxt->varLookupFunc != NULL) {
3896
5
  xmlXPathObjectPtr ret;
3897
3898
5
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3899
5
          (ctxt->varLookupData, name, NULL);
3900
5
  return(ret);
3901
5
    }
3902
15
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
20
}
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
17
       const xmlChar *ns_uri) {
3917
17
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
17
    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
17
    if (ctxt->varHash == NULL)
3929
17
  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
16.1k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
16.1k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
16.1k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
16.1k
    ctxt->varHash = NULL;
3948
16.1k
}
3949
3950
/**
3951
 * Register a new namespace. If `ns_uri` is NULL it unregisters
3952
 * the namespace
3953
 *
3954
 * @param ctxt  the XPath context
3955
 * @param prefix  the namespace prefix cannot be NULL or empty string
3956
 * @param ns_uri  the namespace name
3957
 * @returns 0 in case of success, -1 in case of error
3958
 */
3959
int
3960
xmlXPathRegisterNs(xmlXPathContext *ctxt, const xmlChar *prefix,
3961
5.48k
         const xmlChar *ns_uri) {
3962
5.48k
    xmlChar *copy;
3963
3964
5.48k
    if (ctxt == NULL)
3965
0
  return(-1);
3966
5.48k
    if (prefix == NULL)
3967
0
  return(-1);
3968
5.48k
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
5.48k
    if (ctxt->nsHash == NULL)
3972
5.27k
  ctxt->nsHash = xmlHashCreate(10);
3973
5.48k
    if (ctxt->nsHash == NULL) {
3974
0
        xmlXPathErrMemory(ctxt);
3975
0
  return(-1);
3976
0
    }
3977
5.48k
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
5.48k
    copy = xmlStrdup(ns_uri);
3982
5.48k
    if (copy == NULL) {
3983
0
        xmlXPathErrMemory(ctxt);
3984
0
        return(-1);
3985
0
    }
3986
5.48k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
5.48k
                           xmlHashDefaultDeallocator) < 0) {
3988
0
        xmlXPathErrMemory(ctxt);
3989
0
        xmlFree(copy);
3990
0
        return(-1);
3991
0
    }
3992
3993
5.48k
    return(0);
3994
5.48k
}
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
820k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
820k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
820k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
820k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
200k
  return(XML_XML_NAMESPACE);
4013
4014
619k
    if (ctxt->namespaces != NULL) {
4015
32
  int i;
4016
4017
82
  for (i = 0;i < ctxt->nsNr;i++) {
4018
50
      if ((ctxt->namespaces[i] != NULL) &&
4019
50
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4020
0
    return(ctxt->namespaces[i]->href);
4021
50
  }
4022
32
    }
4023
4024
619k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
619k
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
16.1k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
16.1k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
16.1k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
16.1k
    ctxt->nsHash = NULL;
4039
16.1k
}
4040
4041
/************************************************************************
4042
 *                  *
4043
 *      Routines to handle Values     *
4044
 *                  *
4045
 ************************************************************************/
4046
4047
/* Allocations are terrible, one needs to optimize all this !!! */
4048
4049
/**
4050
 * Create a new xmlXPathObject of type double and of value `val`
4051
 *
4052
 * @param val  the double value
4053
 * @returns the newly created object.
4054
 */
4055
xmlXPathObject *
4056
1.46M
xmlXPathNewFloat(double val) {
4057
1.46M
    xmlXPathObjectPtr ret;
4058
4059
1.46M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
1.46M
    if (ret == NULL)
4061
0
  return(NULL);
4062
1.46M
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
1.46M
    ret->type = XPATH_NUMBER;
4064
1.46M
    ret->floatval = val;
4065
1.46M
    return(ret);
4066
1.46M
}
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
2.28M
xmlXPathNewBoolean(int val) {
4076
2.28M
    xmlXPathObjectPtr ret;
4077
4078
2.28M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
2.28M
    if (ret == NULL)
4080
0
  return(NULL);
4081
2.28M
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
2.28M
    ret->type = XPATH_BOOLEAN;
4083
2.28M
    ret->boolval = (val != 0);
4084
2.28M
    return(ret);
4085
2.28M
}
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
170k
xmlXPathNewString(const xmlChar *val) {
4095
170k
    xmlXPathObjectPtr ret;
4096
4097
170k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
170k
    if (ret == NULL)
4099
0
  return(NULL);
4100
170k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
170k
    ret->type = XPATH_STRING;
4102
170k
    if (val == NULL)
4103
0
        val = BAD_CAST "";
4104
170k
    ret->stringval = xmlStrdup(val);
4105
170k
    if (ret->stringval == NULL) {
4106
0
        xmlFree(ret);
4107
0
        return(NULL);
4108
0
    }
4109
170k
    return(ret);
4110
170k
}
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
48
xmlXPathWrapString (xmlChar *val) {
4122
48
    xmlXPathObjectPtr ret;
4123
4124
48
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
48
    if (ret == NULL) {
4126
0
        xmlFree(val);
4127
0
  return(NULL);
4128
0
    }
4129
48
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
48
    ret->type = XPATH_STRING;
4131
48
    ret->stringval = val;
4132
48
    return(ret);
4133
48
}
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
706k
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
706k
    xmlXPathObjectPtr ret;
4185
4186
706k
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
706k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
706k
    if (ret == NULL)
4191
0
  return(NULL);
4192
706k
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
706k
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
109k
  case XPATH_NUMBER:
4196
109k
      break;
4197
597k
  case XPATH_STRING:
4198
597k
      ret->stringval = xmlStrdup(val->stringval);
4199
597k
            if (ret->stringval == NULL) {
4200
0
                xmlFree(ret);
4201
0
                return(NULL);
4202
0
            }
4203
597k
      break;
4204
597k
  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
706k
    }
4222
706k
    return(ret);
4223
706k
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
24.0M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
24.0M
    if (obj == NULL) return;
4233
24.0M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
19.4M
        if (obj->nodesetval != NULL)
4235
19.4M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
19.4M
    } else if (obj->type == XPATH_STRING) {
4237
769k
  if (obj->stringval != NULL)
4238
769k
      xmlFree(obj->stringval);
4239
769k
    }
4240
24.0M
    xmlFree(obj);
4241
24.0M
}
4242
4243
static void
4244
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4245
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4246
0
}
4247
4248
/**
4249
 * Depending on the state of the cache this frees the given
4250
 * XPath object or stores it in the cache.
4251
 *
4252
 * @param ctxt  XPath context
4253
 * @param obj  the xmlXPathObject to free or to cache
4254
 */
4255
static void
4256
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4257
24.0M
{
4258
24.0M
    if (obj == NULL)
4259
0
  return;
4260
24.0M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
23.4M
   xmlXPathFreeObject(obj);
4262
23.4M
    } else {
4263
603k
  xmlXPathContextCachePtr cache =
4264
603k
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
603k
  switch (obj->type) {
4267
594k
      case XPATH_NODESET:
4268
594k
      case XPATH_XSLT_TREE:
4269
594k
    if (obj->nodesetval != NULL) {
4270
594k
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
594k
      (cache->numNodeset < cache->maxNodeset)) {
4272
547k
                        obj->stringval = (void *) cache->nodesetObjs;
4273
547k
                        cache->nodesetObjs = obj;
4274
547k
                        cache->numNodeset += 1;
4275
547k
      goto obj_cached;
4276
547k
        } else {
4277
47.1k
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
47.1k
      obj->nodesetval = NULL;
4279
47.1k
        }
4280
594k
    }
4281
47.1k
    break;
4282
47.1k
      case XPATH_STRING:
4283
1.79k
    if (obj->stringval != NULL)
4284
1.79k
        xmlFree(obj->stringval);
4285
1.79k
                obj->stringval = NULL;
4286
1.79k
    break;
4287
1.79k
      case XPATH_BOOLEAN:
4288
7.49k
      case XPATH_NUMBER:
4289
7.49k
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
603k
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
56.4k
        if (cache->numMisc >= cache->maxMisc)
4298
0
      goto free_obj;
4299
56.4k
        obj->stringval = (void *) cache->miscObjs;
4300
56.4k
        cache->miscObjs = obj;
4301
56.4k
        cache->numMisc += 1;
4302
4303
603k
obj_cached:
4304
603k
        obj->boolval = 0;
4305
603k
  if (obj->nodesetval != NULL) {
4306
547k
      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
547k
      if (tmpset->nodeNr > 0) {
4313
542k
    int i;
4314
542k
    xmlNodePtr node;
4315
4316
1.08M
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
543k
        node = tmpset->nodeTab[i];
4318
543k
        if ((node != NULL) &&
4319
543k
      (node->type == XML_NAMESPACE_DECL))
4320
0
        {
4321
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
0
        }
4323
543k
    }
4324
542k
      }
4325
547k
      tmpset->nodeNr = 0;
4326
547k
        }
4327
4328
603k
  return;
4329
4330
0
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
0
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
0
  xmlFree(obj);
4337
0
    }
4338
24.0M
}
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
17.5k
xmlXPathCastBooleanToString (int val) {
4355
17.5k
    xmlChar *ret;
4356
17.5k
    if (val)
4357
6
  ret = xmlStrdup((const xmlChar *) "true");
4358
17.5k
    else
4359
17.5k
  ret = xmlStrdup((const xmlChar *) "false");
4360
17.5k
    return(ret);
4361
17.5k
}
4362
4363
/**
4364
 * Converts a number to its string value.
4365
 *
4366
 * @param val  a number
4367
 * @returns a newly allocated string.
4368
 */
4369
xmlChar *
4370
292
xmlXPathCastNumberToString (double val) {
4371
292
    xmlChar *ret;
4372
292
    switch (xmlXPathIsInf(val)) {
4373
0
    case 1:
4374
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
0
  break;
4376
0
    case -1:
4377
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
0
  break;
4379
292
    default:
4380
292
  if (xmlXPathIsNaN(val)) {
4381
292
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
292
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
0
      ret = xmlStrdup((const xmlChar *) "0");
4385
0
  } else {
4386
      /* could be improved */
4387
0
      char buf[100];
4388
0
      xmlXPathFormatNumber(val, buf, 99);
4389
0
      buf[99] = 0;
4390
0
      ret = xmlStrdup((const xmlChar *) buf);
4391
0
  }
4392
292
    }
4393
292
    return(ret);
4394
292
}
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
1.62M
xmlXPathCastNodeToString (xmlNode *node) {
4404
1.62M
    return(xmlNodeGetContent(node));
4405
1.62M
}
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
7.01M
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
7.01M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
5.61M
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
1.40M
    if (ns->nodeNr > 1)
4419
552k
  xmlXPathNodeSetSort(ns);
4420
1.40M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
7.01M
}
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
101k
xmlXPathCastToString(xmlXPathObject *val) {
4432
101k
    xmlChar *ret = NULL;
4433
4434
101k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
101k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
69.4k
        case XPATH_NODESET:
4441
69.4k
        case XPATH_XSLT_TREE:
4442
69.4k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
69.4k
      break;
4444
14.3k
  case XPATH_STRING:
4445
14.3k
      return(xmlStrdup(val->stringval));
4446
17.5k
        case XPATH_BOOLEAN:
4447
17.5k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
17.5k
      break;
4449
292
  case XPATH_NUMBER: {
4450
292
      ret = xmlXPathCastNumberToString(val->floatval);
4451
292
      break;
4452
69.4k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
101k
    }
4458
87.2k
    return(ret);
4459
101k
}
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
48
xmlXPathConvertString(xmlXPathObject *val) {
4470
48
    xmlChar *res = NULL;
4471
4472
48
    if (val == NULL)
4473
0
  return(xmlXPathNewCString(""));
4474
4475
48
    switch (val->type) {
4476
0
    case XPATH_UNDEFINED:
4477
0
  break;
4478
48
    case XPATH_NODESET:
4479
48
    case XPATH_XSLT_TREE:
4480
48
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4481
48
  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
48
    }
4494
48
    xmlXPathFreeObject(val);
4495
48
    if (res == NULL)
4496
0
  return(xmlXPathNewCString(""));
4497
48
    return(xmlXPathWrapString(res));
4498
48
}
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
180k
xmlXPathCastBooleanToNumber(int val) {
4508
180k
    if (val)
4509
40.3k
  return(1.0);
4510
139k
    return(0.0);
4511
180k
}
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.49M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
7.49M
    return(xmlXPathStringEvalNumber(val));
4522
7.49M
}
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
65.9k
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
65.9k
    xmlChar *strval;
4534
65.9k
    double ret;
4535
4536
65.9k
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
65.9k
    strval = xmlXPathCastNodeToString(node);
4539
65.9k
    if (strval == NULL) {
4540
0
        xmlXPathPErrMemory(ctxt);
4541
0
  return(xmlXPathNAN);
4542
0
    }
4543
65.9k
    ret = xmlXPathCastStringToNumber(strval);
4544
65.9k
    xmlFree(strval);
4545
4546
65.9k
    return(ret);
4547
65.9k
}
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
246k
xmlXPathCastNumberToBoolean (double val) {
4618
246k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
228k
   return(0);
4620
18.5k
     return(1);
4621
246k
}
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
139
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
139
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
70
  return(0);
4633
69
    return(1);
4634
139
}
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
845k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
845k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
422k
  return(0);
4646
423k
    return(1);
4647
845k
}
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
966k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
966k
    int ret = 0;
4658
4659
966k
    if (val == NULL)
4660
0
  return(0);
4661
966k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
845k
    case XPATH_NODESET:
4666
845k
    case XPATH_XSLT_TREE:
4667
845k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
845k
  break;
4669
139
    case XPATH_STRING:
4670
139
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
139
  break;
4672
120k
    case XPATH_NUMBER:
4673
120k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
120k
  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
966k
    }
4683
966k
    return(ret);
4684
966k
}
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
16.1k
xmlXPathNewContext(xmlDoc *doc) {
4721
16.1k
    xmlXPathContextPtr ret;
4722
4723
16.1k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
16.1k
    if (ret == NULL)
4725
0
  return(NULL);
4726
16.1k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
16.1k
    ret->doc = doc;
4728
16.1k
    ret->node = NULL;
4729
4730
16.1k
    ret->varHash = NULL;
4731
4732
16.1k
    ret->nb_types = 0;
4733
16.1k
    ret->max_types = 0;
4734
16.1k
    ret->types = NULL;
4735
4736
16.1k
    ret->nb_axis = 0;
4737
16.1k
    ret->max_axis = 0;
4738
16.1k
    ret->axis = NULL;
4739
4740
16.1k
    ret->nsHash = NULL;
4741
16.1k
    ret->user = NULL;
4742
4743
16.1k
    ret->contextSize = -1;
4744
16.1k
    ret->proximityPosition = -1;
4745
4746
#ifdef XP_DEFAULT_CACHE_ON
4747
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
4748
  xmlXPathFreeContext(ret);
4749
  return(NULL);
4750
    }
4751
#endif
4752
4753
16.1k
    return(ret);
4754
16.1k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
16.1k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
16.1k
    if (ctxt == NULL) return;
4764
4765
16.1k
    if (ctxt->cache != NULL)
4766
9.98k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
16.1k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
16.1k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
16.1k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
16.1k
    xmlResetError(&ctxt->lastError);
4771
16.1k
    xmlFree(ctxt);
4772
16.1k
}
4773
4774
/**
4775
 * Register a callback function that will be called on errors and
4776
 * warnings. If handler is NULL, the error handler will be deactivated.
4777
 *
4778
 * @since 2.13.0
4779
 * @param ctxt  the XPath context
4780
 * @param handler  error handler
4781
 * @param data  user data which will be passed to the handler
4782
 */
4783
void
4784
xmlXPathSetErrorHandler(xmlXPathContext *ctxt,
4785
0
                        xmlStructuredErrorFunc handler, void *data) {
4786
0
    if (ctxt == NULL)
4787
0
        return;
4788
4789
0
    ctxt->error = handler;
4790
0
    ctxt->userData = data;
4791
0
}
4792
4793
/************************************************************************
4794
 *                  *
4795
 *    Routines to handle XPath parser contexts    *
4796
 *                  *
4797
 ************************************************************************/
4798
4799
/**
4800
 * Create a new xmlXPathParserContext
4801
 *
4802
 * @param str  the XPath expression
4803
 * @param ctxt  the XPath context
4804
 * @returns the xmlXPathParserContext just allocated.
4805
 */
4806
xmlXPathParserContext *
4807
28.6k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
28.6k
    xmlXPathParserContextPtr ret;
4809
4810
28.6k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
28.6k
    if (ret == NULL) {
4812
0
        xmlXPathErrMemory(ctxt);
4813
0
  return(NULL);
4814
0
    }
4815
28.6k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
28.6k
    ret->cur = ret->base = str;
4817
28.6k
    ret->context = ctxt;
4818
4819
28.6k
    ret->comp = xmlXPathNewCompExpr();
4820
28.6k
    if (ret->comp == NULL) {
4821
0
        xmlXPathErrMemory(ctxt);
4822
0
  xmlFree(ret->valueTab);
4823
0
  xmlFree(ret);
4824
0
  return(NULL);
4825
0
    }
4826
28.6k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
23.4k
        ret->comp->dict = ctxt->dict;
4828
23.4k
  xmlDictReference(ret->comp->dict);
4829
23.4k
    }
4830
4831
28.6k
    return(ret);
4832
28.6k
}
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
500k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
500k
    xmlXPathParserContextPtr ret;
4844
4845
500k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
500k
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
500k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
500k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
500k
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
500k
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
500k
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
500k
    ret->valueNr = 0;
4865
500k
    ret->value = NULL;
4866
4867
500k
    ret->context = ctxt;
4868
500k
    ret->comp = comp;
4869
4870
500k
    return(ret);
4871
500k
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
529k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
529k
    int i;
4881
4882
529k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
529k
    if (ctxt->valueTab != NULL) {
4886
508k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
3.97k
            if (ctxt->context)
4888
3.97k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
3.97k
        }
4892
504k
        xmlFree(ctxt->valueTab);
4893
504k
    }
4894
529k
    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
18.1k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
18.1k
    }
4903
529k
    xmlFree(ctxt);
4904
529k
}
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
2.25M
xmlXPathNodeValHash(xmlNodePtr node) {
4921
2.25M
    int len = 2;
4922
2.25M
    const xmlChar * string = NULL;
4923
2.25M
    xmlNodePtr tmp = NULL;
4924
2.25M
    unsigned int ret = 0;
4925
4926
2.25M
    if (node == NULL)
4927
0
  return(0);
4928
4929
2.25M
    if (node->type == XML_DOCUMENT_NODE) {
4930
966
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
966
  if (tmp == NULL)
4932
0
      node = node->children;
4933
966
  else
4934
966
      node = tmp;
4935
4936
966
  if (node == NULL)
4937
0
      return(0);
4938
966
    }
4939
4940
2.25M
    switch (node->type) {
4941
663
  case XML_COMMENT_NODE:
4942
762
  case XML_PI_NODE:
4943
834
  case XML_CDATA_SECTION_NODE:
4944
9.59k
  case XML_TEXT_NODE:
4945
9.59k
      string = node->content;
4946
9.59k
      if (string == NULL)
4947
98
    return(0);
4948
9.49k
      if (string[0] == 0)
4949
350
    return(0);
4950
9.14k
      return(string[0] + (string[1] << 8));
4951
12.6k
  case XML_NAMESPACE_DECL:
4952
12.6k
      string = ((xmlNsPtr)node)->href;
4953
12.6k
      if (string == NULL)
4954
0
    return(0);
4955
12.6k
      if (string[0] == 0)
4956
23
    return(0);
4957
12.5k
      return(string[0] + (string[1] << 8));
4958
2.12M
  case XML_ATTRIBUTE_NODE:
4959
2.12M
      tmp = ((xmlAttrPtr) node)->children;
4960
2.12M
      break;
4961
111k
  case XML_ELEMENT_NODE:
4962
111k
      tmp = node->children;
4963
111k
      break;
4964
0
  default:
4965
0
      return(0);
4966
2.25M
    }
4967
2.52M
    while (tmp != NULL) {
4968
2.31M
  switch (tmp->type) {
4969
0
      case XML_CDATA_SECTION_NODE:
4970
2.19M
      case XML_TEXT_NODE:
4971
2.19M
    string = tmp->content;
4972
2.19M
    break;
4973
115k
      default:
4974
115k
                string = NULL;
4975
115k
    break;
4976
2.31M
  }
4977
2.31M
  if ((string != NULL) && (string[0] != 0)) {
4978
2.15M
      if (len == 1) {
4979
5.38k
    return(ret + (string[0] << 8));
4980
5.38k
      }
4981
2.15M
      if (string[1] == 0) {
4982
129k
    len = 1;
4983
129k
    ret = string[0];
4984
2.02M
      } else {
4985
2.02M
    return(string[0] + (string[1] << 8));
4986
2.02M
      }
4987
2.15M
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
285k
        if ((tmp->children != NULL) &&
4992
85.7k
            (tmp->type != XML_DTD_NODE) &&
4993
85.7k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
85.7k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
85.7k
            tmp = tmp->children;
4996
85.7k
            continue;
4997
85.7k
  }
4998
199k
  if (tmp == node)
4999
0
      break;
5000
5001
199k
  if (tmp->next != NULL) {
5002
34.3k
      tmp = tmp->next;
5003
34.3k
      continue;
5004
34.3k
  }
5005
5006
165k
  do {
5007
165k
      tmp = tmp->parent;
5008
165k
      if (tmp == NULL)
5009
0
    break;
5010
165k
      if (tmp == node) {
5011
164k
    tmp = NULL;
5012
164k
    break;
5013
164k
      }
5014
639
      if (tmp->next != NULL) {
5015
639
    tmp = tmp->next;
5016
639
    break;
5017
639
      }
5018
639
  } while (tmp != NULL);
5019
165k
    }
5020
205k
    return(ret);
5021
2.23M
}
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
803
xmlXPathStringHash(const xmlChar * string) {
5032
803
    if (string == NULL)
5033
0
  return(0);
5034
803
    if (string[0] == 0)
5035
364
  return(0);
5036
439
    return(string[0] + (string[1] << 8));
5037
803
}
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
76.5k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
76.5k
    int i, ret = 0;
5063
76.5k
    xmlNodeSetPtr ns;
5064
76.5k
    xmlChar *str2;
5065
5066
76.5k
    if ((f == NULL) || (arg == NULL) ||
5067
76.5k
  ((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
76.5k
    ns = arg->nodesetval;
5073
76.5k
    if (ns != NULL) {
5074
96.6k
  for (i = 0;i < ns->nodeNr;i++) {
5075
20.0k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
20.0k
       if (str2 != NULL) {
5077
20.0k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
20.0k
     xmlFree(str2);
5079
20.0k
     xmlXPathNumberFunction(ctxt, 1);
5080
20.0k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
20.0k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
20.0k
     if (ret)
5083
9
         break;
5084
20.0k
       } else {
5085
0
                 xmlXPathPErrMemory(ctxt);
5086
0
             }
5087
20.0k
  }
5088
76.5k
    }
5089
76.5k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
76.5k
    xmlXPathReleaseObject(ctxt->context, f);
5091
76.5k
    return(ret);
5092
76.5k
}
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
103k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
103k
    int i, ret = 0;
5117
103k
    xmlNodeSetPtr ns;
5118
103k
    xmlChar *str2;
5119
5120
103k
    if ((s == NULL) || (arg == NULL) ||
5121
103k
  ((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
103k
    ns = arg->nodesetval;
5127
103k
    if (ns != NULL) {
5128
129k
  for (i = 0;i < ns->nodeNr;i++) {
5129
26.2k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
26.2k
       if (str2 != NULL) {
5131
26.2k
     xmlXPathValuePush(ctxt,
5132
26.2k
         xmlXPathCacheNewString(ctxt, str2));
5133
26.2k
     xmlFree(str2);
5134
26.2k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
26.2k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
26.2k
     if (ret)
5137
521
         break;
5138
26.2k
       } else {
5139
0
                 xmlXPathPErrMemory(ctxt);
5140
0
             }
5141
26.2k
  }
5142
103k
    }
5143
103k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
103k
    xmlXPathReleaseObject(ctxt->context, s);
5145
103k
    return(ret);
5146
103k
}
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
60.6k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
60.6k
    int i, j, init = 0;
5180
60.6k
    double val1;
5181
60.6k
    double *values2;
5182
60.6k
    int ret = 0;
5183
60.6k
    xmlNodeSetPtr ns1;
5184
60.6k
    xmlNodeSetPtr ns2;
5185
5186
60.6k
    if ((arg1 == NULL) ||
5187
60.6k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
60.6k
    if ((arg2 == NULL) ||
5192
60.6k
  ((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
60.6k
    ns1 = arg1->nodesetval;
5199
60.6k
    ns2 = arg2->nodesetval;
5200
5201
60.6k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
30.9k
  xmlXPathFreeObject(arg1);
5203
30.9k
  xmlXPathFreeObject(arg2);
5204
30.9k
  return(0);
5205
30.9k
    }
5206
29.6k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
15.7k
  xmlXPathFreeObject(arg1);
5208
15.7k
  xmlXPathFreeObject(arg2);
5209
15.7k
  return(0);
5210
15.7k
    }
5211
5212
13.9k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
13.9k
    if (values2 == NULL) {
5214
0
        xmlXPathPErrMemory(ctxt);
5215
0
  xmlXPathFreeObject(arg1);
5216
0
  xmlXPathFreeObject(arg2);
5217
0
  return(0);
5218
0
    }
5219
62.9k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
49.6k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
49.6k
  if (xmlXPathIsNaN(val1))
5222
46.1k
      continue;
5223
35.0k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
32.2k
      if (init == 0) {
5225
16.2k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
16.2k
                                                          ns2->nodeTab[j]);
5227
16.2k
      }
5228
32.2k
      if (xmlXPathIsNaN(values2[j]))
5229
30.3k
    continue;
5230
1.84k
      if (inf && strict)
5231
1.76k
    ret = (val1 < values2[j]);
5232
83
      else if (inf && !strict)
5233
6
    ret = (val1 <= values2[j]);
5234
77
      else if (!inf && strict)
5235
77
    ret = (val1 > values2[j]);
5236
0
      else if (!inf && !strict)
5237
0
    ret = (val1 >= values2[j]);
5238
1.84k
      if (ret)
5239
660
    break;
5240
1.84k
  }
5241
3.52k
  if (ret)
5242
660
      break;
5243
2.86k
  init = 1;
5244
2.86k
    }
5245
13.9k
    xmlFree(values2);
5246
13.9k
    xmlXPathFreeObject(arg1);
5247
13.9k
    xmlXPathFreeObject(arg2);
5248
13.9k
    return(ret);
5249
13.9k
}
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
258k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
258k
    if ((val == NULL) || (arg == NULL) ||
5274
258k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
258k
    switch(val->type) {
5278
76.5k
        case XPATH_NUMBER:
5279
76.5k
      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
103k
        case XPATH_STRING:
5284
103k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
78.3k
        case XPATH_BOOLEAN:
5286
78.3k
      xmlXPathValuePush(ctxt, arg);
5287
78.3k
      xmlXPathBooleanFunction(ctxt, 1);
5288
78.3k
      xmlXPathValuePush(ctxt, val);
5289
78.3k
      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
258k
    }
5295
0
    return(0);
5296
258k
}
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
16.1k
{
5315
16.1k
    int i;
5316
16.1k
    xmlNodeSetPtr ns;
5317
16.1k
    xmlChar *str2;
5318
16.1k
    unsigned int hash;
5319
5320
16.1k
    if ((str == NULL) || (arg == NULL) ||
5321
16.1k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
16.1k
    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
16.1k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
15.3k
        return (0);
5330
803
    hash = xmlXPathStringHash(str);
5331
5.37k
    for (i = 0; i < ns->nodeNr; i++) {
5332
4.89k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
332
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
332
            if (str2 == NULL) {
5335
0
                xmlXPathPErrMemory(ctxt);
5336
0
                return(0);
5337
0
            }
5338
332
            if (xmlStrEqual(str, str2)) {
5339
331
                xmlFree(str2);
5340
331
    if (neq)
5341
0
        continue;
5342
331
                return (1);
5343
331
            } else if (neq) {
5344
0
    xmlFree(str2);
5345
0
    return (1);
5346
0
      }
5347
1
            xmlFree(str2);
5348
4.56k
        } else if (neq)
5349
0
      return (1);
5350
4.89k
    }
5351
472
    return (0);
5352
803
}
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
273k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
273k
  int i, ret=0;
5372
273k
  xmlNodeSetPtr ns;
5373
273k
  xmlChar *str2;
5374
273k
  xmlXPathObjectPtr val;
5375
273k
  double v;
5376
5377
273k
    if ((arg == NULL) ||
5378
273k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
273k
    ns = arg->nodesetval;
5382
273k
    if (ns != NULL) {
5383
377k
  for (i=0;i<ns->nodeNr;i++) {
5384
104k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
104k
      if (str2 != NULL) {
5386
104k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
104k
    xmlFree(str2);
5388
104k
    xmlXPathNumberFunction(ctxt, 1);
5389
104k
                CHECK_ERROR0;
5390
104k
    val = xmlXPathValuePop(ctxt);
5391
104k
    v = val->floatval;
5392
104k
    xmlXPathReleaseObject(ctxt->context, val);
5393
104k
    if (!xmlXPathIsNaN(v)) {
5394
2.75k
        if ((!neq) && (v==f)) {
5395
727
      ret = 1;
5396
727
      break;
5397
2.02k
        } else if ((neq) && (v!=f)) {
5398
13
      ret = 1;
5399
13
      break;
5400
13
        }
5401
101k
    } else { /* NaN is unequal to any value */
5402
101k
        if (neq)
5403
2.86k
      ret = 1;
5404
101k
    }
5405
104k
      } else {
5406
0
                xmlXPathPErrMemory(ctxt);
5407
0
            }
5408
104k
  }
5409
273k
    }
5410
5411
273k
    return(ret);
5412
273k
}
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
51.7k
                      xmlXPathObjectPtr arg2, int neq) {
5434
51.7k
    int i, j;
5435
51.7k
    unsigned int *hashs1;
5436
51.7k
    unsigned int *hashs2;
5437
51.7k
    xmlChar **values1;
5438
51.7k
    xmlChar **values2;
5439
51.7k
    int ret = 0;
5440
51.7k
    xmlNodeSetPtr ns1;
5441
51.7k
    xmlNodeSetPtr ns2;
5442
5443
51.7k
    if ((arg1 == NULL) ||
5444
51.7k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
51.7k
    if ((arg2 == NULL) ||
5447
51.7k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
51.7k
    ns1 = arg1->nodesetval;
5451
51.7k
    ns2 = arg2->nodesetval;
5452
5453
51.7k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
24.1k
  return(0);
5455
27.5k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
583
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
26.9k
    if (neq == 0)
5462
2.37M
  for (i = 0;i < ns1->nodeNr;i++)
5463
9.22M
      for (j = 0;j < ns2->nodeNr;j++)
5464
6.88M
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
2.50k
        return(1);
5466
5467
24.4k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
24.4k
    if (values1 == NULL) {
5469
0
        xmlXPathPErrMemory(ctxt);
5470
0
  return(0);
5471
0
    }
5472
24.4k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
24.4k
    if (hashs1 == NULL) {
5474
0
        xmlXPathPErrMemory(ctxt);
5475
0
  xmlFree(values1);
5476
0
  return(0);
5477
0
    }
5478
24.4k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
24.4k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
24.4k
    if (values2 == NULL) {
5481
0
        xmlXPathPErrMemory(ctxt);
5482
0
  xmlFree(hashs1);
5483
0
  xmlFree(values1);
5484
0
  return(0);
5485
0
    }
5486
24.4k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
24.4k
    if (hashs2 == NULL) {
5488
0
        xmlXPathPErrMemory(ctxt);
5489
0
  xmlFree(hashs1);
5490
0
  xmlFree(values1);
5491
0
  xmlFree(values2);
5492
0
  return(0);
5493
0
    }
5494
24.4k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
2.14M
    for (i = 0;i < ns1->nodeNr;i++) {
5496
2.12M
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
8.44M
  for (j = 0;j < ns2->nodeNr;j++) {
5498
6.32M
      if (i == 0)
5499
125k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
6.32M
      if (hashs1[i] != hashs2[j]) {
5501
5.90M
    if (neq) {
5502
142
        ret = 1;
5503
142
        break;
5504
142
    }
5505
5.90M
      }
5506
412k
      else {
5507
412k
    if (values1[i] == NULL) {
5508
411k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
411k
                    if (values1[i] == NULL)
5510
0
                        xmlXPathPErrMemory(ctxt);
5511
411k
                }
5512
412k
    if (values2[j] == NULL) {
5513
16.3k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
16.3k
                    if (values2[j] == NULL)
5515
0
                        xmlXPathPErrMemory(ctxt);
5516
16.3k
                }
5517
412k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
412k
    if (ret)
5519
3.06k
        break;
5520
412k
      }
5521
6.32M
  }
5522
2.12M
  if (ret)
5523
3.21k
      break;
5524
2.12M
    }
5525
2.26M
    for (i = 0;i < ns1->nodeNr;i++)
5526
2.24M
  if (values1[i] != NULL)
5527
411k
      xmlFree(values1[i]);
5528
149k
    for (j = 0;j < ns2->nodeNr;j++)
5529
125k
  if (values2[j] != NULL)
5530
16.3k
      xmlFree(values2[j]);
5531
24.4k
    xmlFree(values1);
5532
24.4k
    xmlFree(values2);
5533
24.4k
    xmlFree(hashs1);
5534
24.4k
    xmlFree(hashs2);
5535
24.4k
    return(ret);
5536
24.4k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
405k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
405k
    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
405k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
366k
        case XPATH_BOOLEAN:
5550
366k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
107k
    case XPATH_BOOLEAN:
5554
107k
        ret = (arg1->boolval == arg2->boolval);
5555
107k
        break;
5556
115k
    case XPATH_NUMBER:
5557
115k
        ret = (arg1->boolval ==
5558
115k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
115k
        break;
5560
143k
    case XPATH_STRING:
5561
143k
        if ((arg2->stringval == NULL) ||
5562
143k
      (arg2->stringval[0] == 0)) ret = 0;
5563
143k
        else
5564
143k
      ret = 1;
5565
143k
        ret = (arg1->boolval == ret);
5566
143k
        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
366k
      }
5574
366k
      break;
5575
366k
        case XPATH_NUMBER:
5576
38.6k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
10.7k
    case XPATH_BOOLEAN:
5580
10.7k
        ret = (arg2->boolval==
5581
10.7k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
10.7k
        break;
5583
7.94k
    case XPATH_STRING:
5584
7.94k
        xmlXPathValuePush(ctxt, arg2);
5585
7.94k
        xmlXPathNumberFunction(ctxt, 1);
5586
7.94k
        arg2 = xmlXPathValuePop(ctxt);
5587
7.94k
                    if (ctxt->error)
5588
0
                        break;
5589
                    /* Falls through. */
5590
27.8k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
27.8k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
27.3k
          xmlXPathIsNaN(arg2->floatval)) {
5594
27.3k
            ret = 0;
5595
27.3k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
1
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
0
          ret = 1;
5598
1
      else
5599
1
          ret = 0;
5600
459
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
0
          ret = 1;
5603
0
      else
5604
0
          ret = 0;
5605
459
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
3
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
3
      else
5609
3
          ret = 0;
5610
456
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
0
      else
5614
0
          ret = 0;
5615
456
        } else {
5616
456
            ret = (arg1->floatval == arg2->floatval);
5617
456
        }
5618
27.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
38.6k
      }
5626
38.6k
      break;
5627
38.6k
        case XPATH_STRING:
5628
1.06k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
584
    case XPATH_BOOLEAN:
5632
584
        if ((arg1->stringval == NULL) ||
5633
584
      (arg1->stringval[0] == 0)) ret = 0;
5634
100
        else
5635
100
      ret = 1;
5636
584
        ret = (arg2->boolval == ret);
5637
584
        break;
5638
74
    case XPATH_STRING:
5639
74
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
74
        break;
5641
411
    case XPATH_NUMBER:
5642
411
        xmlXPathValuePush(ctxt, arg1);
5643
411
        xmlXPathNumberFunction(ctxt, 1);
5644
411
        arg1 = xmlXPathValuePop(ctxt);
5645
411
                    if (ctxt->error)
5646
0
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
411
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
411
          xmlXPathIsNaN(arg2->floatval)) {
5650
411
            ret = 0;
5651
411
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
0
          ret = 1;
5654
0
      else
5655
0
          ret = 0;
5656
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
0
          ret = 1;
5659
0
      else
5660
0
          ret = 0;
5661
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
0
      else
5665
0
          ret = 0;
5666
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
0
      else
5670
0
          ret = 0;
5671
0
        } else {
5672
0
            ret = (arg1->floatval == arg2->floatval);
5673
0
        }
5674
411
        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
1.06k
      }
5682
1.06k
      break;
5683
1.06k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
405k
    }
5690
405k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
405k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
405k
    return(ret);
5693
405k
}
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
923k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
923k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
923k
    int ret = 0;
5705
5706
923k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
923k
    arg2 = xmlXPathValuePop(ctxt);
5708
923k
    arg1 = xmlXPathValuePop(ctxt);
5709
923k
    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
923k
    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
923k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
816k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
529k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
56.3k
    argtmp = arg2;
5732
56.3k
    arg2 = arg1;
5733
56.3k
    arg1 = argtmp;
5734
56.3k
  }
5735
529k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
50.0k
      case XPATH_NODESET:
5739
50.0k
      case XPATH_XSLT_TREE:
5740
50.0k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
50.0k
    break;
5742
190k
      case XPATH_BOOLEAN:
5743
190k
    if ((arg1->nodesetval == NULL) ||
5744
190k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
14.4k
    else
5746
14.4k
        ret = 1;
5747
190k
    ret = (ret == arg2->boolval);
5748
190k
    break;
5749
272k
      case XPATH_NUMBER:
5750
272k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
272k
    break;
5752
16.1k
      case XPATH_STRING:
5753
16.1k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
16.1k
                                                 arg2->stringval, 0);
5755
16.1k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
529k
  }
5760
529k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
529k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
529k
  return(ret);
5763
529k
    }
5764
5765
394k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
923k
}
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
16.6k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
16.6k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
16.6k
    int ret = 0;
5778
5779
16.6k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
16.6k
    arg2 = xmlXPathValuePop(ctxt);
5781
16.6k
    arg1 = xmlXPathValuePop(ctxt);
5782
16.6k
    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
16.6k
    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
16.6k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
12.9k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
4.77k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
1.95k
    argtmp = arg2;
5805
1.95k
    arg2 = arg1;
5806
1.95k
    arg1 = argtmp;
5807
1.95k
  }
5808
4.77k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
1.67k
      case XPATH_NODESET:
5812
1.67k
      case XPATH_XSLT_TREE:
5813
1.67k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
1.67k
    break;
5815
1.97k
      case XPATH_BOOLEAN:
5816
1.97k
    if ((arg1->nodesetval == NULL) ||
5817
1.97k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
496
    else
5819
496
        ret = 1;
5820
1.97k
    ret = (ret != arg2->boolval);
5821
1.97k
    break;
5822
1.13k
      case XPATH_NUMBER:
5823
1.13k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
1.13k
    break;
5825
0
      case XPATH_STRING:
5826
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
0
                                                 arg2->stringval, 1);
5828
0
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
4.77k
  }
5833
4.77k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
4.77k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
4.77k
  return(ret);
5836
4.77k
    }
5837
5838
11.8k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
16.6k
}
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
524k
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
524k
    int ret = 0, arg1i = 0, arg2i = 0;
5866
524k
    xmlXPathObjectPtr arg1, arg2;
5867
5868
524k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
524k
    arg2 = xmlXPathValuePop(ctxt);
5870
524k
    arg1 = xmlXPathValuePop(ctxt);
5871
524k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
0
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
0
  else
5875
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
524k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
319k
      (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
319k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
308k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
60.6k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
258k
  } else {
5890
258k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
10.6k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
10.6k
                                arg1, arg2);
5893
248k
      } else {
5894
248k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
248k
                                arg2, arg1);
5896
248k
      }
5897
258k
  }
5898
319k
  return(ret);
5899
319k
    }
5900
5901
204k
    if (arg1->type != XPATH_NUMBER) {
5902
169k
  xmlXPathValuePush(ctxt, arg1);
5903
169k
  xmlXPathNumberFunction(ctxt, 1);
5904
169k
  arg1 = xmlXPathValuePop(ctxt);
5905
169k
    }
5906
204k
    if (arg2->type != XPATH_NUMBER) {
5907
108k
  xmlXPathValuePush(ctxt, arg2);
5908
108k
  xmlXPathNumberFunction(ctxt, 1);
5909
108k
  arg2 = xmlXPathValuePop(ctxt);
5910
108k
    }
5911
204k
    if (ctxt->error)
5912
0
        goto error;
5913
    /*
5914
     * Add tests for infinity and nan
5915
     * => feedback on 3.4 for Inf and NaN
5916
     */
5917
    /* Hand check NaN and Infinity comparisons */
5918
204k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
124k
  ret=0;
5920
124k
    } else {
5921
80.4k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
80.4k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
80.4k
  if (inf && strict) {
5924
47.6k
      if ((arg1i == -1 && arg2i != -1) ||
5925
47.6k
    (arg2i == 1 && arg1i != 1)) {
5926
3
    ret = 1;
5927
47.6k
      } else if (arg1i == 0 && arg2i == 0) {
5928
47.6k
    ret = (arg1->floatval < arg2->floatval);
5929
47.6k
      } else {
5930
50
    ret = 0;
5931
50
      }
5932
47.6k
  }
5933
32.7k
  else if (inf && !strict) {
5934
1.45k
      if (arg1i == -1 || arg2i == 1) {
5935
0
    ret = 1;
5936
1.45k
      } else if (arg1i == 0 && arg2i == 0) {
5937
1.45k
    ret = (arg1->floatval <= arg2->floatval);
5938
1.45k
      } else {
5939
1
    ret = 0;
5940
1
      }
5941
1.45k
  }
5942
31.3k
  else if (!inf && strict) {
5943
31.2k
      if ((arg1i == 1 && arg2i != 1) ||
5944
31.2k
    (arg2i == -1 && arg1i != -1)) {
5945
0
    ret = 1;
5946
31.2k
      } else if (arg1i == 0 && arg2i == 0) {
5947
31.2k
    ret = (arg1->floatval > arg2->floatval);
5948
31.2k
      } else {
5949
0
    ret = 0;
5950
0
      }
5951
31.2k
  }
5952
73
  else if (!inf && !strict) {
5953
73
      if (arg1i == 1 || arg2i == -1) {
5954
0
    ret = 1;
5955
73
      } else if (arg1i == 0 && arg2i == 0) {
5956
73
    ret = (arg1->floatval >= arg2->floatval);
5957
73
      } else {
5958
0
    ret = 0;
5959
0
      }
5960
73
  }
5961
80.4k
    }
5962
204k
error:
5963
204k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
204k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
204k
    return(ret);
5966
204k
}
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
382k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
382k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
382k
    CAST_TO_NUMBER;
5979
382k
    CHECK_TYPE(XPATH_NUMBER);
5980
382k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
382k
}
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
32.8k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
32.8k
    xmlXPathObjectPtr arg;
5993
32.8k
    double val;
5994
5995
32.8k
    arg = xmlXPathValuePop(ctxt);
5996
32.8k
    if (arg == NULL)
5997
32.8k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
32.8k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
32.8k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
32.8k
    CAST_TO_NUMBER;
6001
32.8k
    CHECK_TYPE(XPATH_NUMBER);
6002
32.8k
    ctxt->value->floatval += val;
6003
32.8k
}
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
403k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
403k
    xmlXPathObjectPtr arg;
6015
403k
    double val;
6016
6017
403k
    arg = xmlXPathValuePop(ctxt);
6018
403k
    if (arg == NULL)
6019
403k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
403k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
403k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
403k
    CAST_TO_NUMBER;
6023
403k
    CHECK_TYPE(XPATH_NUMBER);
6024
403k
    ctxt->value->floatval -= val;
6025
403k
}
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
6.04M
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
6.04M
    xmlXPathObjectPtr arg;
6037
6.04M
    double val;
6038
6039
6.04M
    arg = xmlXPathValuePop(ctxt);
6040
6.04M
    if (arg == NULL)
6041
6.04M
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
6.04M
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
6.04M
    xmlXPathReleaseObject(ctxt->context, arg);
6044
6.04M
    CAST_TO_NUMBER;
6045
6.04M
    CHECK_TYPE(XPATH_NUMBER);
6046
6.04M
    ctxt->value->floatval *= val;
6047
6.04M
}
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
0
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
0
    xmlXPathObjectPtr arg;
6060
0
    double val;
6061
6062
0
    arg = xmlXPathValuePop(ctxt);
6063
0
    if (arg == NULL)
6064
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
0
    xmlXPathReleaseObject(ctxt->context, arg);
6067
0
    CAST_TO_NUMBER;
6068
0
    CHECK_TYPE(XPATH_NUMBER);
6069
0
    ctxt->value->floatval /= val;
6070
0
}
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
80.1k
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
80.1k
    xmlXPathObjectPtr arg;
6082
80.1k
    double arg1, arg2;
6083
6084
80.1k
    arg = xmlXPathValuePop(ctxt);
6085
80.1k
    if (arg == NULL)
6086
80.1k
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
80.1k
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
80.1k
    xmlXPathReleaseObject(ctxt->context, arg);
6089
80.1k
    CAST_TO_NUMBER;
6090
80.1k
    CHECK_TYPE(XPATH_NUMBER);
6091
80.1k
    arg1 = ctxt->value->floatval;
6092
80.1k
    if (arg2 == 0)
6093
69
  ctxt->value->floatval = xmlXPathNAN;
6094
80.1k
    else {
6095
80.1k
  ctxt->value->floatval = fmod(arg1, arg2);
6096
80.1k
    }
6097
80.1k
}
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
24.4k
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
24.4k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
24.4k
    if (cur == NULL)
6141
12.2k
        return(ctxt->context->node);
6142
12.2k
    return(NULL);
6143
24.4k
}
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
10.2k
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
10.2k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
10.2k
    if (cur == NULL) {
6157
7.17k
  if (ctxt->context->node == NULL) return(NULL);
6158
7.17k
  switch (ctxt->context->node->type) {
6159
1.65k
            case XML_ELEMENT_NODE:
6160
2.86k
            case XML_TEXT_NODE:
6161
2.86k
            case XML_CDATA_SECTION_NODE:
6162
2.86k
            case XML_ENTITY_REF_NODE:
6163
2.86k
            case XML_ENTITY_NODE:
6164
2.95k
            case XML_PI_NODE:
6165
2.96k
            case XML_COMMENT_NODE:
6166
2.96k
            case XML_NOTATION_NODE:
6167
2.96k
            case XML_DTD_NODE:
6168
2.96k
    return(ctxt->context->node->children);
6169
237
            case XML_DOCUMENT_NODE:
6170
237
            case XML_DOCUMENT_TYPE_NODE:
6171
237
            case XML_DOCUMENT_FRAG_NODE:
6172
237
            case XML_HTML_DOCUMENT_NODE:
6173
237
    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
643
            case XML_ATTRIBUTE_NODE:
6178
3.97k
      case XML_NAMESPACE_DECL:
6179
3.97k
      case XML_XINCLUDE_START:
6180
3.97k
      case XML_XINCLUDE_END:
6181
3.97k
    return(NULL);
6182
7.17k
  }
6183
0
  return(NULL);
6184
7.17k
    }
6185
3.09k
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
3.09k
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
3.09k
    return(cur->next);
6189
3.09k
}
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
123M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
123M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
123M
    if (cur == NULL) {
6203
64.4M
  cur = ctxt->context->node;
6204
64.4M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
64.4M
  switch (cur->type) {
6209
58.9M
            case XML_ELEMENT_NODE:
6210
58.9M
      case XML_DOCUMENT_FRAG_NODE:
6211
58.9M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
58.9M
            case XML_ENTITY_NODE:
6213
58.9M
    cur = cur->children;
6214
58.9M
    if (cur != NULL) {
6215
6.73M
        if (cur->type == XML_ELEMENT_NODE)
6216
2.01M
      return(cur);
6217
6.82M
        do {
6218
6.82M
      cur = cur->next;
6219
6.82M
        } while ((cur != NULL) &&
6220
4.39M
      (cur->type != XML_ELEMENT_NODE));
6221
4.71M
        return(cur);
6222
6.73M
    }
6223
52.2M
    return(NULL);
6224
349k
            case XML_DOCUMENT_NODE:
6225
349k
            case XML_HTML_DOCUMENT_NODE:
6226
349k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
5.17M
      default:
6228
5.17M
    return(NULL);
6229
64.4M
  }
6230
0
  return(NULL);
6231
64.4M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
58.8M
    switch (cur->type) {
6236
58.8M
  case XML_ELEMENT_NODE:
6237
58.8M
  case XML_TEXT_NODE:
6238
58.8M
  case XML_ENTITY_REF_NODE:
6239
58.8M
  case XML_ENTITY_NODE:
6240
58.8M
  case XML_CDATA_SECTION_NODE:
6241
58.8M
  case XML_PI_NODE:
6242
58.8M
  case XML_COMMENT_NODE:
6243
58.8M
  case XML_XINCLUDE_END:
6244
58.8M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
58.8M
    }
6249
58.8M
    if (cur->next != NULL) {
6250
56.7M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
46.9M
      return(cur->next);
6252
9.77M
  cur = cur->next;
6253
9.79M
  do {
6254
9.79M
      cur = cur->next;
6255
9.79M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
9.77M
  return(cur);
6257
56.7M
    }
6258
2.15M
    return(NULL);
6259
58.8M
}
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
375M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
375M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
375M
    if (cur == NULL) {
6274
2.88M
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
2.88M
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
2.86M
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
37.1k
      return(NULL);
6279
6280
2.84M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
372k
      return(ctxt->context->doc->children);
6282
2.47M
        return(ctxt->context->node->children);
6283
2.84M
    }
6284
6285
372M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
372M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
62.0M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
62.0M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
62.0M
      if (cur->type != XML_DTD_NODE)
6297
62.0M
    return(cur);
6298
62.0M
  }
6299
62.0M
    }
6300
6301
310M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
310M
    while (cur->next != NULL) {
6304
269M
  cur = cur->next;
6305
269M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
269M
      (cur->type != XML_DTD_NODE))
6307
269M
      return(cur);
6308
269M
    }
6309
6310
63.3M
    do {
6311
63.3M
        cur = cur->parent;
6312
63.3M
  if (cur == NULL) break;
6313
63.3M
  if (cur == ctxt->context->node) return(NULL);
6314
60.9M
  if (cur->next != NULL) {
6315
38.7M
      cur = cur->next;
6316
38.7M
      return(cur);
6317
38.7M
  }
6318
60.9M
    } while (cur != NULL);
6319
0
    return(cur);
6320
41.1M
}
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
188M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
188M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
188M
    if (cur == NULL)
6337
1.88M
        return(ctxt->context->node);
6338
6339
186M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
186M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
186M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
38.2k
        return(NULL);
6344
6345
186M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
186M
}
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
494k
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
494k
    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
494k
    if (cur == NULL) {
6365
249k
  if (ctxt->context->node == NULL) return(NULL);
6366
249k
  switch (ctxt->context->node->type) {
6367
134k
            case XML_ELEMENT_NODE:
6368
232k
            case XML_TEXT_NODE:
6369
234k
            case XML_CDATA_SECTION_NODE:
6370
234k
            case XML_ENTITY_REF_NODE:
6371
234k
            case XML_ENTITY_NODE:
6372
235k
            case XML_PI_NODE:
6373
236k
            case XML_COMMENT_NODE:
6374
236k
            case XML_NOTATION_NODE:
6375
236k
            case XML_DTD_NODE:
6376
236k
      case XML_ELEMENT_DECL:
6377
236k
      case XML_ATTRIBUTE_DECL:
6378
236k
      case XML_XINCLUDE_START:
6379
236k
      case XML_XINCLUDE_END:
6380
236k
      case XML_ENTITY_DECL:
6381
236k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
236k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
232k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
232k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
232k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
236k
    return(ctxt->context->node->parent);
6389
1.51k
            case XML_ATTRIBUTE_NODE: {
6390
1.51k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
1.51k
    return(att->parent);
6393
236k
      }
6394
3.32k
            case XML_DOCUMENT_NODE:
6395
3.32k
            case XML_DOCUMENT_TYPE_NODE:
6396
3.32k
            case XML_DOCUMENT_FRAG_NODE:
6397
3.32k
            case XML_HTML_DOCUMENT_NODE:
6398
3.32k
                return(NULL);
6399
7.92k
      case XML_NAMESPACE_DECL: {
6400
7.92k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
7.92k
    if ((ns->next != NULL) &&
6403
7.92k
        (ns->next->type != XML_NAMESPACE_DECL))
6404
7.92k
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
7.92k
      }
6407
249k
  }
6408
249k
    }
6409
245k
    return(NULL);
6410
494k
}
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
5.88M
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
5.88M
    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
5.88M
    if (cur == NULL) {
6433
10.9k
  if (ctxt->context->node == NULL) return(NULL);
6434
10.9k
  switch (ctxt->context->node->type) {
6435
6.82k
            case XML_ELEMENT_NODE:
6436
8.99k
            case XML_TEXT_NODE:
6437
8.99k
            case XML_CDATA_SECTION_NODE:
6438
8.99k
            case XML_ENTITY_REF_NODE:
6439
8.99k
            case XML_ENTITY_NODE:
6440
9.07k
            case XML_PI_NODE:
6441
9.08k
            case XML_COMMENT_NODE:
6442
9.08k
      case XML_DTD_NODE:
6443
9.08k
      case XML_ELEMENT_DECL:
6444
9.08k
      case XML_ATTRIBUTE_DECL:
6445
9.08k
      case XML_ENTITY_DECL:
6446
9.08k
            case XML_NOTATION_NODE:
6447
9.08k
      case XML_XINCLUDE_START:
6448
9.08k
      case XML_XINCLUDE_END:
6449
9.08k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
9.08k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
8.86k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
8.86k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
8.86k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
9.08k
    return(ctxt->context->node->parent);
6457
122
            case XML_ATTRIBUTE_NODE: {
6458
122
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
122
    return(tmp->parent);
6461
9.08k
      }
6462
341
            case XML_DOCUMENT_NODE:
6463
341
            case XML_DOCUMENT_TYPE_NODE:
6464
341
            case XML_DOCUMENT_FRAG_NODE:
6465
341
            case XML_HTML_DOCUMENT_NODE:
6466
341
                return(NULL);
6467
1.36k
      case XML_NAMESPACE_DECL: {
6468
1.36k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
1.36k
    if ((ns->next != NULL) &&
6471
1.36k
        (ns->next->type != XML_NAMESPACE_DECL))
6472
1.36k
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
1.36k
      }
6476
10.9k
  }
6477
0
  return(NULL);
6478
10.9k
    }
6479
5.86M
    if (cur == ctxt->context->doc->children)
6480
25.8k
  return((xmlNodePtr) ctxt->context->doc);
6481
5.84M
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
610k
  return(NULL);
6483
5.23M
    switch (cur->type) {
6484
4.74M
  case XML_ELEMENT_NODE:
6485
4.87M
  case XML_TEXT_NODE:
6486
4.87M
  case XML_CDATA_SECTION_NODE:
6487
4.87M
  case XML_ENTITY_REF_NODE:
6488
4.87M
  case XML_ENTITY_NODE:
6489
4.87M
  case XML_PI_NODE:
6490
4.87M
  case XML_COMMENT_NODE:
6491
4.87M
  case XML_NOTATION_NODE:
6492
4.87M
  case XML_DTD_NODE:
6493
4.87M
        case XML_ELEMENT_DECL:
6494
4.87M
        case XML_ATTRIBUTE_DECL:
6495
4.87M
        case XML_ENTITY_DECL:
6496
4.87M
  case XML_XINCLUDE_START:
6497
4.87M
  case XML_XINCLUDE_END:
6498
4.87M
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
4.87M
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
4.28M
    ((cur->parent->name[0] == ' ') ||
6502
4.28M
     (xmlStrEqual(cur->parent->name,
6503
4.28M
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
4.87M
      return(cur->parent);
6506
20.7k
  case XML_ATTRIBUTE_NODE: {
6507
20.7k
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
20.7k
      return(att->parent);
6510
4.87M
  }
6511
340k
  case XML_NAMESPACE_DECL: {
6512
340k
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
340k
      if ((ns->next != NULL) &&
6515
340k
          (ns->next->type != XML_NAMESPACE_DECL))
6516
340k
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
340k
  }
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
5.23M
    }
6526
0
    return(NULL);
6527
5.23M
}
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
6.41M
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
6.41M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
6.41M
    if (cur == NULL)
6544
600k
        return(ctxt->context->node);
6545
5.81M
    return(xmlXPathNextAncestor(ctxt, cur));
6546
6.41M
}
6547
6548
/**
6549
 * Traversal function for the "following-sibling" direction
6550
 * The following-sibling axis contains the following siblings of the context
6551
 * node in document order.
6552
 *
6553
 * @param ctxt  the XPath Parser context
6554
 * @param cur  the current node in the traversal
6555
 * @returns the next element following that axis
6556
 */
6557
xmlNode *
6558
0
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
0
        return(NULL);
6563
6564
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6565
0
        return(NULL);
6566
6567
0
    if (cur == NULL)
6568
0
        cur = ctxt->context->node;
6569
6570
0
    if (cur->type == XML_DOCUMENT_NODE)
6571
0
        return(NULL);
6572
6573
0
    return(cur->next);
6574
0
}
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
0
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6588
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6590
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6591
0
        return(NULL);
6592
6593
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6594
0
        return(NULL);
6595
6596
0
    if (cur == NULL) {
6597
0
        cur = ctxt->context->node;
6598
0
    } else if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6599
0
        cur = cur->prev;
6600
0
        if (cur == NULL)
6601
0
            cur = ctxt->context->node;
6602
0
    }
6603
6604
0
    if (cur->type == XML_DOCUMENT_NODE)
6605
0
        return(NULL);
6606
6607
0
    return(cur->prev);
6608
0
}
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
0
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6623
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6624
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6625
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6626
0
        return(cur->children);
6627
6628
0
    if (cur == NULL) {
6629
0
        cur = ctxt->context->node;
6630
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6631
0
            cur = cur->parent;
6632
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6633
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6634
6635
0
            if ((ns->next == NULL) ||
6636
0
                (ns->next->type == XML_NAMESPACE_DECL))
6637
0
                return (NULL);
6638
0
            cur = (xmlNodePtr) ns->next;
6639
0
        }
6640
0
    }
6641
6642
    /* ERROR */
6643
0
    if (cur == NULL)
6644
0
        return(NULL);
6645
6646
0
    if (cur->type == XML_DOCUMENT_NODE)
6647
0
        return(NULL);
6648
6649
0
    if (cur->next != NULL)
6650
0
        return(cur->next);
6651
6652
0
    do {
6653
0
        cur = cur->parent;
6654
0
        if (cur == NULL)
6655
0
            break;
6656
0
        if (cur == (xmlNodePtr) ctxt->context->doc)
6657
0
            return(NULL);
6658
0
        if (cur->next != NULL && cur->type != XML_DOCUMENT_NODE)
6659
0
            return(cur->next);
6660
0
    } while (cur != NULL);
6661
6662
0
    return(cur);
6663
0
}
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
0
{
6757
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6758
0
    if (cur == NULL) {
6759
0
        cur = ctxt->context->node;
6760
0
        if (cur == NULL)
6761
0
            return (NULL);
6762
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6763
0
            cur = cur->parent;
6764
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6765
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6766
6767
0
            if ((ns->next == NULL) ||
6768
0
                (ns->next->type == XML_NAMESPACE_DECL))
6769
0
                return (NULL);
6770
0
            cur = (xmlNodePtr) ns->next;
6771
0
        }
6772
0
        ctxt->ancestor = cur->parent;
6773
0
    }
6774
6775
0
    if (cur->type == XML_NAMESPACE_DECL || cur->type == XML_DOCUMENT_NODE)
6776
0
        return(NULL);
6777
6778
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6779
0
  cur = cur->prev;
6780
6781
0
    while (cur->prev == NULL) {
6782
0
        cur = cur->parent;
6783
0
        if (cur == NULL)
6784
0
            return (NULL);
6785
0
        if (cur == ctxt->context->doc->children)
6786
0
            return (NULL);
6787
0
        if (cur != ctxt->ancestor)
6788
0
            return (cur);
6789
0
        ctxt->ancestor = cur->parent;
6790
0
    }
6791
6792
0
    if (cur->type == XML_DOCUMENT_NODE)
6793
0
        return(NULL);
6794
6795
0
    cur = cur->prev;
6796
0
    while (cur->last != NULL)
6797
0
        cur = cur->last;
6798
0
    return (cur);
6799
0
}
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.30M
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6815
1.30M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6816
1.30M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6817
1.06M
    if (cur == NULL) {
6818
289k
        if (ctxt->context->tmpNsList != NULL)
6819
0
      xmlFree(ctxt->context->tmpNsList);
6820
289k
  ctxt->context->tmpNsNr = 0;
6821
289k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6822
289k
                             &ctxt->context->tmpNsList) < 0) {
6823
0
            xmlXPathPErrMemory(ctxt);
6824
0
            return(NULL);
6825
0
        }
6826
289k
        if (ctxt->context->tmpNsList != NULL) {
6827
771k
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6828
485k
                ctxt->context->tmpNsNr++;
6829
485k
            }
6830
286k
        }
6831
289k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6832
289k
    }
6833
774k
    if (ctxt->context->tmpNsNr > 0) {
6834
485k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6835
485k
    } else {
6836
289k
  if (ctxt->context->tmpNsList != NULL)
6837
286k
      xmlFree(ctxt->context->tmpNsList);
6838
289k
  ctxt->context->tmpNsList = NULL;
6839
289k
  return(NULL);
6840
289k
    }
6841
774k
}
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
149M
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6853
149M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854
149M
    if (ctxt->context->node == NULL)
6855
0
  return(NULL);
6856
149M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6857
45.1M
  return(NULL);
6858
104M
    if (cur == NULL) {
6859
92.0M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6860
0
      return(NULL);
6861
92.0M
        return((xmlNodePtr)ctxt->context->node->properties);
6862
92.0M
    }
6863
12.0M
    return((xmlNodePtr)cur->next);
6864
104M
}
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
892k
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6888
892k
    if ((ctxt == NULL) || (ctxt->context == NULL))
6889
0
  return;
6890
892k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6891
892k
                                            (xmlNodePtr) ctxt->context->doc));
6892
892k
}
6893
6894
/************************************************************************
6895
 *                  *
6896
 *    The explicit core function library      *
6897
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6898
 *                  *
6899
 ************************************************************************/
6900
6901
6902
/**
6903
 * Implement the last() XPath function
6904
 *    number last()
6905
 * The last function returns the number of nodes in the context node list.
6906
 *
6907
 * @param ctxt  the XPath Parser context
6908
 * @param nargs  the number of arguments
6909
 */
6910
void
6911
0
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6912
0
    CHECK_ARITY(0);
6913
0
    if (ctxt->context->contextSize >= 0) {
6914
0
  xmlXPathValuePush(ctxt,
6915
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6916
0
    } else {
6917
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6918
0
    }
6919
0
}
6920
6921
/**
6922
 * Implement the position() XPath function
6923
 *    number position()
6924
 * The position function returns the position of the context node in the
6925
 * context node list. The first position is 1, and so the last position
6926
 * will be equal to last().
6927
 *
6928
 * @param ctxt  the XPath Parser context
6929
 * @param nargs  the number of arguments
6930
 */
6931
void
6932
0
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6933
0
    CHECK_ARITY(0);
6934
0
    if (ctxt->context->proximityPosition >= 0) {
6935
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6936
0
            (double) ctxt->context->proximityPosition));
6937
0
    } else {
6938
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6939
0
    }
6940
0
}
6941
6942
/**
6943
 * Implement the count() XPath function
6944
 *    number count(node-set)
6945
 *
6946
 * @param ctxt  the XPath Parser context
6947
 * @param nargs  the number of arguments
6948
 */
6949
void
6950
17.4k
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6951
17.4k
    xmlXPathObjectPtr cur;
6952
6953
52.4k
    CHECK_ARITY(1);
6954
52.4k
    if ((ctxt->value == NULL) ||
6955
17.4k
  ((ctxt->value->type != XPATH_NODESET) &&
6956
4
   (ctxt->value->type != XPATH_XSLT_TREE)))
6957
17.4k
  XP_ERROR(XPATH_INVALID_TYPE);
6958
17.4k
    cur = xmlXPathValuePop(ctxt);
6959
6960
17.4k
    if ((cur == NULL) || (cur->nodesetval == NULL))
6961
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6962
17.4k
    else
6963
17.4k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6964
17.4k
      (double) cur->nodesetval->nodeNr));
6965
17.4k
    xmlXPathReleaseObject(ctxt->context, cur);
6966
17.4k
}
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
1.26k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6977
1.26k
    xmlNodeSetPtr ret;
6978
1.26k
    const xmlChar *cur = ids;
6979
1.26k
    xmlChar *ID;
6980
1.26k
    xmlAttrPtr attr;
6981
1.26k
    xmlNodePtr elem = NULL;
6982
6983
1.26k
    if (ids == NULL) return(NULL);
6984
6985
1.26k
    ret = xmlXPathNodeSetCreate(NULL);
6986
1.26k
    if (ret == NULL)
6987
0
        return(ret);
6988
6989
1.26k
    while (IS_BLANK_CH(*cur)) cur++;
6990
2.78k
    while (*cur != 0) {
6991
80.8k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6992
79.3k
      cur++;
6993
6994
1.51k
        ID = xmlStrndup(ids, cur - ids);
6995
1.51k
  if (ID == NULL) {
6996
0
            xmlXPathFreeNodeSet(ret);
6997
0
            return(NULL);
6998
0
        }
6999
        /*
7000
         * We used to check the fact that the value passed
7001
         * was an NCName, but this generated much troubles for
7002
         * me and Aleksey Sanin, people blatantly violated that
7003
         * constraint, like Visa3D spec.
7004
         * if (xmlValidateNCName(ID, 1) == 0)
7005
         */
7006
1.51k
        attr = xmlGetID(doc, ID);
7007
1.51k
        xmlFree(ID);
7008
1.51k
        if (attr != NULL) {
7009
1.20k
            if (attr->type == XML_ATTRIBUTE_NODE)
7010
1.20k
                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
1.20k
            if (elem != NULL) {
7016
1.20k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7017
0
                    xmlXPathFreeNodeSet(ret);
7018
0
                    return(NULL);
7019
0
                }
7020
1.20k
            }
7021
1.20k
        }
7022
7023
12.1k
  while (IS_BLANK_CH(*cur)) cur++;
7024
1.51k
  ids = cur;
7025
1.51k
    }
7026
1.26k
    return(ret);
7027
1.26k
}
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
1.26k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7048
1.26k
    xmlChar *tokens;
7049
1.26k
    xmlNodeSetPtr ret;
7050
1.26k
    xmlXPathObjectPtr obj;
7051
7052
3.79k
    CHECK_ARITY(1);
7053
3.79k
    obj = xmlXPathValuePop(ctxt);
7054
3.79k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7055
1.26k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7056
0
  xmlNodeSetPtr ns;
7057
0
  int i;
7058
7059
0
  ret = xmlXPathNodeSetCreate(NULL);
7060
0
        if (ret == NULL)
7061
0
            xmlXPathPErrMemory(ctxt);
7062
7063
0
  if (obj->nodesetval != NULL) {
7064
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7065
0
    tokens =
7066
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7067
0
                if (tokens == NULL)
7068
0
                    xmlXPathPErrMemory(ctxt);
7069
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7070
0
                if (ns == NULL)
7071
0
                    xmlXPathPErrMemory(ctxt);
7072
0
    ret = xmlXPathNodeSetMerge(ret, ns);
7073
0
                if (ret == NULL)
7074
0
                    xmlXPathPErrMemory(ctxt);
7075
0
    xmlXPathFreeNodeSet(ns);
7076
0
    if (tokens != NULL)
7077
0
        xmlFree(tokens);
7078
0
      }
7079
0
  }
7080
0
  xmlXPathReleaseObject(ctxt->context, obj);
7081
0
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7082
0
  return;
7083
0
    }
7084
1.26k
    tokens = xmlXPathCastToString(obj);
7085
1.26k
    if (tokens == NULL)
7086
0
        xmlXPathPErrMemory(ctxt);
7087
1.26k
    xmlXPathReleaseObject(ctxt->context, obj);
7088
1.26k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7089
1.26k
    if (ret == NULL)
7090
0
        xmlXPathPErrMemory(ctxt);
7091
1.26k
    xmlFree(tokens);
7092
1.26k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7093
1.26k
}
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
0
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7109
0
    xmlXPathObjectPtr cur;
7110
7111
0
    if (ctxt == NULL) return;
7112
7113
0
    if (nargs == 0) {
7114
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7115
0
  nargs = 1;
7116
0
    }
7117
7118
0
    CHECK_ARITY(1);
7119
0
    if ((ctxt->value == NULL) ||
7120
0
  ((ctxt->value->type != XPATH_NODESET) &&
7121
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7122
0
  XP_ERROR(XPATH_INVALID_TYPE);
7123
0
    cur = xmlXPathValuePop(ctxt);
7124
7125
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7126
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7127
0
    } else {
7128
0
  int i = 0; /* Should be first in document order !!!!! */
7129
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7130
0
  case XML_ELEMENT_NODE:
7131
0
  case XML_ATTRIBUTE_NODE:
7132
0
  case XML_PI_NODE:
7133
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7134
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7135
0
      else
7136
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7137
0
      cur->nodesetval->nodeTab[i]->name));
7138
0
      break;
7139
0
  case XML_NAMESPACE_DECL:
7140
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7141
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7142
0
      break;
7143
0
  default:
7144
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7145
0
  }
7146
0
    }
7147
0
    xmlXPathReleaseObject(ctxt->context, cur);
7148
0
}
7149
7150
/**
7151
 * Implement the namespace-uri() XPath function
7152
 *    string namespace-uri(node-set?)
7153
 * The namespace-uri function returns a string containing the
7154
 * namespace URI of the expanded name of the node in the argument
7155
 * node-set that is first in document order. If the node-set is empty,
7156
 * the first node has no name, or the expanded name has no namespace
7157
 * URI, an empty string is returned. If the argument is omitted it
7158
 * defaults to the context node.
7159
 *
7160
 * @param ctxt  the XPath Parser context
7161
 * @param nargs  the number of arguments
7162
 */
7163
void
7164
0
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7165
0
    xmlXPathObjectPtr cur;
7166
7167
0
    if (ctxt == NULL) return;
7168
7169
0
    if (nargs == 0) {
7170
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7171
0
  nargs = 1;
7172
0
    }
7173
0
    CHECK_ARITY(1);
7174
0
    if ((ctxt->value == NULL) ||
7175
0
  ((ctxt->value->type != XPATH_NODESET) &&
7176
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7177
0
  XP_ERROR(XPATH_INVALID_TYPE);
7178
0
    cur = xmlXPathValuePop(ctxt);
7179
7180
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7181
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7182
0
    } else {
7183
0
  int i = 0; /* Should be first in document order !!!!! */
7184
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7185
0
  case XML_ELEMENT_NODE:
7186
0
  case XML_ATTRIBUTE_NODE:
7187
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7188
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7189
0
      else
7190
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7191
0
        cur->nodesetval->nodeTab[i]->ns->href));
7192
0
      break;
7193
0
  default:
7194
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7195
0
  }
7196
0
    }
7197
0
    xmlXPathReleaseObject(ctxt->context, cur);
7198
0
}
7199
7200
/**
7201
 * Implement the name() XPath function
7202
 *    string name(node-set?)
7203
 * The name function returns a string containing a QName representing
7204
 * the name of the node in the argument node-set that is first in document
7205
 * order. The QName must represent the name with respect to the namespace
7206
 * declarations in effect on the node whose name is being represented.
7207
 * Typically, this will be the form in which the name occurred in the XML
7208
 * source. This need not be the case if there are namespace declarations
7209
 * in effect on the node that associate multiple prefixes with the same
7210
 * namespace. However, an implementation may include information about
7211
 * the original prefix in its representation of nodes; in this case, an
7212
 * implementation can ensure that the returned string is always the same
7213
 * as the QName used in the XML source. If the argument it omitted it
7214
 * defaults to the context node.
7215
 * Libxml keep the original prefix so the "real qualified name" used is
7216
 * returned.
7217
 *
7218
 * @param ctxt  the XPath Parser context
7219
 * @param nargs  the number of arguments
7220
 */
7221
static void
7222
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7223
13.2k
{
7224
13.2k
    xmlXPathObjectPtr cur;
7225
7226
13.2k
    if (nargs == 0) {
7227
13.2k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7228
13.2k
        nargs = 1;
7229
13.2k
    }
7230
7231
39.7k
    CHECK_ARITY(1);
7232
39.7k
    if ((ctxt->value == NULL) ||
7233
13.2k
        ((ctxt->value->type != XPATH_NODESET) &&
7234
1
         (ctxt->value->type != XPATH_XSLT_TREE)))
7235
13.2k
        XP_ERROR(XPATH_INVALID_TYPE);
7236
13.2k
    cur = xmlXPathValuePop(ctxt);
7237
7238
13.2k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7239
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7240
13.2k
    } else {
7241
13.2k
        int i = 0;              /* Should be first in document order !!!!! */
7242
7243
13.2k
        switch (cur->nodesetval->nodeTab[i]->type) {
7244
13.2k
            case XML_ELEMENT_NODE:
7245
13.2k
            case XML_ATTRIBUTE_NODE:
7246
13.2k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7247
0
        xmlXPathValuePush(ctxt,
7248
0
      xmlXPathCacheNewCString(ctxt, ""));
7249
13.2k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7250
13.2k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7251
13.2k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7252
13.2k
          cur->nodesetval->nodeTab[i]->name));
7253
13.2k
    } else {
7254
0
        xmlChar *fullname;
7255
7256
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7257
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
7258
0
             NULL, 0);
7259
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7260
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7261
0
        if (fullname == NULL)
7262
0
                        xmlXPathPErrMemory(ctxt);
7263
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7264
0
                }
7265
13.2k
                break;
7266
0
            default:
7267
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7268
0
        cur->nodesetval->nodeTab[i]));
7269
0
                xmlXPathLocalNameFunction(ctxt, 1);
7270
13.2k
        }
7271
13.2k
    }
7272
13.2k
    xmlXPathReleaseObject(ctxt->context, cur);
7273
13.2k
}
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
0
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7313
0
    xmlXPathObjectPtr cur;
7314
0
    xmlChar *stringval;
7315
7316
0
    if (ctxt == NULL) return;
7317
0
    if (nargs == 0) {
7318
0
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7319
0
        if (stringval == NULL)
7320
0
            xmlXPathPErrMemory(ctxt);
7321
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7322
0
  return;
7323
0
    }
7324
7325
0
    CHECK_ARITY(1);
7326
0
    cur = xmlXPathValuePop(ctxt);
7327
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7328
0
    if (cur->type != XPATH_STRING) {
7329
0
        stringval = xmlXPathCastToString(cur);
7330
0
        if (stringval == NULL)
7331
0
            xmlXPathPErrMemory(ctxt);
7332
0
        xmlXPathReleaseObject(ctxt->context, cur);
7333
0
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7334
0
    }
7335
0
    xmlXPathValuePush(ctxt, cur);
7336
0
}
7337
7338
/**
7339
 * Implement the string-length() XPath function
7340
 *    number string-length(string?)
7341
 * The string-length returns the number of characters in the string
7342
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7343
 * the context node converted to a string, in other words the value
7344
 * of the context node.
7345
 *
7346
 * @param ctxt  the XPath Parser context
7347
 * @param nargs  the number of arguments
7348
 */
7349
void
7350
0
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7351
0
    xmlXPathObjectPtr cur;
7352
7353
0
    if (nargs == 0) {
7354
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7355
0
      return;
7356
0
  if (ctxt->context->node == NULL) {
7357
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7358
0
  } else {
7359
0
      xmlChar *content;
7360
7361
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7362
0
            if (content == NULL)
7363
0
                xmlXPathPErrMemory(ctxt);
7364
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7365
0
    xmlUTF8Strlen(content)));
7366
0
      xmlFree(content);
7367
0
  }
7368
0
  return;
7369
0
    }
7370
0
    CHECK_ARITY(1);
7371
0
    CAST_TO_STRING;
7372
0
    CHECK_TYPE(XPATH_STRING);
7373
0
    cur = xmlXPathValuePop(ctxt);
7374
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7375
0
  xmlUTF8Strlen(cur->stringval)));
7376
0
    xmlXPathReleaseObject(ctxt->context, cur);
7377
0
}
7378
7379
/**
7380
 * Implement the concat() XPath function
7381
 *    string concat(string, string, string*)
7382
 * The concat function returns the concatenation of its arguments.
7383
 *
7384
 * @param ctxt  the XPath Parser context
7385
 * @param nargs  the number of arguments
7386
 */
7387
void
7388
0
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7389
0
    xmlXPathObjectPtr cur, newobj;
7390
0
    xmlChar *tmp;
7391
7392
0
    if (ctxt == NULL) return;
7393
0
    if (nargs < 2) {
7394
0
  CHECK_ARITY(2);
7395
0
    }
7396
7397
0
    CAST_TO_STRING;
7398
0
    cur = xmlXPathValuePop(ctxt);
7399
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7400
0
  xmlXPathReleaseObject(ctxt->context, cur);
7401
0
  return;
7402
0
    }
7403
0
    nargs--;
7404
7405
0
    while (nargs > 0) {
7406
0
  CAST_TO_STRING;
7407
0
  newobj = xmlXPathValuePop(ctxt);
7408
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7409
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7410
0
      xmlXPathReleaseObject(ctxt->context, cur);
7411
0
      XP_ERROR(XPATH_INVALID_TYPE);
7412
0
  }
7413
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7414
0
        if (tmp == NULL)
7415
0
            xmlXPathPErrMemory(ctxt);
7416
0
  newobj->stringval = cur->stringval;
7417
0
  cur->stringval = tmp;
7418
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7419
0
  nargs--;
7420
0
    }
7421
0
    xmlXPathValuePush(ctxt, cur);
7422
0
}
7423
7424
/**
7425
 * Implement the contains() XPath function
7426
 *    boolean contains(string, string)
7427
 * The contains function returns true if the first argument string
7428
 * contains the second argument string, and otherwise returns false.
7429
 *
7430
 * @param ctxt  the XPath Parser context
7431
 * @param nargs  the number of arguments
7432
 */
7433
void
7434
0
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7435
0
    xmlXPathObjectPtr hay, needle;
7436
7437
0
    CHECK_ARITY(2);
7438
0
    CAST_TO_STRING;
7439
0
    CHECK_TYPE(XPATH_STRING);
7440
0
    needle = xmlXPathValuePop(ctxt);
7441
0
    CAST_TO_STRING;
7442
0
    hay = xmlXPathValuePop(ctxt);
7443
7444
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7445
0
  xmlXPathReleaseObject(ctxt->context, hay);
7446
0
  xmlXPathReleaseObject(ctxt->context, needle);
7447
0
  XP_ERROR(XPATH_INVALID_TYPE);
7448
0
    }
7449
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7450
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7451
0
    else
7452
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7453
0
    xmlXPathReleaseObject(ctxt->context, hay);
7454
0
    xmlXPathReleaseObject(ctxt->context, needle);
7455
0
}
7456
7457
/**
7458
 * Implement the starts-with() XPath function
7459
 *    boolean starts-with(string, string)
7460
 * The starts-with function returns true if the first argument string
7461
 * starts with the second argument string, and otherwise returns false.
7462
 *
7463
 * @param ctxt  the XPath Parser context
7464
 * @param nargs  the number of arguments
7465
 */
7466
void
7467
0
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7468
0
    xmlXPathObjectPtr hay, needle;
7469
0
    int n;
7470
7471
0
    CHECK_ARITY(2);
7472
0
    CAST_TO_STRING;
7473
0
    CHECK_TYPE(XPATH_STRING);
7474
0
    needle = xmlXPathValuePop(ctxt);
7475
0
    CAST_TO_STRING;
7476
0
    hay = xmlXPathValuePop(ctxt);
7477
7478
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7479
0
  xmlXPathReleaseObject(ctxt->context, hay);
7480
0
  xmlXPathReleaseObject(ctxt->context, needle);
7481
0
  XP_ERROR(XPATH_INVALID_TYPE);
7482
0
    }
7483
0
    n = xmlStrlen(needle->stringval);
7484
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7485
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7486
0
    else
7487
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7488
0
    xmlXPathReleaseObject(ctxt->context, hay);
7489
0
    xmlXPathReleaseObject(ctxt->context, needle);
7490
0
}
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
0
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7521
0
    xmlXPathObjectPtr str, start, len;
7522
0
    double le=0, in;
7523
0
    int i = 1, j = INT_MAX;
7524
7525
0
    if (nargs < 2) {
7526
0
  CHECK_ARITY(2);
7527
0
    }
7528
0
    if (nargs > 3) {
7529
0
  CHECK_ARITY(3);
7530
0
    }
7531
    /*
7532
     * take care of possible last (position) argument
7533
    */
7534
0
    if (nargs == 3) {
7535
0
  CAST_TO_NUMBER;
7536
0
  CHECK_TYPE(XPATH_NUMBER);
7537
0
  len = xmlXPathValuePop(ctxt);
7538
0
  le = len->floatval;
7539
0
  xmlXPathReleaseObject(ctxt->context, len);
7540
0
    }
7541
7542
0
    CAST_TO_NUMBER;
7543
0
    CHECK_TYPE(XPATH_NUMBER);
7544
0
    start = xmlXPathValuePop(ctxt);
7545
0
    in = start->floatval;
7546
0
    xmlXPathReleaseObject(ctxt->context, start);
7547
0
    CAST_TO_STRING;
7548
0
    CHECK_TYPE(XPATH_STRING);
7549
0
    str = xmlXPathValuePop(ctxt);
7550
7551
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7552
0
        i = INT_MAX;
7553
0
    } else if (in >= 1.0) {
7554
0
        i = (int)in;
7555
0
        if (in - floor(in) >= 0.5)
7556
0
            i += 1;
7557
0
    }
7558
7559
0
    if (nargs == 3) {
7560
0
        double rin, rle, end;
7561
7562
0
        rin = floor(in);
7563
0
        if (in - rin >= 0.5)
7564
0
            rin += 1.0;
7565
7566
0
        rle = floor(le);
7567
0
        if (le - rle >= 0.5)
7568
0
            rle += 1.0;
7569
7570
0
        end = rin + rle;
7571
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7572
0
            j = 1;
7573
0
        } else if (end < INT_MAX) {
7574
0
            j = (int)end;
7575
0
        }
7576
0
    }
7577
7578
0
    i -= 1;
7579
0
    j -= 1;
7580
7581
0
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7582
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7583
0
        if (ret == NULL)
7584
0
            xmlXPathPErrMemory(ctxt);
7585
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7586
0
  xmlFree(ret);
7587
0
    } else {
7588
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7589
0
    }
7590
7591
0
    xmlXPathReleaseObject(ctxt->context, str);
7592
0
}
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
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7608
0
    xmlXPathObjectPtr str = NULL;
7609
0
    xmlXPathObjectPtr find = NULL;
7610
0
    const xmlChar *point;
7611
0
    xmlChar *result;
7612
7613
0
    CHECK_ARITY(2);
7614
0
    CAST_TO_STRING;
7615
0
    find = xmlXPathValuePop(ctxt);
7616
0
    CAST_TO_STRING;
7617
0
    str = xmlXPathValuePop(ctxt);
7618
0
    if (ctxt->error != 0)
7619
0
        goto error;
7620
7621
0
    point = xmlStrstr(str->stringval, find->stringval);
7622
0
    if (point == NULL) {
7623
0
        result = xmlStrdup(BAD_CAST "");
7624
0
    } else {
7625
0
        result = xmlStrndup(str->stringval, point - str->stringval);
7626
0
    }
7627
0
    if (result == NULL) {
7628
0
        xmlXPathPErrMemory(ctxt);
7629
0
        goto error;
7630
0
    }
7631
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7632
7633
0
error:
7634
0
    xmlXPathReleaseObject(ctxt->context, str);
7635
0
    xmlXPathReleaseObject(ctxt->context, find);
7636
0
}
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
0
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7653
0
    xmlXPathObjectPtr str = NULL;
7654
0
    xmlXPathObjectPtr find = NULL;
7655
0
    const xmlChar *point;
7656
0
    xmlChar *result;
7657
7658
0
    CHECK_ARITY(2);
7659
0
    CAST_TO_STRING;
7660
0
    find = xmlXPathValuePop(ctxt);
7661
0
    CAST_TO_STRING;
7662
0
    str = xmlXPathValuePop(ctxt);
7663
0
    if (ctxt->error != 0)
7664
0
        goto error;
7665
7666
0
    point = xmlStrstr(str->stringval, find->stringval);
7667
0
    if (point == NULL) {
7668
0
        result = xmlStrdup(BAD_CAST "");
7669
0
    } else {
7670
0
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7671
0
    }
7672
0
    if (result == NULL) {
7673
0
        xmlXPathPErrMemory(ctxt);
7674
0
        goto error;
7675
0
    }
7676
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7677
7678
0
error:
7679
0
    xmlXPathReleaseObject(ctxt->context, str);
7680
0
    xmlXPathReleaseObject(ctxt->context, find);
7681
0
}
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
0
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7698
0
    xmlChar *source, *target;
7699
0
    int blank;
7700
7701
0
    if (ctxt == NULL) return;
7702
0
    if (nargs == 0) {
7703
        /* Use current context node */
7704
0
        source = xmlXPathCastNodeToString(ctxt->context->node);
7705
0
        if (source == NULL)
7706
0
            xmlXPathPErrMemory(ctxt);
7707
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7708
0
        nargs = 1;
7709
0
    }
7710
7711
0
    CHECK_ARITY(1);
7712
0
    CAST_TO_STRING;
7713
0
    CHECK_TYPE(XPATH_STRING);
7714
0
    source = ctxt->value->stringval;
7715
0
    if (source == NULL)
7716
0
        return;
7717
0
    target = source;
7718
7719
    /* Skip leading whitespaces */
7720
0
    while (IS_BLANK_CH(*source))
7721
0
        source++;
7722
7723
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7724
0
    blank = 0;
7725
0
    while (*source) {
7726
0
        if (IS_BLANK_CH(*source)) {
7727
0
      blank = 1;
7728
0
        } else {
7729
0
            if (blank) {
7730
0
                *target++ = 0x20;
7731
0
                blank = 0;
7732
0
            }
7733
0
            *target++ = *source;
7734
0
        }
7735
0
        source++;
7736
0
    }
7737
0
    *target = 0;
7738
0
}
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
0
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7763
0
    xmlXPathObjectPtr str = NULL;
7764
0
    xmlXPathObjectPtr from = NULL;
7765
0
    xmlXPathObjectPtr to = NULL;
7766
0
    xmlBufPtr target;
7767
0
    int offset, max;
7768
0
    int ch;
7769
0
    const xmlChar *point;
7770
0
    xmlChar *cptr, *content;
7771
7772
0
    CHECK_ARITY(3);
7773
7774
0
    CAST_TO_STRING;
7775
0
    to = xmlXPathValuePop(ctxt);
7776
0
    CAST_TO_STRING;
7777
0
    from = xmlXPathValuePop(ctxt);
7778
0
    CAST_TO_STRING;
7779
0
    str = xmlXPathValuePop(ctxt);
7780
0
    if (ctxt->error != 0)
7781
0
        goto error;
7782
7783
    /*
7784
     * Account for quadratic runtime
7785
     */
7786
0
    if (ctxt->context->opLimit != 0) {
7787
0
        unsigned long f1 = xmlStrlen(from->stringval);
7788
0
        unsigned long f2 = xmlStrlen(str->stringval);
7789
7790
0
        if ((f1 > 0) && (f2 > 0)) {
7791
0
            unsigned long p;
7792
7793
0
            f1 = f1 / 10 + 1;
7794
0
            f2 = f2 / 10 + 1;
7795
0
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7796
0
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7797
0
                goto error;
7798
0
        }
7799
0
    }
7800
7801
0
    target = xmlBufCreate(50);
7802
0
    if (target == NULL) {
7803
0
        xmlXPathPErrMemory(ctxt);
7804
0
        goto error;
7805
0
    }
7806
7807
0
    max = xmlUTF8Strlen(to->stringval);
7808
0
    for (cptr = str->stringval; (ch=*cptr); ) {
7809
0
        offset = xmlUTF8Strloc(from->stringval, cptr);
7810
0
        if (offset >= 0) {
7811
0
            if (offset < max) {
7812
0
                point = xmlUTF8Strpos(to->stringval, offset);
7813
0
                if (point)
7814
0
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7815
0
            }
7816
0
        } else
7817
0
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7818
7819
        /* Step to next character in input */
7820
0
        cptr++;
7821
0
        if ( ch & 0x80 ) {
7822
            /* if not simple ascii, verify proper format */
7823
0
            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
0
            while ( (ch <<= 1) & 0x80 )
7829
0
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7830
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7831
0
                    break;
7832
0
                }
7833
0
            if (ch & 0x80) /* must have had error encountered */
7834
0
                break;
7835
0
        }
7836
0
    }
7837
7838
0
    content = xmlBufDetach(target);
7839
0
    if (content == NULL)
7840
0
        xmlXPathPErrMemory(ctxt);
7841
0
    else
7842
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7843
0
    xmlBufFree(target);
7844
0
error:
7845
0
    xmlXPathReleaseObject(ctxt->context, str);
7846
0
    xmlXPathReleaseObject(ctxt->context, from);
7847
0
    xmlXPathReleaseObject(ctxt->context, to);
7848
0
}
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
1.47M
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7864
1.47M
    xmlXPathObjectPtr cur;
7865
7866
4.43M
    CHECK_ARITY(1);
7867
4.43M
    cur = xmlXPathValuePop(ctxt);
7868
4.43M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7869
1.47M
    if (cur->type != XPATH_BOOLEAN) {
7870
966k
        int boolval = xmlXPathCastToBoolean(cur);
7871
7872
966k
        xmlXPathReleaseObject(ctxt->context, cur);
7873
966k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7874
966k
    }
7875
1.47M
    xmlXPathValuePush(ctxt, cur);
7876
1.47M
}
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
0
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7889
0
    CHECK_ARITY(1);
7890
0
    CAST_TO_BOOLEAN;
7891
0
    CHECK_TYPE(XPATH_BOOLEAN);
7892
0
    ctxt->value->boolval = ! ctxt->value->boolval;
7893
0
}
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
0
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7904
0
    CHECK_ARITY(0);
7905
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7906
0
}
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
0
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7917
0
    CHECK_ARITY(0);
7918
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7919
0
}
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
0
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7943
0
    xmlXPathObjectPtr val;
7944
0
    xmlNodePtr cur;
7945
0
    xmlChar *theLang = NULL;
7946
0
    const xmlChar *lang;
7947
0
    int ret = 0;
7948
0
    int i;
7949
7950
0
    CHECK_ARITY(1);
7951
0
    CAST_TO_STRING;
7952
0
    CHECK_TYPE(XPATH_STRING);
7953
0
    val = xmlXPathValuePop(ctxt);
7954
0
    lang = val->stringval;
7955
0
    cur = ctxt->context->node;
7956
0
    while (cur != NULL) {
7957
0
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7958
0
                                &theLang) < 0)
7959
0
            xmlXPathPErrMemory(ctxt);
7960
0
        if (theLang != NULL)
7961
0
            break;
7962
0
        cur = cur->parent;
7963
0
    }
7964
0
    if ((theLang != NULL) && (lang != NULL)) {
7965
0
        for (i = 0;lang[i] != 0;i++)
7966
0
            if (toupper(lang[i]) != toupper(theLang[i]))
7967
0
                goto not_equal;
7968
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7969
0
            ret = 1;
7970
0
    }
7971
0
not_equal:
7972
0
    if (theLang != NULL)
7973
0
  xmlFree((void *)theLang);
7974
7975
0
    xmlXPathReleaseObject(ctxt->context, val);
7976
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7977
0
}
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.43M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7988
1.43M
    xmlXPathObjectPtr cur;
7989
1.43M
    double res;
7990
7991
1.43M
    if (ctxt == NULL) return;
7992
1.43M
    if (nargs == 0) {
7993
0
  if (ctxt->context->node == NULL) {
7994
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7995
0
  } else {
7996
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7997
0
            if (content == NULL)
7998
0
                xmlXPathPErrMemory(ctxt);
7999
8000
0
      res = xmlXPathStringEvalNumber(content);
8001
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8002
0
      xmlFree(content);
8003
0
  }
8004
0
  return;
8005
0
    }
8006
8007
5.73M
    CHECK_ARITY(1);
8008
5.73M
    cur = xmlXPathValuePop(ctxt);
8009
5.73M
    if (cur->type != XPATH_NUMBER) {
8010
1.43M
        double floatval;
8011
8012
1.43M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8013
1.43M
        xmlXPathReleaseObject(ctxt->context, cur);
8014
1.43M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8015
1.43M
    }
8016
5.73M
    xmlXPathValuePush(ctxt, cur);
8017
5.73M
}
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
0
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
0
    xmlXPathObjectPtr cur;
8031
0
    int i;
8032
0
    double res = 0.0;
8033
8034
0
    CHECK_ARITY(1);
8035
0
    if ((ctxt->value == NULL) ||
8036
0
  ((ctxt->value->type != XPATH_NODESET) &&
8037
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8038
0
  XP_ERROR(XPATH_INVALID_TYPE);
8039
0
    cur = xmlXPathValuePop(ctxt);
8040
8041
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8042
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8043
0
      res += xmlXPathNodeToNumberInternal(ctxt,
8044
0
                                                cur->nodesetval->nodeTab[i]);
8045
0
  }
8046
0
    }
8047
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8048
0
    xmlXPathReleaseObject(ctxt->context, cur);
8049
0
}
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
0
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8062
0
    CHECK_ARITY(1);
8063
0
    CAST_TO_NUMBER;
8064
0
    CHECK_TYPE(XPATH_NUMBER);
8065
8066
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
8067
0
}
8068
8069
/**
8070
 * Implement the ceiling() XPath function
8071
 *    number ceiling(number)
8072
 * The ceiling function returns the smallest (closest to negative infinity)
8073
 * number that is not less than the argument and that is an integer.
8074
 *
8075
 * @param ctxt  the XPath Parser context
8076
 * @param nargs  the number of arguments
8077
 */
8078
void
8079
0
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8080
0
    CHECK_ARITY(1);
8081
0
    CAST_TO_NUMBER;
8082
0
    CHECK_TYPE(XPATH_NUMBER);
8083
8084
#ifdef _AIX
8085
    /* Work around buggy ceil() function on AIX */
8086
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8087
#else
8088
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8089
0
#endif
8090
0
}
8091
8092
/**
8093
 * Implement the round() XPath function
8094
 *    number round(number)
8095
 * The round function returns the number that is closest to the
8096
 * argument and that is an integer. If there are two such numbers,
8097
 * then the one that is closest to positive infinity is returned.
8098
 *
8099
 * @param ctxt  the XPath Parser context
8100
 * @param nargs  the number of arguments
8101
 */
8102
void
8103
0
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8104
0
    double f;
8105
8106
0
    CHECK_ARITY(1);
8107
0
    CAST_TO_NUMBER;
8108
0
    CHECK_TYPE(XPATH_NUMBER);
8109
8110
0
    f = ctxt->value->floatval;
8111
8112
0
    if ((f >= -0.5) && (f < 0.5)) {
8113
        /* Handles negative zero. */
8114
0
        ctxt->value->floatval *= 0.0;
8115
0
    }
8116
0
    else {
8117
0
        double rounded = floor(f);
8118
0
        if (f - rounded >= 0.5)
8119
0
            rounded += 1.0;
8120
0
        ctxt->value->floatval = rounded;
8121
0
    }
8122
0
}
8123
8124
/************************************************************************
8125
 *                  *
8126
 *      The Parser          *
8127
 *                  *
8128
 ************************************************************************/
8129
8130
/*
8131
 * a few forward declarations since we use a recursive call based
8132
 * implementation.
8133
 */
8134
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8135
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8136
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8137
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8138
8139
/**
8140
 * Parse an XML non-colonized name.
8141
 *
8142
 * @param ctxt  the XPath Parser context
8143
 * @returns the nc name or NULL
8144
 */
8145
8146
xmlChar *
8147
107k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8148
107k
    const xmlChar *end;
8149
107k
    xmlChar *ret;
8150
8151
107k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8152
8153
107k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8154
107k
    if (end == NULL) {
8155
1
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8156
0
    }
8157
107k
    if (end == ctxt->cur)
8158
16.8k
        return(NULL);
8159
8160
90.7k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8161
90.7k
    if (ret == NULL)
8162
0
        xmlXPathPErrMemory(ctxt);
8163
90.7k
    ctxt->cur = end;
8164
90.7k
    return(ret);
8165
107k
}
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
12.9k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8179
12.9k
    xmlChar *ret = NULL;
8180
8181
12.9k
    *prefix = NULL;
8182
12.9k
    ret = xmlXPathParseNCName(ctxt);
8183
12.9k
    if (ret && CUR == ':') {
8184
354
        *prefix = ret;
8185
354
  NEXT;
8186
354
  ret = xmlXPathParseNCName(ctxt);
8187
354
    }
8188
12.9k
    return(ret);
8189
12.9k
}
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
1.34k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8200
1.34k
    const xmlChar *end;
8201
1.34k
    xmlChar *ret;
8202
8203
1.34k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8204
8205
1.34k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8206
1.34k
    if (end == NULL) {
8207
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8208
0
    }
8209
1.34k
    if (end == ctxt->cur)
8210
61
        return(NULL);
8211
8212
1.28k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8213
1.28k
    if (ret == NULL)
8214
0
        xmlXPathPErrMemory(ctxt);
8215
1.28k
    ctxt->cur = end;
8216
1.28k
    return(ret);
8217
1.34k
}
8218
8219
16.9k
#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.49M
xmlXPathStringEvalNumber(const xmlChar *str) {
8237
7.49M
    const xmlChar *cur = str;
8238
7.49M
    double ret;
8239
7.49M
    int ok = 0;
8240
7.49M
    int isneg = 0;
8241
7.49M
    int exponent = 0;
8242
7.49M
    int is_exponent_negative = 0;
8243
7.49M
#ifdef __GNUC__
8244
7.49M
    unsigned long tmp = 0;
8245
7.49M
    double temp;
8246
7.49M
#endif
8247
7.49M
    if (cur == NULL) return(0);
8248
7.49M
    while (IS_BLANK_CH(*cur)) cur++;
8249
7.49M
    if (*cur == '-') {
8250
7.06k
  isneg = 1;
8251
7.06k
  cur++;
8252
7.06k
    }
8253
7.49M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8254
7.19M
        return(xmlXPathNAN);
8255
7.19M
    }
8256
8257
303k
#ifdef __GNUC__
8258
    /*
8259
     * tmp/temp is a workaround against a gcc compiler bug
8260
     * http://veillard.com/gcc.bug
8261
     */
8262
303k
    ret = 0;
8263
665k
    while ((*cur >= '0') && (*cur <= '9')) {
8264
361k
  ret = ret * 10;
8265
361k
  tmp = (*cur - '0');
8266
361k
  ok = 1;
8267
361k
  cur++;
8268
361k
  temp = (double) tmp;
8269
361k
  ret = ret + temp;
8270
361k
    }
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
303k
    if (*cur == '.') {
8281
24.4k
  int v, frac = 0, max;
8282
24.4k
  double fraction = 0;
8283
8284
24.4k
        cur++;
8285
24.4k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8286
8.38k
      return(xmlXPathNAN);
8287
8.38k
  }
8288
19.8k
        while (*cur == '0') {
8289
3.85k
      frac = frac + 1;
8290
3.85k
      cur++;
8291
3.85k
        }
8292
16.0k
        max = frac + MAX_FRAC;
8293
54.0k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8294
38.0k
      v = (*cur - '0');
8295
38.0k
      fraction = fraction * 10 + v;
8296
38.0k
      frac = frac + 1;
8297
38.0k
      cur++;
8298
38.0k
  }
8299
16.0k
  fraction /= pow(10.0, frac);
8300
16.0k
  ret = ret + fraction;
8301
24.3k
  while ((*cur >= '0') && (*cur <= '9'))
8302
8.35k
      cur++;
8303
16.0k
    }
8304
294k
    if ((*cur == 'e') || (*cur == 'E')) {
8305
11.8k
      cur++;
8306
11.8k
      if (*cur == '-') {
8307
75
  is_exponent_negative = 1;
8308
75
  cur++;
8309
11.7k
      } else if (*cur == '+') {
8310
18
        cur++;
8311
18
      }
8312
13.0k
      while ((*cur >= '0') && (*cur <= '9')) {
8313
1.25k
        if (exponent < 1000000)
8314
838
    exponent = exponent * 10 + (*cur - '0');
8315
1.25k
  cur++;
8316
1.25k
      }
8317
11.8k
    }
8318
3.76M
    while (IS_BLANK_CH(*cur)) cur++;
8319
294k
    if (*cur != 0) return(xmlXPathNAN);
8320
235k
    if (isneg) ret = -ret;
8321
235k
    if (is_exponent_negative) exponent = -exponent;
8322
235k
    ret *= pow(10.0, (double)exponent);
8323
235k
    return(ret);
8324
294k
}
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
13.6k
{
8338
13.6k
    double ret = 0.0;
8339
13.6k
    int ok = 0;
8340
13.6k
    int exponent = 0;
8341
13.6k
    int is_exponent_negative = 0;
8342
13.6k
    xmlXPathObjectPtr num;
8343
13.6k
#ifdef __GNUC__
8344
13.6k
    unsigned long tmp = 0;
8345
13.6k
    double temp;
8346
13.6k
#endif
8347
8348
13.6k
    CHECK_ERROR;
8349
13.5k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8350
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8351
0
    }
8352
13.5k
#ifdef __GNUC__
8353
    /*
8354
     * tmp/temp is a workaround against a gcc compiler bug
8355
     * http://veillard.com/gcc.bug
8356
     */
8357
13.5k
    ret = 0;
8358
1.01M
    while ((CUR >= '0') && (CUR <= '9')) {
8359
1.00M
  ret = ret * 10;
8360
1.00M
  tmp = (CUR - '0');
8361
1.00M
        ok = 1;
8362
1.00M
        NEXT;
8363
1.00M
  temp = (double) tmp;
8364
1.00M
  ret = ret + temp;
8365
1.00M
    }
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
13.5k
    if (CUR == '.') {
8375
890
  int v, frac = 0, max;
8376
890
  double fraction = 0;
8377
8378
890
        NEXT;
8379
890
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8380
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8381
0
        }
8382
498k
        while (CUR == '0') {
8383
498k
            frac = frac + 1;
8384
498k
            NEXT;
8385
498k
        }
8386
890
        max = frac + MAX_FRAC;
8387
3.88k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8388
2.99k
      v = (CUR - '0');
8389
2.99k
      fraction = fraction * 10 + v;
8390
2.99k
      frac = frac + 1;
8391
2.99k
            NEXT;
8392
2.99k
        }
8393
890
        fraction /= pow(10.0, frac);
8394
890
        ret = ret + fraction;
8395
58.6k
        while ((CUR >= '0') && (CUR <= '9'))
8396
57.7k
            NEXT;
8397
890
    }
8398
13.5k
    if ((CUR == 'e') || (CUR == 'E')) {
8399
293
        NEXT;
8400
293
        if (CUR == '-') {
8401
1
            is_exponent_negative = 1;
8402
1
            NEXT;
8403
292
        } else if (CUR == '+') {
8404
67
      NEXT;
8405
67
  }
8406
4.00k
        while ((CUR >= '0') && (CUR <= '9')) {
8407
3.70k
            if (exponent < 1000000)
8408
1.37k
                exponent = exponent * 10 + (CUR - '0');
8409
3.70k
            NEXT;
8410
3.70k
        }
8411
293
        if (is_exponent_negative)
8412
1
            exponent = -exponent;
8413
293
        ret *= pow(10.0, (double) exponent);
8414
293
    }
8415
13.5k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8416
13.5k
    if (num == NULL) {
8417
0
  ctxt->error = XPATH_MEMORY_ERROR;
8418
13.5k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8419
13.5k
                              NULL) == -1) {
8420
0
        xmlXPathReleaseObject(ctxt->context, num);
8421
0
    }
8422
13.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
9.72k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8435
9.72k
    const xmlChar *q;
8436
9.72k
    xmlChar *ret = NULL;
8437
9.72k
    int quote;
8438
8439
9.72k
    if (CUR == '"') {
8440
7.39k
        quote = '"';
8441
7.39k
    } else if (CUR == '\'') {
8442
2.32k
        quote = '\'';
8443
2.32k
    } else {
8444
1
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8445
0
    }
8446
8447
9.71k
    NEXT;
8448
9.71k
    q = CUR_PTR;
8449
2.82M
    while (CUR != quote) {
8450
2.82M
        int ch;
8451
2.82M
        int len = 4;
8452
8453
2.82M
        if (CUR == 0)
8454
2.81M
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8455
2.81M
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8456
2.81M
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8457
2.81M
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8458
2.81M
        CUR_PTR += len;
8459
2.81M
    }
8460
9.56k
    ret = xmlStrndup(q, CUR_PTR - q);
8461
9.56k
    if (ret == NULL)
8462
0
        xmlXPathPErrMemory(ctxt);
8463
9.56k
    NEXT;
8464
9.56k
    return(ret);
8465
9.71k
}
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
9.71k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8479
9.71k
    xmlChar *ret = NULL;
8480
9.71k
    xmlXPathObjectPtr lit;
8481
8482
9.71k
    ret = xmlXPathParseLiteral(ctxt);
8483
9.71k
    if (ret == NULL)
8484
155
        return;
8485
9.56k
    lit = xmlXPathCacheNewString(ctxt, ret);
8486
9.56k
    if (lit == NULL) {
8487
0
        ctxt->error = XPATH_MEMORY_ERROR;
8488
9.56k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8489
9.56k
                              NULL) == -1) {
8490
0
        xmlXPathReleaseObject(ctxt->context, lit);
8491
0
    }
8492
9.56k
    xmlFree(ret);
8493
9.56k
}
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
323
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8512
323
    xmlChar *name;
8513
323
    xmlChar *prefix;
8514
8515
323
    SKIP_BLANKS;
8516
323
    if (CUR != '$') {
8517
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8518
0
    }
8519
323
    NEXT;
8520
323
    name = xmlXPathParseQName(ctxt, &prefix);
8521
323
    if (name == NULL) {
8522
176
        xmlFree(prefix);
8523
176
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8524
0
    }
8525
147
    ctxt->comp->last = -1;
8526
147
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8527
0
        xmlFree(prefix);
8528
0
        xmlFree(name);
8529
0
    }
8530
147
    SKIP_BLANKS;
8531
147
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8532
12
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8533
0
    }
8534
147
}
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
14.4k
xmlXPathIsNodeType(const xmlChar *name) {
8549
14.4k
    if (name == NULL)
8550
0
  return(0);
8551
8552
14.4k
    if (xmlStrEqual(name, BAD_CAST "node"))
8553
470
  return(1);
8554
13.9k
    if (xmlStrEqual(name, BAD_CAST "text"))
8555
11
  return(1);
8556
13.9k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8557
199
  return(1);
8558
13.7k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8559
2
  return(1);
8560
13.7k
    return(0);
8561
13.7k
}
8562
8563
/**
8564
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8565
 *  [17]   Argument ::=   Expr
8566
 *
8567
 * Compile a function call, the evaluation of all arguments are
8568
 * pushed on the stack
8569
 *
8570
 * @param ctxt  the XPath Parser context
8571
 */
8572
static void
8573
12.6k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8574
12.6k
    xmlChar *name;
8575
12.6k
    xmlChar *prefix;
8576
12.6k
    int nbargs = 0;
8577
12.6k
    int sort = 1;
8578
8579
12.6k
    name = xmlXPathParseQName(ctxt, &prefix);
8580
12.6k
    if (name == NULL) {
8581
223
  xmlFree(prefix);
8582
223
  XP_ERROR(XPATH_EXPR_ERROR);
8583
0
    }
8584
12.3k
    SKIP_BLANKS;
8585
8586
12.3k
    if (CUR != '(') {
8587
20
  xmlFree(name);
8588
20
  xmlFree(prefix);
8589
20
  XP_ERROR(XPATH_EXPR_ERROR);
8590
0
    }
8591
12.3k
    NEXT;
8592
12.3k
    SKIP_BLANKS;
8593
8594
    /*
8595
    * Optimization for count(): we don't need the node-set to be sorted.
8596
    */
8597
12.3k
    if ((prefix == NULL) && (name[0] == 'c') &&
8598
2.22k
  xmlStrEqual(name, BAD_CAST "count"))
8599
1.52k
    {
8600
1.52k
  sort = 0;
8601
1.52k
    }
8602
12.3k
    ctxt->comp->last = -1;
8603
12.3k
    if (CUR != ')') {
8604
13.1k
  while (CUR != 0) {
8605
12.8k
      int op1 = ctxt->comp->last;
8606
12.8k
      ctxt->comp->last = -1;
8607
12.8k
      xmlXPathCompileExpr(ctxt, sort);
8608
12.8k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8609
1.29k
    xmlFree(name);
8610
1.29k
    xmlFree(prefix);
8611
1.29k
    return;
8612
1.29k
      }
8613
11.5k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8614
11.5k
      nbargs++;
8615
11.5k
      if (CUR == ')') break;
8616
4.97k
      if (CUR != ',') {
8617
1.49k
    xmlFree(name);
8618
1.49k
    xmlFree(prefix);
8619
1.49k
    XP_ERROR(XPATH_EXPR_ERROR);
8620
0
      }
8621
3.48k
      NEXT;
8622
3.48k
      SKIP_BLANKS;
8623
3.48k
  }
8624
9.68k
    }
8625
9.58k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8626
0
        xmlFree(prefix);
8627
0
        xmlFree(name);
8628
0
    }
8629
9.58k
    NEXT;
8630
9.58k
    SKIP_BLANKS;
8631
9.58k
}
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
43.2k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8646
43.2k
    SKIP_BLANKS;
8647
43.2k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8648
42.9k
    else if (CUR == '(') {
8649
6.97k
  NEXT;
8650
6.97k
  SKIP_BLANKS;
8651
6.97k
  xmlXPathCompileExpr(ctxt, 1);
8652
6.97k
  CHECK_ERROR;
8653
5.83k
  if (CUR != ')') {
8654
137
      XP_ERROR(XPATH_EXPR_ERROR);
8655
0
  }
8656
5.69k
  NEXT;
8657
5.69k
  SKIP_BLANKS;
8658
35.9k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8659
13.6k
  xmlXPathCompNumber(ctxt);
8660
22.3k
    } else if ((CUR == '\'') || (CUR == '"')) {
8661
9.71k
  xmlXPathCompLiteral(ctxt);
8662
12.6k
    } else {
8663
12.6k
  xmlXPathCompFunctionCall(ctxt);
8664
12.6k
    }
8665
41.9k
    SKIP_BLANKS;
8666
41.9k
}
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
43.2k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8684
43.2k
    xmlXPathCompPrimaryExpr(ctxt);
8685
43.2k
    CHECK_ERROR;
8686
38.5k
    SKIP_BLANKS;
8687
8688
43.3k
    while (CUR == '[') {
8689
4.85k
  xmlXPathCompPredicate(ctxt, 1);
8690
4.85k
  SKIP_BLANKS;
8691
4.85k
    }
8692
8693
8694
38.5k
}
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
68.4k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8706
68.4k
    const xmlChar *end;
8707
68.4k
    xmlChar *ret;
8708
8709
68.4k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8710
68.4k
    if (end == NULL) {
8711
1
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8712
0
    }
8713
68.4k
    if (end == ctxt->cur)
8714
5.07k
        return(NULL);
8715
8716
63.3k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8717
63.3k
    if (ret == NULL)
8718
0
        xmlXPathPErrMemory(ctxt);
8719
63.3k
    return(ret);
8720
68.4k
}
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
5.48M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8735
5.48M
    int lc = 1;           /* Should we branch to LocationPath ?         */
8736
5.48M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8737
8738
5.48M
    SKIP_BLANKS;
8739
5.48M
    if ((CUR == '$') || (CUR == '(') ||
8740
5.48M
  (IS_ASCII_DIGIT(CUR)) ||
8741
5.46M
        (CUR == '\'') || (CUR == '"') ||
8742
5.45M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8743
30.6k
  lc = 0;
8744
5.45M
    } else if (CUR == '*') {
8745
  /* relative or absolute location path */
8746
5.36M
  lc = 1;
8747
5.36M
    } else if (CUR == '/') {
8748
  /* relative or absolute location path */
8749
23.1k
  lc = 1;
8750
73.7k
    } else if (CUR == '@') {
8751
  /* relative abbreviated attribute location path */
8752
1.66k
  lc = 1;
8753
72.0k
    } else if (CUR == '.') {
8754
  /* relative abbreviated attribute location path */
8755
3.61k
  lc = 1;
8756
68.4k
    } 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
68.4k
  SKIP_BLANKS;
8769
68.4k
  name = xmlXPathScanName(ctxt);
8770
68.4k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8771
2.42k
      lc = 1;
8772
2.42k
      xmlFree(name);
8773
66.0k
  } else if (name != NULL) {
8774
60.9k
      int len =xmlStrlen(name);
8775
8776
8777
1.93M
      while (NXT(len) != 0) {
8778
1.92M
    if (NXT(len) == '/') {
8779
        /* element name */
8780
6.67k
        lc = 1;
8781
6.67k
        break;
8782
1.91M
    } else if (IS_BLANK_CH(NXT(len))) {
8783
        /* ignore blanks */
8784
1.87M
        ;
8785
1.87M
    } else if (NXT(len) == ':') {
8786
120
        lc = 1;
8787
120
        break;
8788
46.0k
    } else if ((NXT(len) == '(')) {
8789
        /* Node Type or Function */
8790
12.9k
        if (xmlXPathIsNodeType(name)) {
8791
367
      lc = 1;
8792
12.6k
        } else {
8793
12.6k
      lc = 0;
8794
12.6k
        }
8795
12.9k
                    break;
8796
33.1k
    } else if ((NXT(len) == '[')) {
8797
        /* element name */
8798
494
        lc = 1;
8799
494
        break;
8800
32.6k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8801
28.5k
         (NXT(len) == '=')) {
8802
11.8k
        lc = 1;
8803
11.8k
        break;
8804
20.8k
    } else {
8805
20.8k
        lc = 1;
8806
20.8k
        break;
8807
20.8k
    }
8808
1.87M
    len++;
8809
1.87M
      }
8810
60.9k
      if (NXT(len) == 0) {
8811
    /* element name */
8812
8.06k
    lc = 1;
8813
8.06k
      }
8814
60.9k
      xmlFree(name);
8815
60.9k
  } else {
8816
      /* make sure all cases are covered explicitly */
8817
5.08k
      XP_ERROR(XPATH_EXPR_ERROR);
8818
0
  }
8819
68.4k
    }
8820
8821
5.48M
    if (lc) {
8822
5.43M
  if (CUR == '/') {
8823
23.1k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8824
5.41M
  } else {
8825
5.41M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8826
5.41M
  }
8827
5.43M
  xmlXPathCompLocationPath(ctxt);
8828
5.43M
    } else {
8829
43.2k
  xmlXPathCompFilterExpr(ctxt);
8830
43.2k
  CHECK_ERROR;
8831
37.4k
  if ((CUR == '/') && (NXT(1) == '/')) {
8832
1.33k
      SKIP(2);
8833
1.33k
      SKIP_BLANKS;
8834
8835
1.33k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8836
1.33k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8837
8838
1.33k
      xmlXPathCompRelativeLocationPath(ctxt);
8839
36.1k
  } else if (CUR == '/') {
8840
1.66k
      xmlXPathCompRelativeLocationPath(ctxt);
8841
1.66k
  }
8842
37.4k
    }
8843
5.47M
    SKIP_BLANKS;
8844
5.47M
}
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
5.46M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8857
5.46M
    xmlXPathCompPathExpr(ctxt);
8858
5.46M
    CHECK_ERROR;
8859
5.45M
    SKIP_BLANKS;
8860
5.47M
    while (CUR == '|') {
8861
19.9k
  int op1 = ctxt->comp->last;
8862
19.9k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8863
8864
19.9k
  NEXT;
8865
19.9k
  SKIP_BLANKS;
8866
19.9k
  xmlXPathCompPathExpr(ctxt);
8867
8868
19.9k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8869
8870
19.9k
  SKIP_BLANKS;
8871
19.9k
    }
8872
5.45M
}
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
5.46M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8885
5.46M
    int minus = 0;
8886
5.46M
    int found = 0;
8887
8888
5.46M
    SKIP_BLANKS;
8889
5.55M
    while (CUR == '-') {
8890
90.2k
        minus = 1 - minus;
8891
90.2k
  found = 1;
8892
90.2k
  NEXT;
8893
90.2k
  SKIP_BLANKS;
8894
90.2k
    }
8895
8896
5.46M
    xmlXPathCompUnionExpr(ctxt);
8897
5.46M
    CHECK_ERROR;
8898
5.45M
    if (found) {
8899
18.4k
  if (minus)
8900
13.7k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8901
4.78k
  else
8902
4.78k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8903
18.4k
    }
8904
5.45M
}
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
105k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8920
105k
    xmlXPathCompUnaryExpr(ctxt);
8921
105k
    CHECK_ERROR;
8922
94.0k
    SKIP_BLANKS;
8923
5.45M
    while ((CUR == '*') ||
8924
93.6k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8925
5.36M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8926
5.36M
  int op = -1;
8927
5.36M
  int op1 = ctxt->comp->last;
8928
8929
5.36M
        if (CUR == '*') {
8930
5.36M
      op = 0;
8931
5.36M
      NEXT;
8932
5.36M
  } else if (CUR == 'd') {
8933
0
      op = 1;
8934
0
      SKIP(3);
8935
902
  } else if (CUR == 'm') {
8936
902
      op = 2;
8937
902
      SKIP(3);
8938
902
  }
8939
5.36M
  SKIP_BLANKS;
8940
5.36M
        xmlXPathCompUnaryExpr(ctxt);
8941
5.36M
  CHECK_ERROR;
8942
5.36M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8943
5.36M
  SKIP_BLANKS;
8944
5.36M
    }
8945
94.0k
}
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
82.2k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8959
8960
82.2k
    xmlXPathCompMultiplicativeExpr(ctxt);
8961
82.2k
    CHECK_ERROR;
8962
69.8k
    SKIP_BLANKS;
8963
92.7k
    while ((CUR == '+') || (CUR == '-')) {
8964
23.6k
  int plus;
8965
23.6k
  int op1 = ctxt->comp->last;
8966
8967
23.6k
        if (CUR == '+') plus = 1;
8968
15.6k
  else plus = 0;
8969
23.6k
  NEXT;
8970
23.6k
  SKIP_BLANKS;
8971
23.6k
        xmlXPathCompMultiplicativeExpr(ctxt);
8972
23.6k
  CHECK_ERROR;
8973
22.8k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8974
22.8k
  SKIP_BLANKS;
8975
22.8k
    }
8976
69.8k
}
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
74.5k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8997
74.5k
    xmlXPathCompAdditiveExpr(ctxt);
8998
74.5k
    CHECK_ERROR;
8999
62.1k
    SKIP_BLANKS;
9000
69.1k
    while ((CUR == '<') || (CUR == '>')) {
9001
7.75k
  int inf, strict;
9002
7.75k
  int op1 = ctxt->comp->last;
9003
9004
7.75k
        if (CUR == '<') inf = 1;
9005
5.73k
  else inf = 0;
9006
7.75k
  if (NXT(1) == '=') strict = 0;
9007
7.66k
  else strict = 1;
9008
7.75k
  NEXT;
9009
7.75k
  if (!strict) NEXT;
9010
7.75k
  SKIP_BLANKS;
9011
7.75k
        xmlXPathCompAdditiveExpr(ctxt);
9012
7.75k
  CHECK_ERROR;
9013
6.96k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9014
6.96k
  SKIP_BLANKS;
9015
6.96k
    }
9016
62.1k
}
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
61.9k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9034
61.9k
    xmlXPathCompRelationalExpr(ctxt);
9035
61.9k
    CHECK_ERROR;
9036
49.9k
    SKIP_BLANKS;
9037
61.3k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9038
12.5k
  int eq;
9039
12.5k
  int op1 = ctxt->comp->last;
9040
9041
12.5k
        if (CUR == '=') eq = 1;
9042
273
  else eq = 0;
9043
12.5k
  NEXT;
9044
12.5k
  if (!eq) NEXT;
9045
12.5k
  SKIP_BLANKS;
9046
12.5k
        xmlXPathCompRelationalExpr(ctxt);
9047
12.5k
  CHECK_ERROR;
9048
11.4k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9049
11.4k
  SKIP_BLANKS;
9050
11.4k
    }
9051
49.9k
}
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
60.7k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9063
60.7k
    xmlXPathCompEqualityExpr(ctxt);
9064
60.7k
    CHECK_ERROR;
9065
47.6k
    SKIP_BLANKS;
9066
48.7k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9067
1.16k
  int op1 = ctxt->comp->last;
9068
1.16k
        SKIP(3);
9069
1.16k
  SKIP_BLANKS;
9070
1.16k
        xmlXPathCompEqualityExpr(ctxt);
9071
1.16k
  CHECK_ERROR;
9072
1.14k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9073
1.14k
  SKIP_BLANKS;
9074
1.14k
    }
9075
47.6k
}
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
43.3k
    SKIP_BLANKS;
9104
47.6k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9105
4.78k
  int op1 = ctxt->comp->last;
9106
4.78k
        SKIP(2);
9107
4.78k
  SKIP_BLANKS;
9108
4.78k
        xmlXPathCompAndExpr(ctxt);
9109
4.78k
  CHECK_ERROR;
9110
4.22k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9111
4.22k
  SKIP_BLANKS;
9112
4.22k
    }
9113
42.8k
    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
34.2k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9121
34.2k
    }
9122
9123
42.8k
    if (xpctxt != NULL)
9124
42.8k
        xpctxt->depth -= 10;
9125
42.8k
}
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
7.92k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9138
7.92k
    int op1 = ctxt->comp->last;
9139
9140
7.92k
    SKIP_BLANKS;
9141
7.92k
    if (CUR != '[') {
9142
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9143
0
    }
9144
7.92k
    NEXT;
9145
7.92k
    SKIP_BLANKS;
9146
9147
7.92k
    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
7.92k
    if (! filter)
9158
3.06k
  xmlXPathCompileExpr(ctxt, 0);
9159
4.85k
    else
9160
4.85k
  xmlXPathCompileExpr(ctxt, 1);
9161
7.92k
    CHECK_ERROR;
9162
9163
5.44k
    if (CUR != ']') {
9164
168
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9165
0
    }
9166
9167
5.28k
    if (filter)
9168
3.15k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9169
2.12k
    else
9170
2.12k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9171
9172
5.28k
    NEXT;
9173
5.28k
    SKIP_BLANKS;
9174
5.28k
}
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
5.44M
         xmlChar *name) {
9202
5.44M
    int blanks;
9203
9204
5.44M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9205
0
  return(NULL);
9206
0
    }
9207
5.44M
    *type = (xmlXPathTypeVal) 0;
9208
5.44M
    *test = (xmlXPathTestVal) 0;
9209
5.44M
    *prefix = NULL;
9210
5.44M
    SKIP_BLANKS;
9211
9212
5.44M
    if ((name == NULL) && (CUR == '*')) {
9213
  /*
9214
   * All elements
9215
   */
9216
5.37M
  NEXT;
9217
5.37M
  *test = NODE_TEST_ALL;
9218
5.37M
  return(NULL);
9219
5.37M
    }
9220
9221
66.4k
    if (name == NULL)
9222
9.92k
  name = xmlXPathParseNCName(ctxt);
9223
66.4k
    if (name == NULL) {
9224
2.59k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9225
0
    }
9226
9227
63.8k
    blanks = IS_BLANK_CH(CUR);
9228
63.8k
    SKIP_BLANKS;
9229
63.8k
    if (CUR == '(') {
9230
1.98k
  NEXT;
9231
  /*
9232
   * NodeType or PI search
9233
   */
9234
1.98k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9235
12
      *type = NODE_TYPE_COMMENT;
9236
1.97k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9237
1.84k
      *type = NODE_TYPE_NODE;
9238
136
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9239
2
      *type = NODE_TYPE_PI;
9240
134
  else if (xmlStrEqual(name, BAD_CAST "text"))
9241
11
      *type = NODE_TYPE_TEXT;
9242
123
  else {
9243
123
      if (name != NULL)
9244
123
    xmlFree(name);
9245
123
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9246
0
  }
9247
9248
1.86k
  *test = NODE_TEST_TYPE;
9249
9250
1.86k
  SKIP_BLANKS;
9251
1.86k
  if (*type == NODE_TYPE_PI) {
9252
      /*
9253
       * Specific case: search a PI by name.
9254
       */
9255
2
      if (name != NULL)
9256
2
    xmlFree(name);
9257
2
      name = NULL;
9258
2
      if (CUR != ')') {
9259
1
    name = xmlXPathParseLiteral(ctxt);
9260
1
    *test = NODE_TEST_PI;
9261
1
    SKIP_BLANKS;
9262
1
      }
9263
2
  }
9264
1.86k
  if (CUR != ')') {
9265
82
      if (name != NULL)
9266
81
    xmlFree(name);
9267
82
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9268
0
  }
9269
1.78k
  NEXT;
9270
1.78k
  return(name);
9271
1.86k
    }
9272
61.8k
    *test = NODE_TEST_NAME;
9273
61.8k
    if ((!blanks) && (CUR == ':')) {
9274
6.13k
  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
6.13k
  *prefix = name;
9284
9285
6.13k
  if (CUR == '*') {
9286
      /*
9287
       * All elements
9288
       */
9289
300
      NEXT;
9290
300
      *test = NODE_TEST_ALL;
9291
300
      return(NULL);
9292
300
  }
9293
9294
5.83k
  name = xmlXPathParseNCName(ctxt);
9295
5.83k
  if (name == NULL) {
9296
108
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9297
0
  }
9298
5.83k
    }
9299
61.4k
    return(name);
9300
61.8k
}
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
64.8k
xmlXPathIsAxisName(const xmlChar *name) {
9322
64.8k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9323
64.8k
    switch (name[0]) {
9324
5.42k
  case 'a':
9325
5.42k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9326
1.70k
    ret = AXIS_ANCESTOR;
9327
5.42k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9328
1.71k
    ret = AXIS_ANCESTOR_OR_SELF;
9329
5.42k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9330
94
    ret = AXIS_ATTRIBUTE;
9331
5.42k
      break;
9332
386
  case 'c':
9333
386
      if (xmlStrEqual(name, BAD_CAST "child"))
9334
11
    ret = AXIS_CHILD;
9335
386
      break;
9336
2.82k
  case 'd':
9337
2.82k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9338
1.49k
    ret = AXIS_DESCENDANT;
9339
2.82k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9340
1
    ret = AXIS_DESCENDANT_OR_SELF;
9341
2.82k
      break;
9342
3.03k
  case 'f':
9343
3.03k
      if (xmlStrEqual(name, BAD_CAST "following"))
9344
22
    ret = AXIS_FOLLOWING;
9345
3.03k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9346
66
    ret = AXIS_FOLLOWING_SIBLING;
9347
3.03k
      break;
9348
12.5k
  case 'n':
9349
12.5k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9350
4.15k
    ret = AXIS_NAMESPACE;
9351
12.5k
      break;
9352
445
  case 'p':
9353
445
      if (xmlStrEqual(name, BAD_CAST "parent"))
9354
1
    ret = AXIS_PARENT;
9355
445
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9356
1
    ret = AXIS_PRECEDING;
9357
445
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9358
1
    ret = AXIS_PRECEDING_SIBLING;
9359
445
      break;
9360
1.16k
  case 's':
9361
1.16k
      if (xmlStrEqual(name, BAD_CAST "self"))
9362
742
    ret = AXIS_SELF;
9363
1.16k
      break;
9364
64.8k
    }
9365
64.8k
    return(ret);
9366
64.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
5.45M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9391
5.45M
    SKIP_BLANKS;
9392
5.45M
    if ((CUR == '.') && (NXT(1) == '.')) {
9393
251
  SKIP(2);
9394
251
  SKIP_BLANKS;
9395
251
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9396
251
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9397
5.45M
    } else if (CUR == '.') {
9398
8.00k
  NEXT;
9399
8.00k
  SKIP_BLANKS;
9400
5.44M
    } else {
9401
5.44M
  xmlChar *name = NULL;
9402
5.44M
  xmlChar *prefix = NULL;
9403
5.44M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9404
5.44M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9405
5.44M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9406
5.44M
  int op1;
9407
9408
5.44M
  if (CUR == '*') {
9409
5.36M
      axis = AXIS_CHILD;
9410
5.36M
  } else {
9411
78.5k
      if (name == NULL)
9412
78.5k
    name = xmlXPathParseNCName(ctxt);
9413
78.5k
      if (name != NULL) {
9414
64.8k
    axis = xmlXPathIsAxisName(name);
9415
64.8k
    if (axis != 0) {
9416
10.0k
        SKIP_BLANKS;
9417
10.0k
        if ((CUR == ':') && (NXT(1) == ':')) {
9418
8.05k
      SKIP(2);
9419
8.05k
      xmlFree(name);
9420
8.05k
      name = NULL;
9421
8.05k
        } else {
9422
      /* an element name can conflict with an axis one :-\ */
9423
1.94k
      axis = AXIS_CHILD;
9424
1.94k
        }
9425
54.8k
    } else {
9426
54.8k
        axis = AXIS_CHILD;
9427
54.8k
    }
9428
64.8k
      } else if (CUR == '@') {
9429
10.5k
    NEXT;
9430
10.5k
    axis = AXIS_ATTRIBUTE;
9431
10.5k
      } else {
9432
3.11k
    axis = AXIS_CHILD;
9433
3.11k
      }
9434
78.5k
  }
9435
9436
5.44M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9437
807
            xmlFree(name);
9438
807
            return;
9439
807
        }
9440
9441
5.44M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9442
5.44M
  if (test == 0)
9443
2.72k
      return;
9444
9445
5.44M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9446
6.13k
      (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
5.44M
  op1 = ctxt->comp->last;
9454
5.44M
  ctxt->comp->last = -1;
9455
9456
5.44M
  SKIP_BLANKS;
9457
5.44M
  while (CUR == '[') {
9458
3.06k
      xmlXPathCompPredicate(ctxt, 0);
9459
3.06k
  }
9460
9461
5.44M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9462
5.44M
                           test, type, (void *)prefix, (void *)name) == -1) {
9463
11
            xmlFree(prefix);
9464
11
            xmlFree(name);
9465
11
        }
9466
5.44M
    }
9467
5.45M
}
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
5.44M
(xmlXPathParserContextPtr ctxt) {
9482
5.44M
    SKIP_BLANKS;
9483
5.44M
    if ((CUR == '/') && (NXT(1) == '/')) {
9484
721
  SKIP(2);
9485
721
  SKIP_BLANKS;
9486
721
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9487
721
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9488
5.43M
    } else if (CUR == '/') {
9489
1.81k
      NEXT;
9490
1.81k
  SKIP_BLANKS;
9491
1.81k
    }
9492
5.44M
    xmlXPathCompStep(ctxt);
9493
5.44M
    CHECK_ERROR;
9494
5.43M
    SKIP_BLANKS;
9495
5.45M
    while (CUR == '/') {
9496
12.0k
  if ((CUR == '/') && (NXT(1) == '/')) {
9497
6.09k
      SKIP(2);
9498
6.09k
      SKIP_BLANKS;
9499
6.09k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9500
6.09k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9501
6.09k
      xmlXPathCompStep(ctxt);
9502
6.09k
  } else if (CUR == '/') {
9503
6.00k
      NEXT;
9504
6.00k
      SKIP_BLANKS;
9505
6.00k
      xmlXPathCompStep(ctxt);
9506
6.00k
  }
9507
12.0k
  SKIP_BLANKS;
9508
12.0k
    }
9509
5.43M
}
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
5.43M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9525
5.43M
    SKIP_BLANKS;
9526
5.43M
    if (CUR != '/') {
9527
5.41M
        xmlXPathCompRelativeLocationPath(ctxt);
9528
5.41M
    } else {
9529
45.8k
  while (CUR == '/') {
9530
23.3k
      if ((CUR == '/') && (NXT(1) == '/')) {
9531
18.3k
    SKIP(2);
9532
18.3k
    SKIP_BLANKS;
9533
18.3k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9534
18.3k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9535
18.3k
    xmlXPathCompRelativeLocationPath(ctxt);
9536
18.3k
      } else if (CUR == '/') {
9537
5.01k
    NEXT;
9538
5.01k
    SKIP_BLANKS;
9539
5.01k
    if ((CUR != 0) &&
9540
4.84k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9541
3.15k
                     (CUR == '_') || (CUR == '.') ||
9542
3.06k
         (CUR == '@') || (CUR == '*')))
9543
2.88k
        xmlXPathCompRelativeLocationPath(ctxt);
9544
5.01k
      }
9545
23.3k
      CHECK_ERROR;
9546
23.3k
  }
9547
23.1k
    }
9548
5.43M
}
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
86.3k
{
9578
86.3k
    xmlXPathContextPtr xpctxt;
9579
86.3k
    xmlNodePtr oldnode;
9580
86.3k
    xmlDocPtr olddoc;
9581
86.3k
    xmlXPathStepOpPtr filterOp;
9582
86.3k
    int oldcs, oldpp;
9583
86.3k
    int i, j, pos;
9584
9585
86.3k
    if ((set == NULL) || (set->nodeNr == 0))
9586
1.11k
        return;
9587
9588
    /*
9589
    * Check if the node set contains a sufficient number of nodes for
9590
    * the requested range.
9591
    */
9592
85.2k
    if (set->nodeNr < minPos) {
9593
2.34k
        xmlXPathNodeSetClear(set, hasNsNodes);
9594
2.34k
        return;
9595
2.34k
    }
9596
9597
82.8k
    xpctxt = ctxt->context;
9598
82.8k
    oldnode = xpctxt->node;
9599
82.8k
    olddoc = xpctxt->doc;
9600
82.8k
    oldcs = xpctxt->contextSize;
9601
82.8k
    oldpp = xpctxt->proximityPosition;
9602
82.8k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9603
9604
82.8k
    xpctxt->contextSize = set->nodeNr;
9605
9606
1.45M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9607
1.38M
        xmlNodePtr node = set->nodeTab[i];
9608
1.38M
        int res;
9609
9610
1.38M
        xpctxt->node = node;
9611
1.38M
        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.38M
        if ((node->type != XML_NAMESPACE_DECL) &&
9620
718k
            (node->doc != NULL))
9621
718k
            xpctxt->doc = node->doc;
9622
9623
1.38M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9624
9625
1.38M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9626
822
            break;
9627
1.38M
        if (res < 0) {
9628
            /* Shouldn't happen */
9629
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9630
0
            break;
9631
0
        }
9632
9633
1.38M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9634
564k
            if (i != j) {
9635
418k
                set->nodeTab[j] = node;
9636
418k
                set->nodeTab[i] = NULL;
9637
418k
            }
9638
9639
564k
            j += 1;
9640
820k
        } else {
9641
            /* Remove the entry from the initial node set. */
9642
820k
            set->nodeTab[i] = NULL;
9643
820k
            if (node->type == XML_NAMESPACE_DECL)
9644
368k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9645
820k
        }
9646
9647
1.38M
        if (res != 0) {
9648
565k
            if (pos == maxPos) {
9649
13.4k
                i += 1;
9650
13.4k
                break;
9651
13.4k
            }
9652
9653
552k
            pos += 1;
9654
552k
        }
9655
1.38M
    }
9656
9657
    /* Free remaining nodes. */
9658
82.8k
    if (hasNsNodes) {
9659
194k
        for (; i < set->nodeNr; i++) {
9660
191k
            xmlNodePtr node = set->nodeTab[i];
9661
191k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9662
107k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9663
191k
        }
9664
3.10k
    }
9665
9666
82.8k
    set->nodeNr = j;
9667
9668
    /* If too many elements were removed, shrink table to preserve memory. */
9669
82.8k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9670
8.34k
        (set->nodeNr < set->nodeMax / 2)) {
9671
7.14k
        xmlNodePtr *tmp;
9672
7.14k
        int nodeMax = set->nodeNr;
9673
9674
7.14k
        if (nodeMax < XML_NODESET_DEFAULT)
9675
6.95k
            nodeMax = XML_NODESET_DEFAULT;
9676
7.14k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9677
7.14k
                nodeMax * sizeof(xmlNodePtr));
9678
7.14k
        if (tmp == NULL) {
9679
0
            xmlXPathPErrMemory(ctxt);
9680
7.14k
        } else {
9681
7.14k
            set->nodeTab = tmp;
9682
7.14k
            set->nodeMax = nodeMax;
9683
7.14k
        }
9684
7.14k
    }
9685
9686
82.8k
    xpctxt->node = oldnode;
9687
82.8k
    xpctxt->doc = olddoc;
9688
82.8k
    xpctxt->contextSize = oldcs;
9689
82.8k
    xpctxt->proximityPosition = oldpp;
9690
82.8k
}
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
83.1k
{
9711
83.1k
    if (op->ch1 != -1) {
9712
2.38k
  xmlXPathCompExprPtr comp = ctxt->comp;
9713
  /*
9714
  * Process inner predicates first.
9715
  */
9716
2.38k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9717
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9718
0
  }
9719
2.38k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9720
2.38k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9721
2.38k
        ctxt->context->depth += 1;
9722
2.38k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9723
2.38k
                                    1, set->nodeNr, hasNsNodes);
9724
2.38k
        ctxt->context->depth -= 1;
9725
2.38k
  CHECK_ERROR;
9726
2.38k
    }
9727
9728
83.1k
    if (op->ch2 != -1)
9729
83.1k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9730
83.1k
}
9731
9732
static int
9733
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9734
          xmlXPathStepOpPtr op,
9735
          int *maxPos)
9736
40.5k
{
9737
9738
40.5k
    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
40.5k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9754
0
  return(0);
9755
9756
40.5k
    if (op->ch2 != -1) {
9757
40.5k
  exprOp = &ctxt->comp->steps[op->ch2];
9758
40.5k
    } else
9759
0
  return(0);
9760
9761
40.5k
    if ((exprOp != NULL) &&
9762
40.5k
  (exprOp->op == XPATH_OP_VALUE) &&
9763
20.0k
  (exprOp->value4 != NULL) &&
9764
20.0k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9765
19.4k
    {
9766
19.4k
        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
19.4k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9780
17.5k
      *maxPos = (int) floatval;
9781
17.5k
            if (floatval == (double) *maxPos)
9782
17.4k
                return(1);
9783
17.5k
        }
9784
19.4k
    }
9785
23.0k
    return(0);
9786
40.5k
}
9787
9788
static int
9789
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9790
                           xmlXPathStepOpPtr op,
9791
         xmlNodePtr * first, xmlNodePtr * last,
9792
         int toBool)
9793
10.3M
{
9794
9795
10.3M
#define XP_TEST_HIT \
9796
337M
    if (hasAxisRange != 0) { \
9797
16.5k
  if (++pos == maxPos) { \
9798
4.57k
      if (addNode(seq, cur) < 0) \
9799
4.57k
          xmlXPathPErrMemory(ctxt); \
9800
4.57k
      goto axis_range_end; } \
9801
337M
    } else { \
9802
337M
  if (addNode(seq, cur) < 0) \
9803
337M
      xmlXPathPErrMemory(ctxt); \
9804
337M
  if (breakOnFirstHit) goto first_hit; }
9805
9806
10.3M
#define XP_TEST_HIT_NS \
9807
10.3M
    if (hasAxisRange != 0) { \
9808
0
  if (++pos == maxPos) { \
9809
0
      hasNsNodes = 1; \
9810
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9811
0
          xmlXPathPErrMemory(ctxt); \
9812
0
  goto axis_range_end; } \
9813
774k
    } else { \
9814
774k
  hasNsNodes = 1; \
9815
774k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9816
774k
      xmlXPathPErrMemory(ctxt); \
9817
774k
  if (breakOnFirstHit) goto first_hit; }
9818
9819
10.3M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9820
10.3M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9821
10.3M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9822
10.3M
    const xmlChar *prefix = op->value4;
9823
10.3M
    const xmlChar *name = op->value5;
9824
10.3M
    const xmlChar *URI = NULL;
9825
9826
10.3M
    int total = 0, hasNsNodes = 0;
9827
    /* The popped object holding the context nodes */
9828
10.3M
    xmlXPathObjectPtr obj;
9829
    /* The set of context nodes for the node tests */
9830
10.3M
    xmlNodeSetPtr contextSeq;
9831
10.3M
    int contextIdx;
9832
10.3M
    xmlNodePtr contextNode;
9833
    /* The final resulting node set wrt to all context nodes */
9834
10.3M
    xmlNodeSetPtr outSeq;
9835
    /*
9836
    * The temporary resulting node set wrt 1 context node.
9837
    * Used to feed predicate evaluation.
9838
    */
9839
10.3M
    xmlNodeSetPtr seq;
9840
10.3M
    xmlNodePtr cur;
9841
    /* First predicate operator */
9842
10.3M
    xmlXPathStepOpPtr predOp;
9843
10.3M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9844
10.3M
    int hasPredicateRange, hasAxisRange, pos;
9845
10.3M
    int breakOnFirstHit;
9846
9847
10.3M
    xmlXPathTraversalFunction next = NULL;
9848
10.3M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9849
10.3M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9850
10.3M
    xmlNodePtr oldContextNode;
9851
10.3M
    xmlXPathContextPtr xpctxt = ctxt->context;
9852
9853
9854
10.3M
    CHECK_TYPE0(XPATH_NODESET);
9855
10.3M
    obj = xmlXPathValuePop(ctxt);
9856
    /*
9857
    * Setup namespaces.
9858
    */
9859
10.3M
    if (prefix != NULL) {
9860
813k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9861
813k
        if (URI == NULL) {
9862
273
      xmlXPathReleaseObject(xpctxt, obj);
9863
273
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9864
273
                           "Undefined namespace prefix: %s\n", prefix);
9865
273
            return 0;
9866
273
  }
9867
813k
    }
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
10.3M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9882
10.3M
    switch (axis) {
9883
14.1k
        case AXIS_ANCESTOR:
9884
14.1k
            first = NULL;
9885
14.1k
            next = xmlXPathNextAncestor;
9886
14.1k
            break;
9887
600k
        case AXIS_ANCESTOR_OR_SELF:
9888
600k
            first = NULL;
9889
600k
            next = xmlXPathNextAncestorOrSelf;
9890
600k
            break;
9891
621k
        case AXIS_ATTRIBUTE:
9892
621k
            first = NULL;
9893
621k
      last = NULL;
9894
621k
            next = xmlXPathNextAttribute;
9895
621k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9896
621k
            break;
9897
7.98M
        case AXIS_CHILD:
9898
7.98M
      last = NULL;
9899
7.98M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9900
7.98M
    (type == NODE_TYPE_NODE))
9901
7.98M
      {
9902
    /*
9903
    * Optimization if an element node type is 'element'.
9904
    */
9905
7.98M
    next = xmlXPathNextChildElement;
9906
7.98M
      } else
9907
7.17k
    next = xmlXPathNextChild;
9908
7.98M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9909
7.98M
            break;
9910
476k
        case AXIS_DESCENDANT:
9911
476k
      last = NULL;
9912
476k
            next = xmlXPathNextDescendant;
9913
476k
            break;
9914
575k
        case AXIS_DESCENDANT_OR_SELF:
9915
575k
      last = NULL;
9916
575k
            next = xmlXPathNextDescendantOrSelf;
9917
575k
            break;
9918
0
        case AXIS_FOLLOWING:
9919
0
      last = NULL;
9920
0
            next = xmlXPathNextFollowing;
9921
0
            break;
9922
0
        case AXIS_FOLLOWING_SIBLING:
9923
0
      last = NULL;
9924
0
            next = xmlXPathNextFollowingSibling;
9925
0
            break;
9926
3.09k
        case AXIS_NAMESPACE:
9927
3.09k
            first = NULL;
9928
3.09k
      last = NULL;
9929
3.09k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9930
3.09k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9931
3.09k
            break;
9932
23.1k
        case AXIS_PARENT:
9933
23.1k
            first = NULL;
9934
23.1k
            next = xmlXPathNextParent;
9935
23.1k
            break;
9936
0
        case AXIS_PRECEDING:
9937
0
            first = NULL;
9938
0
            next = xmlXPathNextPrecedingInternal;
9939
0
            break;
9940
0
        case AXIS_PRECEDING_SIBLING:
9941
0
            first = NULL;
9942
0
            next = xmlXPathNextPrecedingSibling;
9943
0
            break;
9944
12.2k
        case AXIS_SELF:
9945
12.2k
            first = NULL;
9946
12.2k
      last = NULL;
9947
12.2k
            next = xmlXPathNextSelf;
9948
12.2k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9949
12.2k
            break;
9950
10.3M
    }
9951
9952
10.3M
    if (next == NULL) {
9953
0
  xmlXPathReleaseObject(xpctxt, obj);
9954
0
        return(0);
9955
0
    }
9956
10.3M
    contextSeq = obj->nodesetval;
9957
10.3M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9958
145k
        xmlXPathValuePush(ctxt, obj);
9959
145k
        return(0);
9960
145k
    }
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
10.1M
    maxPos = 0;
9980
10.1M
    predOp = NULL;
9981
10.1M
    hasPredicateRange = 0;
9982
10.1M
    hasAxisRange = 0;
9983
10.1M
    if (op->ch2 != -1) {
9984
  /*
9985
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9986
  */
9987
40.5k
  predOp = &ctxt->comp->steps[op->ch2];
9988
40.5k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9989
17.4k
      if (predOp->ch1 != -1) {
9990
    /*
9991
    * Use the next inner predicate operator.
9992
    */
9993
2.48k
    predOp = &ctxt->comp->steps[predOp->ch1];
9994
2.48k
    hasPredicateRange = 1;
9995
15.0k
      } else {
9996
    /*
9997
    * There's no other predicate than the [n] predicate.
9998
    */
9999
15.0k
    predOp = NULL;
10000
15.0k
    hasAxisRange = 1;
10001
15.0k
      }
10002
17.4k
  }
10003
40.5k
    }
10004
10.1M
    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
10.1M
    oldContextNode = xpctxt->node;
10019
10.1M
    addNode = xmlXPathNodeSetAddUnique;
10020
10.1M
    outSeq = NULL;
10021
10.1M
    seq = NULL;
10022
10.1M
    contextNode = NULL;
10023
10.1M
    contextIdx = 0;
10024
10025
10026
217M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10027
207M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
10028
207M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
10029
10030
207M
  if (seq == NULL) {
10031
10.7M
      seq = xmlXPathNodeSetCreate(NULL);
10032
10.7M
      if (seq == NULL) {
10033
0
                xmlXPathPErrMemory(ctxt);
10034
0
    total = 0;
10035
0
    goto error;
10036
0
      }
10037
10.7M
  }
10038
  /*
10039
  * Traverse the axis and test the nodes.
10040
  */
10041
207M
  pos = 0;
10042
207M
  cur = NULL;
10043
207M
  hasNsNodes = 0;
10044
658M
        do {
10045
658M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10046
0
                goto error;
10047
10048
658M
            cur = next(ctxt, cur);
10049
658M
            if (cur == NULL)
10050
207M
                break;
10051
10052
      /*
10053
      * QUESTION TODO: What does the "first" and "last" stuff do?
10054
      */
10055
450M
            if ((first != NULL) && (*first != NULL)) {
10056
0
    if (*first == cur)
10057
0
        break;
10058
0
    if (((total % 256) == 0) &&
10059
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10060
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10061
#else
10062
        (xmlXPathCmpNodes(*first, cur) >= 0))
10063
#endif
10064
0
    {
10065
0
        break;
10066
0
    }
10067
0
      }
10068
450M
      if ((last != NULL) && (*last != NULL)) {
10069
0
    if (*last == cur)
10070
0
        break;
10071
0
    if (((total % 256) == 0) &&
10072
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10073
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10074
#else
10075
        (xmlXPathCmpNodes(cur, *last) >= 0))
10076
#endif
10077
0
    {
10078
0
        break;
10079
0
    }
10080
0
      }
10081
10082
450M
            total++;
10083
10084
450M
      switch (test) {
10085
0
                case NODE_TEST_NONE:
10086
0
        total = 0;
10087
0
        goto error;
10088
186M
                case NODE_TEST_TYPE:
10089
186M
        if (type == NODE_TYPE_NODE) {
10090
186M
      switch (cur->type) {
10091
464k
          case XML_DOCUMENT_NODE:
10092
464k
          case XML_HTML_DOCUMENT_NODE:
10093
118M
          case XML_ELEMENT_NODE:
10094
118M
          case XML_ATTRIBUTE_NODE:
10095
119M
          case XML_PI_NODE:
10096
124M
          case XML_COMMENT_NODE:
10097
124M
          case XML_CDATA_SECTION_NODE:
10098
186M
          case XML_TEXT_NODE:
10099
186M
        XP_TEST_HIT
10100
186M
        break;
10101
186M
          case XML_NAMESPACE_DECL: {
10102
22.8k
        if (axis == AXIS_NAMESPACE) {
10103
0
            XP_TEST_HIT_NS
10104
22.8k
        } else {
10105
22.8k
                              hasNsNodes = 1;
10106
22.8k
            XP_TEST_HIT
10107
22.8k
        }
10108
22.8k
        break;
10109
22.8k
                            }
10110
22.8k
          default:
10111
0
        break;
10112
186M
      }
10113
186M
        } else if (cur->type == (xmlElementType) type) {
10114
15
      if (cur->type == XML_NAMESPACE_DECL)
10115
0
          XP_TEST_HIT_NS
10116
15
      else
10117
15
          XP_TEST_HIT
10118
52
        } else if ((type == NODE_TYPE_TEXT) &&
10119
31
       (cur->type == XML_CDATA_SECTION_NODE))
10120
0
        {
10121
0
      XP_TEST_HIT
10122
0
        }
10123
186M
        break;
10124
186M
                case NODE_TEST_PI:
10125
0
                    if ((cur->type == XML_PI_NODE) &&
10126
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10127
0
        {
10128
0
      XP_TEST_HIT
10129
0
                    }
10130
0
                    break;
10131
182M
                case NODE_TEST_ALL:
10132
182M
                    if (axis == AXIS_ATTRIBUTE) {
10133
11.7M
                        if (cur->type == XML_ATTRIBUTE_NODE)
10134
11.7M
      {
10135
11.7M
                            if (prefix == NULL)
10136
11.7M
          {
10137
11.7M
        XP_TEST_HIT
10138
11.7M
                            } else if ((cur->ns != NULL) &&
10139
0
        (xmlStrEqual(URI, cur->ns->href)))
10140
0
          {
10141
0
        XP_TEST_HIT
10142
0
                            }
10143
11.7M
                        }
10144
170M
                    } else if (axis == AXIS_NAMESPACE) {
10145
774k
                        if (cur->type == XML_NAMESPACE_DECL)
10146
774k
      {
10147
774k
          XP_TEST_HIT_NS
10148
774k
                        }
10149
169M
                    } else {
10150
169M
                        if (cur->type == XML_ELEMENT_NODE) {
10151
136M
                            if (prefix == NULL)
10152
136M
          {
10153
136M
        XP_TEST_HIT
10154
10155
136M
                            } else if ((cur->ns != NULL) &&
10156
5.80k
        (xmlStrEqual(URI, cur->ns->href)))
10157
175
          {
10158
175
        XP_TEST_HIT
10159
175
                            }
10160
136M
                        }
10161
169M
                    }
10162
182M
                    break;
10163
182M
                case NODE_TEST_NS:{
10164
                        /* TODO */
10165
0
                        break;
10166
182M
                    }
10167
81.4M
                case NODE_TEST_NAME:
10168
81.4M
                    if (axis == AXIS_ATTRIBUTE) {
10169
326k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10170
0
          break;
10171
81.0M
        } else if (axis == AXIS_NAMESPACE) {
10172
0
                        if (cur->type != XML_NAMESPACE_DECL)
10173
0
          break;
10174
81.0M
        } else {
10175
81.0M
            if (cur->type != XML_ELEMENT_NODE)
10176
33.7M
          break;
10177
81.0M
        }
10178
47.6M
                    switch (cur->type) {
10179
47.3M
                        case XML_ELEMENT_NODE:
10180
47.3M
                            if (xmlStrEqual(name, cur->name)) {
10181
1.98M
                                if (prefix == NULL) {
10182
1.58M
                                    if (cur->ns == NULL)
10183
1.20M
            {
10184
1.20M
          XP_TEST_HIT
10185
1.20M
                                    }
10186
1.58M
                                } else {
10187
399k
                                    if ((cur->ns != NULL) &&
10188
399k
                                        (xmlStrEqual(URI, cur->ns->href)))
10189
396k
            {
10190
396k
          XP_TEST_HIT
10191
396k
                                    }
10192
399k
                                }
10193
1.98M
                            }
10194
47.3M
                            break;
10195
47.3M
                        case XML_ATTRIBUTE_NODE:{
10196
326k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10197
10198
326k
                                if (xmlStrEqual(name, attr->name)) {
10199
8.50k
                                    if (prefix == NULL) {
10200
8.50k
                                        if ((attr->ns == NULL) ||
10201
0
                                            (attr->ns->prefix == NULL))
10202
8.50k
          {
10203
8.50k
              XP_TEST_HIT
10204
8.50k
                                        }
10205
8.50k
                                    } else {
10206
0
                                        if ((attr->ns != NULL) &&
10207
0
                                            (xmlStrEqual(URI,
10208
0
                attr->ns->href)))
10209
0
          {
10210
0
              XP_TEST_HIT
10211
0
                                        }
10212
0
                                    }
10213
8.50k
                                }
10214
326k
                                break;
10215
326k
                            }
10216
326k
                        case XML_NAMESPACE_DECL:
10217
0
                            if (cur->type == XML_NAMESPACE_DECL) {
10218
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
10219
10220
0
                                if ((ns->prefix != NULL) && (name != NULL)
10221
0
                                    && (xmlStrEqual(ns->prefix, name)))
10222
0
        {
10223
0
            XP_TEST_HIT_NS
10224
0
                                }
10225
0
                            }
10226
0
                            break;
10227
0
                        default:
10228
0
                            break;
10229
47.6M
                    }
10230
47.6M
                    break;
10231
450M
      } /* switch(test) */
10232
450M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10233
10234
207M
  goto apply_predicates;
10235
10236
207M
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
4.57k
  if (outSeq == NULL) {
10244
1.90k
      outSeq = seq;
10245
1.90k
      seq = NULL;
10246
2.66k
  } else {
10247
2.66k
      outSeq = mergeAndClear(outSeq, seq);
10248
2.66k
            if (outSeq == NULL)
10249
0
                xmlXPathPErrMemory(ctxt);
10250
2.66k
        }
10251
  /*
10252
  * Break if only a true/false result was requested.
10253
  */
10254
4.57k
  if (toBool)
10255
37
      break;
10256
4.53k
  continue;
10257
10258
13.2k
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
13.2k
  if (outSeq == NULL) {
10264
13.2k
      outSeq = seq;
10265
13.2k
      seq = NULL;
10266
13.2k
  } else {
10267
0
      outSeq = mergeAndClear(outSeq, seq);
10268
0
            if (outSeq == NULL)
10269
0
                xmlXPathPErrMemory(ctxt);
10270
0
        }
10271
13.2k
  break;
10272
10273
207M
apply_predicates: /* --------------------------------------------------- */
10274
207M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10275
0
      goto error;
10276
10277
        /*
10278
  * Apply predicates.
10279
  */
10280
207M
        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
80.7k
      if (hasPredicateRange != 0)
10310
4.61k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10311
4.61k
              hasNsNodes);
10312
76.1k
      else
10313
76.1k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10314
76.1k
              hasNsNodes);
10315
10316
80.7k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10317
36
    total = 0;
10318
36
    goto error;
10319
36
      }
10320
80.7k
        }
10321
10322
207M
        if (seq->nodeNr > 0) {
10323
      /*
10324
      * Add to result set.
10325
      */
10326
17.1M
      if (outSeq == NULL) {
10327
2.56M
    outSeq = seq;
10328
2.56M
    seq = NULL;
10329
14.5M
      } else {
10330
14.5M
    outSeq = mergeAndClear(outSeq, seq);
10331
14.5M
                if (outSeq == NULL)
10332
0
                    xmlXPathPErrMemory(ctxt);
10333
14.5M
      }
10334
10335
17.1M
            if (toBool)
10336
258
                break;
10337
17.1M
  }
10338
207M
    }
10339
10340
10.1M
error:
10341
10.1M
    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
10.1M
    xmlXPathReleaseObject(xpctxt, obj);
10353
10354
    /*
10355
    * Ensure we return at least an empty set.
10356
    */
10357
10.1M
    if (outSeq == NULL) {
10358
7.59M
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10359
7.59M
      outSeq = seq;
10360
7.59M
        } else {
10361
0
      outSeq = xmlXPathNodeSetCreate(NULL);
10362
0
            if (outSeq == NULL)
10363
0
                xmlXPathPErrMemory(ctxt);
10364
0
        }
10365
7.59M
    }
10366
10.1M
    if ((seq != NULL) && (seq != outSeq)) {
10367
567k
   xmlXPathFreeNodeSet(seq);
10368
567k
    }
10369
    /*
10370
    * Hand over the result. Better to push the set also in
10371
    * case of errors.
10372
    */
10373
10.1M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10374
    /*
10375
    * Reset the context node.
10376
    */
10377
10.1M
    xpctxt->node = oldContextNode;
10378
    /*
10379
    * When traversing the namespace axis in "toBool" mode, it's
10380
    * possible that tmpNsList wasn't freed.
10381
    */
10382
10.1M
    if (xpctxt->tmpNsList != NULL) {
10383
0
        xmlFree(xpctxt->tmpNsList);
10384
0
        xpctxt->tmpNsList = NULL;
10385
0
    }
10386
10387
10.1M
    return(total);
10388
10.1M
}
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
112
{
10407
112
    int total = 0, cur;
10408
112
    xmlXPathCompExprPtr comp;
10409
112
    xmlXPathObjectPtr arg1, arg2;
10410
10411
112
    CHECK_ERROR0;
10412
112
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10413
0
        return(0);
10414
112
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10415
112
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10416
112
    ctxt->context->depth += 1;
10417
112
    comp = ctxt->comp;
10418
112
    switch (op->op) {
10419
0
        case XPATH_OP_END:
10420
0
            break;
10421
0
        case XPATH_OP_UNION:
10422
0
            total =
10423
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10424
0
                                        first);
10425
0
      CHECK_ERROR0;
10426
0
            if ((ctxt->value != NULL)
10427
0
                && (ctxt->value->type == XPATH_NODESET)
10428
0
                && (ctxt->value->nodesetval != NULL)
10429
0
                && (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
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10441
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10442
0
                *first = ctxt->value->nodesetval->nodeTab[0];
10443
0
            }
10444
0
            cur =
10445
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10446
0
                                        first);
10447
0
      CHECK_ERROR0;
10448
10449
0
            arg2 = xmlXPathValuePop(ctxt);
10450
0
            arg1 = xmlXPathValuePop(ctxt);
10451
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10452
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10453
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10454
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10455
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10456
0
            }
10457
0
            if ((ctxt->context->opLimit != 0) &&
10458
0
                (((arg1->nodesetval != NULL) &&
10459
0
                  (xmlXPathCheckOpLimit(ctxt,
10460
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10461
0
                 ((arg2->nodesetval != NULL) &&
10462
0
                  (xmlXPathCheckOpLimit(ctxt,
10463
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10464
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10465
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10466
0
                break;
10467
0
            }
10468
10469
0
            if ((arg2->nodesetval != NULL) &&
10470
0
                (arg2->nodesetval->nodeNr != 0)) {
10471
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10472
0
                                                        arg2->nodesetval);
10473
0
                if (arg1->nodesetval == NULL)
10474
0
                    xmlXPathPErrMemory(ctxt);
10475
0
            }
10476
0
            xmlXPathValuePush(ctxt, arg1);
10477
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10478
0
            total += cur;
10479
0
            break;
10480
0
        case XPATH_OP_ROOT:
10481
0
            xmlXPathRoot(ctxt);
10482
0
            break;
10483
0
        case XPATH_OP_NODE:
10484
0
            if (op->ch1 != -1)
10485
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10486
0
      CHECK_ERROR0;
10487
0
            if (op->ch2 != -1)
10488
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10489
0
      CHECK_ERROR0;
10490
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10491
0
    ctxt->context->node));
10492
0
            break;
10493
0
        case XPATH_OP_COLLECT:{
10494
0
                if (op->ch1 == -1)
10495
0
                    break;
10496
10497
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10498
0
    CHECK_ERROR0;
10499
10500
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10501
0
                break;
10502
0
            }
10503
0
        case XPATH_OP_VALUE:
10504
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10505
0
            break;
10506
54
        case XPATH_OP_SORT:
10507
54
            if (op->ch1 != -1)
10508
54
                total +=
10509
54
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10510
54
                                            first);
10511
54
      CHECK_ERROR0;
10512
54
            if ((ctxt->value != NULL)
10513
54
                && (ctxt->value->type == XPATH_NODESET)
10514
0
                && (ctxt->value->nodesetval != NULL)
10515
0
    && (ctxt->value->nodesetval->nodeNr > 1))
10516
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10517
54
            break;
10518
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10519
4
  case XPATH_OP_FILTER:
10520
4
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10521
4
            break;
10522
0
#endif
10523
54
        default:
10524
54
            total += xmlXPathCompOpEval(ctxt, op);
10525
54
            break;
10526
112
    }
10527
10528
112
    ctxt->context->depth -= 1;
10529
112
    return(total);
10530
112
}
10531
10532
/**
10533
 * Evaluate the Precompiled XPath operation searching only the last
10534
 * element in document order
10535
 *
10536
 * @param ctxt  the XPath parser context with the compiled expression
10537
 * @param op  an XPath compiled operation
10538
 * @param last  the last elem found so far
10539
 * @returns the number of nodes traversed
10540
 */
10541
static int
10542
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10543
                       xmlNodePtr * last)
10544
0
{
10545
0
    int total = 0, cur;
10546
0
    xmlXPathCompExprPtr comp;
10547
0
    xmlXPathObjectPtr arg1, arg2;
10548
10549
0
    CHECK_ERROR0;
10550
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10551
0
        return(0);
10552
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10553
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10554
0
    ctxt->context->depth += 1;
10555
0
    comp = ctxt->comp;
10556
0
    switch (op->op) {
10557
0
        case XPATH_OP_END:
10558
0
            break;
10559
0
        case XPATH_OP_UNION:
10560
0
            total =
10561
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10562
0
      CHECK_ERROR0;
10563
0
            if ((ctxt->value != NULL)
10564
0
                && (ctxt->value->type == XPATH_NODESET)
10565
0
                && (ctxt->value->nodesetval != NULL)
10566
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10567
                /*
10568
                 * limit tree traversing to first node in the result
10569
                 */
10570
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10571
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10572
0
                *last =
10573
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10574
0
                                                     nodesetval->nodeNr -
10575
0
                                                     1];
10576
0
            }
10577
0
            cur =
10578
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10579
0
      CHECK_ERROR0;
10580
0
            if ((ctxt->value != NULL)
10581
0
                && (ctxt->value->type == XPATH_NODESET)
10582
0
                && (ctxt->value->nodesetval != NULL)
10583
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10584
0
            }
10585
10586
0
            arg2 = xmlXPathValuePop(ctxt);
10587
0
            arg1 = xmlXPathValuePop(ctxt);
10588
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10589
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10590
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10591
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10592
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10593
0
            }
10594
0
            if ((ctxt->context->opLimit != 0) &&
10595
0
                (((arg1->nodesetval != NULL) &&
10596
0
                  (xmlXPathCheckOpLimit(ctxt,
10597
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10598
0
                 ((arg2->nodesetval != NULL) &&
10599
0
                  (xmlXPathCheckOpLimit(ctxt,
10600
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10601
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10602
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10603
0
                break;
10604
0
            }
10605
10606
0
            if ((arg2->nodesetval != NULL) &&
10607
0
                (arg2->nodesetval->nodeNr != 0)) {
10608
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10609
0
                                                        arg2->nodesetval);
10610
0
                if (arg1->nodesetval == NULL)
10611
0
                    xmlXPathPErrMemory(ctxt);
10612
0
            }
10613
0
            xmlXPathValuePush(ctxt, arg1);
10614
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10615
0
            total += cur;
10616
0
            break;
10617
0
        case XPATH_OP_ROOT:
10618
0
            xmlXPathRoot(ctxt);
10619
0
            break;
10620
0
        case XPATH_OP_NODE:
10621
0
            if (op->ch1 != -1)
10622
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10623
0
      CHECK_ERROR0;
10624
0
            if (op->ch2 != -1)
10625
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10626
0
      CHECK_ERROR0;
10627
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10628
0
    ctxt->context->node));
10629
0
            break;
10630
0
        case XPATH_OP_COLLECT:{
10631
0
                if (op->ch1 == -1)
10632
0
                    break;
10633
10634
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10635
0
    CHECK_ERROR0;
10636
10637
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10638
0
                break;
10639
0
            }
10640
0
        case XPATH_OP_VALUE:
10641
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10642
0
            break;
10643
0
        case XPATH_OP_SORT:
10644
0
            if (op->ch1 != -1)
10645
0
                total +=
10646
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10647
0
                                           last);
10648
0
      CHECK_ERROR0;
10649
0
            if ((ctxt->value != NULL)
10650
0
                && (ctxt->value->type == XPATH_NODESET)
10651
0
                && (ctxt->value->nodesetval != NULL)
10652
0
    && (ctxt->value->nodesetval->nodeNr > 1))
10653
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10654
0
            break;
10655
0
        default:
10656
0
            total += xmlXPathCompOpEval(ctxt, op);
10657
0
            break;
10658
0
    }
10659
10660
0
    ctxt->context->depth -= 1;
10661
0
    return (total);
10662
0
}
10663
10664
#ifdef XP_OPTIMIZED_FILTER_FIRST
10665
static int
10666
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10667
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10668
4
{
10669
4
    int total = 0;
10670
4
    xmlXPathCompExprPtr comp;
10671
4
    xmlXPathObjectPtr obj;
10672
4
    xmlNodeSetPtr set;
10673
10674
4
    CHECK_ERROR0;
10675
4
    comp = ctxt->comp;
10676
    /*
10677
    * Optimization for ()[last()] selection i.e. the last elem
10678
    */
10679
4
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10680
4
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10681
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10682
0
  int f = comp->steps[op->ch2].ch1;
10683
10684
0
  if ((f != -1) &&
10685
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10686
0
      (comp->steps[f].value5 == NULL) &&
10687
0
      (comp->steps[f].value == 0) &&
10688
0
      (comp->steps[f].value4 != NULL) &&
10689
0
      (xmlStrEqual
10690
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
10691
0
      xmlNodePtr last = NULL;
10692
10693
0
      total +=
10694
0
    xmlXPathCompOpEvalLast(ctxt,
10695
0
        &comp->steps[op->ch1],
10696
0
        &last);
10697
0
      CHECK_ERROR0;
10698
      /*
10699
      * The nodeset should be in document order,
10700
      * Keep only the last value
10701
      */
10702
0
      if ((ctxt->value != NULL) &&
10703
0
    (ctxt->value->type == XPATH_NODESET) &&
10704
0
    (ctxt->value->nodesetval != NULL) &&
10705
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10706
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
10707
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10708
0
    *first = *(ctxt->value->nodesetval->nodeTab);
10709
0
      }
10710
0
      return (total);
10711
0
  }
10712
0
    }
10713
10714
4
    if (op->ch1 != -1)
10715
4
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10716
4
    CHECK_ERROR0;
10717
3
    if (op->ch2 == -1)
10718
0
  return (total);
10719
3
    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
3
    CHECK_TYPE0(XPATH_NODESET);
10728
0
    obj = xmlXPathValuePop(ctxt);
10729
0
    set = obj->nodesetval;
10730
0
    if (set != NULL) {
10731
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10732
0
        if (set->nodeNr > 0)
10733
0
            *first = set->nodeTab[0];
10734
0
    }
10735
0
    xmlXPathValuePush(ctxt, obj);
10736
10737
0
    return (total);
10738
3
}
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
34.0M
{
10751
34.0M
    int total = 0;
10752
34.0M
    int equal, ret;
10753
34.0M
    xmlXPathCompExprPtr comp;
10754
34.0M
    xmlXPathObjectPtr arg1, arg2;
10755
10756
34.0M
    CHECK_ERROR0;
10757
34.0M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10758
0
        return(0);
10759
34.0M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10760
34.0M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10761
34.0M
    ctxt->context->depth += 1;
10762
34.0M
    comp = ctxt->comp;
10763
34.0M
    switch (op->op) {
10764
0
        case XPATH_OP_END:
10765
0
            break;
10766
81.3k
        case XPATH_OP_AND:
10767
81.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10768
81.3k
      CHECK_ERROR0;
10769
81.2k
            xmlXPathBooleanFunction(ctxt, 1);
10770
81.2k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10771
22.3k
                break;
10772
58.9k
            arg2 = xmlXPathValuePop(ctxt);
10773
58.9k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10774
58.9k
      if (ctxt->error) {
10775
53
    xmlXPathFreeObject(arg2);
10776
53
    break;
10777
53
      }
10778
58.8k
            xmlXPathBooleanFunction(ctxt, 1);
10779
58.8k
            if (ctxt->value != NULL)
10780
58.8k
                ctxt->value->boolval &= arg2->boolval;
10781
58.8k
      xmlXPathReleaseObject(ctxt->context, arg2);
10782
58.8k
            break;
10783
53.9k
        case XPATH_OP_OR:
10784
53.9k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10785
53.9k
      CHECK_ERROR0;
10786
53.2k
            xmlXPathBooleanFunction(ctxt, 1);
10787
53.2k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10788
22.2k
                break;
10789
31.0k
            arg2 = xmlXPathValuePop(ctxt);
10790
31.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10791
31.0k
      if (ctxt->error) {
10792
35
    xmlXPathFreeObject(arg2);
10793
35
    break;
10794
35
      }
10795
30.9k
            xmlXPathBooleanFunction(ctxt, 1);
10796
30.9k
            if (ctxt->value != NULL)
10797
30.9k
                ctxt->value->boolval |= arg2->boolval;
10798
30.9k
      xmlXPathReleaseObject(ctxt->context, arg2);
10799
30.9k
            break;
10800
940k
        case XPATH_OP_EQUAL:
10801
940k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10802
940k
      CHECK_ERROR0;
10803
939k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10804
939k
      CHECK_ERROR0;
10805
939k
      if (op->value)
10806
923k
    equal = xmlXPathEqualValues(ctxt);
10807
16.6k
      else
10808
16.6k
    equal = xmlXPathNotEqualValues(ctxt);
10809
939k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10810
939k
            break;
10811
399k
        case XPATH_OP_CMP:
10812
399k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10813
399k
      CHECK_ERROR0;
10814
399k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10815
399k
      CHECK_ERROR0;
10816
399k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10817
399k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10818
399k
            break;
10819
865k
        case XPATH_OP_PLUS:
10820
865k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10821
865k
      CHECK_ERROR0;
10822
865k
            if (op->ch2 != -1) {
10823
436k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10824
436k
      }
10825
865k
      CHECK_ERROR0;
10826
865k
            if (op->value == 0)
10827
403k
                xmlXPathSubValues(ctxt);
10828
461k
            else if (op->value == 1)
10829
32.8k
                xmlXPathAddValues(ctxt);
10830
428k
            else if (op->value == 2)
10831
382k
                xmlXPathValueFlipSign(ctxt);
10832
45.9k
            else if (op->value == 3) {
10833
45.9k
                CAST_TO_NUMBER;
10834
45.9k
                CHECK_TYPE0(XPATH_NUMBER);
10835
45.9k
            }
10836
865k
            break;
10837
6.14M
        case XPATH_OP_MULT:
10838
6.14M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10839
6.14M
      CHECK_ERROR0;
10840
6.12M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10841
6.12M
      CHECK_ERROR0;
10842
6.12M
            if (op->value == 0)
10843
6.04M
                xmlXPathMultValues(ctxt);
10844
80.1k
            else if (op->value == 1)
10845
0
                xmlXPathDivValues(ctxt);
10846
80.1k
            else if (op->value == 2)
10847
80.1k
                xmlXPathModValues(ctxt);
10848
6.12M
            break;
10849
642k
        case XPATH_OP_UNION:
10850
642k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10851
642k
      CHECK_ERROR0;
10852
642k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10853
642k
      CHECK_ERROR0;
10854
10855
642k
            arg2 = xmlXPathValuePop(ctxt);
10856
642k
            arg1 = xmlXPathValuePop(ctxt);
10857
642k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10858
642k
                (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
642k
            if ((ctxt->context->opLimit != 0) &&
10864
0
                (((arg1->nodesetval != NULL) &&
10865
0
                  (xmlXPathCheckOpLimit(ctxt,
10866
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10867
0
                 ((arg2->nodesetval != NULL) &&
10868
0
                  (xmlXPathCheckOpLimit(ctxt,
10869
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10870
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10871
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10872
0
                break;
10873
0
            }
10874
10875
642k
      if (((arg2->nodesetval != NULL) &&
10876
642k
     (arg2->nodesetval->nodeNr != 0)))
10877
322k
      {
10878
322k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10879
322k
              arg2->nodesetval);
10880
322k
                if (arg1->nodesetval == NULL)
10881
0
                    xmlXPathPErrMemory(ctxt);
10882
322k
      }
10883
10884
642k
            xmlXPathValuePush(ctxt, arg1);
10885
642k
      xmlXPathReleaseObject(ctxt->context, arg2);
10886
642k
            break;
10887
892k
        case XPATH_OP_ROOT:
10888
892k
            xmlXPathRoot(ctxt);
10889
892k
            break;
10890
8.93M
        case XPATH_OP_NODE:
10891
8.93M
            if (op->ch1 != -1)
10892
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10893
8.93M
      CHECK_ERROR0;
10894
8.93M
            if (op->ch2 != -1)
10895
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10896
8.93M
      CHECK_ERROR0;
10897
8.93M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10898
8.93M
                                                    ctxt->context->node));
10899
8.93M
            break;
10900
10.2M
        case XPATH_OP_COLLECT:{
10901
10.2M
                if (op->ch1 == -1)
10902
0
                    break;
10903
10904
10.2M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10905
10.2M
    CHECK_ERROR0;
10906
10907
10.2M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10908
10.2M
                break;
10909
10.2M
            }
10910
662k
        case XPATH_OP_VALUE:
10911
662k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10912
662k
            break;
10913
27
        case XPATH_OP_VARIABLE:{
10914
27
    xmlXPathObjectPtr val;
10915
10916
27
                if (op->ch1 != -1)
10917
0
                    total +=
10918
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10919
27
                if (op->value5 == NULL) {
10920
20
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10921
20
        if (val == NULL) {
10922
20
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10923
20
                                       "Undefined variable: %s\n", op->value4);
10924
20
                        return 0;
10925
20
                    }
10926
0
                    xmlXPathValuePush(ctxt, val);
10927
7
    } else {
10928
7
                    const xmlChar *URI;
10929
10930
7
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10931
7
                    if (URI == NULL) {
10932
5
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10933
5
                                       "Undefined namespace prefix: %s\n",
10934
5
                                       op->value5);
10935
5
                        return 0;
10936
5
                    }
10937
2
        val = xmlXPathVariableLookupNS(ctxt->context,
10938
2
                                                       op->value4, URI);
10939
2
        if (val == NULL) {
10940
2
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10941
2
                                       "Undefined variable: %s:%s\n",
10942
2
                                       op->value5, op->value4);
10943
2
                        return 0;
10944
2
                    }
10945
0
                    xmlXPathValuePush(ctxt, val);
10946
0
                }
10947
0
                break;
10948
27
            }
10949
1.21M
        case XPATH_OP_FUNCTION:{
10950
1.21M
                xmlXPathFunction func;
10951
1.21M
                const xmlChar *oldFunc, *oldFuncURI;
10952
1.21M
    int i;
10953
1.21M
                int frame;
10954
10955
1.21M
                frame = ctxt->valueNr;
10956
1.21M
                if (op->ch1 != -1) {
10957
1.19M
                    total +=
10958
1.19M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10959
1.19M
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10960
461
                        break;
10961
1.19M
                }
10962
1.21M
    if (ctxt->valueNr < frame + op->value)
10963
1.21M
        XP_ERROR0(XPATH_INVALID_OPERAND);
10964
2.40M
    for (i = 0; i < op->value; i++) {
10965
1.19M
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10966
1.19M
      XP_ERROR0(XPATH_INVALID_OPERAND);
10967
1.19M
                }
10968
1.21M
                if (op->cache != NULL)
10969
1.20M
                    func = op->cache;
10970
4.25k
                else {
10971
4.25k
                    const xmlChar *URI = NULL;
10972
10973
4.25k
                    if (op->value5 == NULL) {
10974
4.25k
                        func = xmlXPathFunctionLookup(ctxt->context,
10975
4.25k
                                                      op->value4);
10976
4.25k
                        if (func == NULL) {
10977
77
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10978
77
                                           "Unregistered function: %s\n",
10979
77
                                           op->value4);
10980
77
                            return 0;
10981
77
                        }
10982
4.25k
                    } else {
10983
3
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10984
3
                        if (URI == NULL) {
10985
2
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10986
2
                                           "Undefined namespace prefix: %s\n",
10987
2
                                           op->value5);
10988
2
                            return 0;
10989
2
                        }
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
4.17k
                    op->cache = func;
11000
4.17k
                    op->cacheURI = (void *) URI;
11001
4.17k
                }
11002
1.21M
                oldFunc = ctxt->context->function;
11003
1.21M
                oldFuncURI = ctxt->context->functionURI;
11004
1.21M
                ctxt->context->function = op->value4;
11005
1.21M
                ctxt->context->functionURI = op->cacheURI;
11006
1.21M
                func(ctxt, op->value);
11007
1.21M
                ctxt->context->function = oldFunc;
11008
1.21M
                ctxt->context->functionURI = oldFuncURI;
11009
1.21M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11010
1.21M
                    (ctxt->valueNr != frame + 1))
11011
1.21M
                    XP_ERROR0(XPATH_STACK_ERROR);
11012
1.21M
                break;
11013
1.21M
            }
11014
1.19M
        case XPATH_OP_ARG:
11015
1.19M
            if (op->ch1 != -1) {
11016
2.65k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11017
2.65k
          CHECK_ERROR0;
11018
2.65k
            }
11019
1.19M
            if (op->ch2 != -1) {
11020
1.19M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11021
1.19M
          CHECK_ERROR0;
11022
1.19M
      }
11023
1.19M
            break;
11024
1.19M
        case XPATH_OP_PREDICATE:
11025
3.25k
        case XPATH_OP_FILTER:{
11026
3.25k
                xmlXPathObjectPtr obj;
11027
3.25k
                xmlNodeSetPtr set;
11028
11029
                /*
11030
                 * Optimization for ()[1] selection i.e. the first elem
11031
                 */
11032
3.25k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11033
3.25k
#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
3.25k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11044
23
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11045
#else
11046
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
#endif
11048
3.24k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11049
71
                    xmlXPathObjectPtr val;
11050
11051
71
                    val = comp->steps[op->ch2].value4;
11052
71
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11053
71
                        (val->floatval == 1.0)) {
11054
58
                        xmlNodePtr first = NULL;
11055
11056
58
                        total +=
11057
58
                            xmlXPathCompOpEvalFirst(ctxt,
11058
58
                                                    &comp->steps[op->ch1],
11059
58
                                                    &first);
11060
58
      CHECK_ERROR0;
11061
                        /*
11062
                         * The nodeset should be in document order,
11063
                         * Keep only the first value
11064
                         */
11065
54
                        if ((ctxt->value != NULL) &&
11066
54
                            (ctxt->value->type == XPATH_NODESET) &&
11067
0
                            (ctxt->value->nodesetval != NULL) &&
11068
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11069
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11070
0
                                                        1, 1);
11071
54
                        break;
11072
58
                    }
11073
71
                }
11074
                /*
11075
                 * Optimization for ()[last()] selection i.e. the last elem
11076
                 */
11077
3.19k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11078
3.19k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11079
3.18k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11080
3.17k
                    int f = comp->steps[op->ch2].ch1;
11081
11082
3.17k
                    if ((f != -1) &&
11083
3.17k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11084
2.99k
                        (comp->steps[f].value5 == NULL) &&
11085
2.99k
                        (comp->steps[f].value == 0) &&
11086
1
                        (comp->steps[f].value4 != NULL) &&
11087
1
                        (xmlStrEqual
11088
1
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11089
0
                        xmlNodePtr last = NULL;
11090
11091
0
                        total +=
11092
0
                            xmlXPathCompOpEvalLast(ctxt,
11093
0
                                                   &comp->steps[op->ch1],
11094
0
                                                   &last);
11095
0
      CHECK_ERROR0;
11096
                        /*
11097
                         * The nodeset should be in document order,
11098
                         * Keep only the last value
11099
                         */
11100
0
                        if ((ctxt->value != NULL) &&
11101
0
                            (ctxt->value->type == XPATH_NODESET) &&
11102
0
                            (ctxt->value->nodesetval != NULL) &&
11103
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11104
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11105
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11106
0
                        break;
11107
0
                    }
11108
3.17k
                }
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
3.19k
                if (op->ch1 != -1)
11121
3.19k
                    total +=
11122
3.19k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11123
3.19k
    CHECK_ERROR0;
11124
3.18k
                if (op->ch2 == -1)
11125
0
                    break;
11126
3.18k
                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
3.18k
                CHECK_TYPE0(XPATH_NODESET);
11136
3.17k
                obj = xmlXPathValuePop(ctxt);
11137
3.17k
                set = obj->nodesetval;
11138
3.17k
                if (set != NULL)
11139
3.17k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11140
3.17k
                                          1, set->nodeNr, 1);
11141
3.17k
                xmlXPathValuePush(ctxt, obj);
11142
3.17k
                break;
11143
3.18k
            }
11144
1.70M
        case XPATH_OP_SORT:
11145
1.70M
            if (op->ch1 != -1)
11146
1.70M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11147
1.70M
      CHECK_ERROR0;
11148
1.70M
            if ((ctxt->value != NULL) &&
11149
1.70M
                (ctxt->value->type == XPATH_NODESET) &&
11150
1.22M
                (ctxt->value->nodesetval != NULL) &&
11151
1.22M
    (ctxt->value->nodesetval->nodeNr > 1))
11152
7.79k
      {
11153
7.79k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11154
7.79k
      }
11155
1.70M
            break;
11156
0
        default:
11157
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11158
0
            break;
11159
34.0M
    }
11160
11161
34.0M
    ctxt->context->depth -= 1;
11162
34.0M
    return (total);
11163
34.0M
}
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.38M
{
11178
1.38M
    xmlXPathObjectPtr resObj = NULL;
11179
11180
2.56M
start:
11181
2.56M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11182
0
        return(0);
11183
    /* comp = ctxt->comp; */
11184
2.56M
    switch (op->op) {
11185
0
        case XPATH_OP_END:
11186
0
            return (0);
11187
15.2k
  case XPATH_OP_VALUE:
11188
15.2k
      resObj = (xmlXPathObjectPtr) op->value4;
11189
15.2k
      if (isPredicate)
11190
15.2k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11191
0
      return(xmlXPathCastToBoolean(resObj));
11192
1.17M
  case XPATH_OP_SORT:
11193
      /*
11194
      * We don't need sorting for boolean results. Skip this one.
11195
      */
11196
1.17M
            if (op->ch1 != -1) {
11197
1.17M
    op = &ctxt->comp->steps[op->ch1];
11198
1.17M
    goto start;
11199
1.17M
      }
11200
0
      return(0);
11201
17.8k
  case XPATH_OP_COLLECT:
11202
17.8k
      if (op->ch1 == -1)
11203
0
    return(0);
11204
11205
17.8k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11206
17.8k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11207
3
    return(-1);
11208
11209
17.8k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11210
17.8k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11211
6
    return(-1);
11212
11213
17.8k
      resObj = xmlXPathValuePop(ctxt);
11214
17.8k
      if (resObj == NULL)
11215
0
    return(-1);
11216
17.8k
      break;
11217
1.35M
  default:
11218
      /*
11219
      * Fallback to call xmlXPathCompOpEval().
11220
      */
11221
1.35M
      xmlXPathCompOpEval(ctxt, op);
11222
1.35M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11223
813
    return(-1);
11224
11225
1.35M
      resObj = xmlXPathValuePop(ctxt);
11226
1.35M
      if (resObj == NULL)
11227
0
    return(-1);
11228
1.35M
      break;
11229
2.56M
    }
11230
11231
1.36M
    if (resObj) {
11232
1.36M
  int res;
11233
11234
1.36M
  if (resObj->type == XPATH_BOOLEAN) {
11235
1.33M
      res = resObj->boolval;
11236
1.33M
  } 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
30.6k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11246
30.6k
  } else {
11247
0
      res = xmlXPathCastToBoolean(resObj);
11248
0
  }
11249
1.36M
  xmlXPathReleaseObject(ctxt->context, resObj);
11250
1.36M
  return(res);
11251
1.36M
    }
11252
11253
0
    return(0);
11254
1.36M
}
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
504k
{
11497
504k
    xmlXPathCompExprPtr comp;
11498
504k
    int oldDepth;
11499
11500
504k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11501
0
  return(-1);
11502
11503
504k
    if (ctxt->valueTab == NULL) {
11504
3.09k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11505
3.09k
        int valueMax = 1;
11506
#else
11507
        int valueMax = 10;
11508
#endif
11509
11510
  /* Allocate the value stack */
11511
3.09k
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11512
3.09k
  if (ctxt->valueTab == NULL) {
11513
0
      xmlXPathPErrMemory(ctxt);
11514
0
      return(-1);
11515
0
  }
11516
3.09k
  ctxt->valueNr = 0;
11517
3.09k
  ctxt->valueMax = valueMax;
11518
3.09k
  ctxt->value = NULL;
11519
3.09k
    }
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
504k
    comp = ctxt->comp;
11553
504k
    if (comp->last < 0) {
11554
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11555
0
  return(-1);
11556
0
    }
11557
504k
    oldDepth = ctxt->context->depth;
11558
504k
    if (toBool)
11559
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11560
0
      &comp->steps[comp->last], 0));
11561
504k
    else
11562
504k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11563
504k
    ctxt->context->depth = oldDepth;
11564
11565
504k
    return(0);
11566
504k
}
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
384k
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11590
384k
    if ((ctxt == NULL) || (res == NULL)) return(0);
11591
384k
    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
384k
        case XPATH_NODESET:
11597
384k
        case XPATH_XSLT_TREE:
11598
384k
      if (res->nodesetval == NULL)
11599
0
    return(0);
11600
384k
      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
384k
    }
11607
0
    return(0);
11608
384k
}
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
45.9k
                                xmlXPathObject *res) {
11627
45.9k
    if ((ctxt == NULL) || (res == NULL)) return(0);
11628
45.9k
    switch (res->type) {
11629
0
        case XPATH_BOOLEAN:
11630
0
      return(res->boolval);
11631
22.8k
        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
22.8k
      return(res->floatval == ctxt->context->proximityPosition);
11637
0
#endif
11638
17.8k
        case XPATH_NODESET:
11639
17.8k
        case XPATH_XSLT_TREE:
11640
17.8k
      if (res->nodesetval == NULL)
11641
0
    return(0);
11642
17.8k
      return(res->nodesetval->nodeNr != 0);
11643
5.18k
        case XPATH_STRING:
11644
5.18k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11645
0
        default:
11646
0
      break;
11647
45.9k
    }
11648
0
    return(0);
11649
45.9k
}
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
6.31M
{
11741
6.31M
    xmlXPathCompExprPtr comp = pctxt->comp;
11742
6.31M
    xmlXPathContextPtr ctxt;
11743
11744
    /*
11745
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11746
    * internal representation.
11747
    */
11748
11749
6.31M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11750
2.09M
        (op->ch1 != -1) &&
11751
2.09M
        (op->ch2 == -1 /* no predicate */))
11752
2.09M
    {
11753
2.09M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11754
11755
2.09M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11756
18.8k
            ((xmlXPathAxisVal) prevop->value ==
11757
18.8k
                AXIS_DESCENDANT_OR_SELF) &&
11758
14.2k
            (prevop->ch2 == -1) &&
11759
14.2k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11760
14.2k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11761
14.2k
        {
11762
            /*
11763
            * This is a "descendant-or-self::node()" without predicates.
11764
            * Try to eliminate it.
11765
            */
11766
11767
14.2k
            switch ((xmlXPathAxisVal) op->value) {
11768
4.26k
                case AXIS_CHILD:
11769
4.26k
                case AXIS_DESCENDANT:
11770
                    /*
11771
                    * Convert "descendant-or-self::node()/child::" or
11772
                    * "descendant-or-self::node()/descendant::" to
11773
                    * "descendant::"
11774
                    */
11775
4.26k
                    op->ch1   = prevop->ch1;
11776
4.26k
                    op->value = AXIS_DESCENDANT;
11777
4.26k
                    break;
11778
0
                case AXIS_SELF:
11779
26
                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
26
                    op->ch1   = prevop->ch1;
11786
26
                    op->value = AXIS_DESCENDANT_OR_SELF;
11787
26
                    break;
11788
9.94k
                default:
11789
9.94k
                    break;
11790
14.2k
            }
11791
14.2k
  }
11792
2.09M
    }
11793
11794
    /* OP_VALUE has invalid ch1. */
11795
6.31M
    if (op->op == XPATH_OP_VALUE)
11796
12.1k
        return;
11797
11798
    /* Recurse */
11799
6.29M
    ctxt = pctxt->context;
11800
6.29M
    if (ctxt != NULL) {
11801
6.29M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11802
5.33k
            return;
11803
6.29M
        ctxt->depth += 1;
11804
6.29M
    }
11805
6.29M
    if (op->ch1 != -1)
11806
4.21M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11807
6.29M
    if (op->ch2 != -1)
11808
2.08M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11809
6.29M
    if (ctxt != NULL)
11810
6.29M
        ctxt->depth -= 1;
11811
6.29M
}
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
23.4k
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11823
23.4k
    xmlXPathParserContextPtr pctxt;
11824
23.4k
    xmlXPathContextPtr tmpctxt = NULL;
11825
23.4k
    xmlXPathCompExprPtr comp;
11826
23.4k
    int oldDepth = 0;
11827
11828
23.4k
    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
23.4k
    xmlInitParser();
11838
11839
    /*
11840
     * We need an xmlXPathContext for the depth check.
11841
     */
11842
23.4k
    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
23.4k
    pctxt = xmlXPathNewParserContext(str, ctxt);
11850
23.4k
    if (pctxt == NULL) {
11851
0
        if (tmpctxt != NULL)
11852
0
            xmlXPathFreeContext(tmpctxt);
11853
0
        return NULL;
11854
0
    }
11855
11856
23.4k
    oldDepth = ctxt->depth;
11857
23.4k
    xmlXPathCompileExpr(pctxt, 1);
11858
23.4k
    ctxt->depth = oldDepth;
11859
11860
23.4k
    if( pctxt->error != XPATH_EXPRESSION_OK )
11861
7.83k
    {
11862
7.83k
        xmlXPathFreeParserContext(pctxt);
11863
7.83k
        if (tmpctxt != NULL)
11864
0
            xmlXPathFreeContext(tmpctxt);
11865
7.83k
        return(NULL);
11866
7.83k
    }
11867
11868
15.6k
    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
5.05k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11876
5.05k
  comp = NULL;
11877
10.5k
    } else {
11878
10.5k
  comp = pctxt->comp;
11879
10.5k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11880
9.43k
            if (ctxt != NULL)
11881
9.43k
                oldDepth = ctxt->depth;
11882
9.43k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11883
9.43k
            if (ctxt != NULL)
11884
9.43k
                ctxt->depth = oldDepth;
11885
9.43k
  }
11886
10.5k
  pctxt->comp = NULL;
11887
10.5k
    }
11888
15.6k
    xmlXPathFreeParserContext(pctxt);
11889
15.6k
    if (tmpctxt != NULL)
11890
0
        xmlXPathFreeContext(tmpctxt);
11891
11892
15.6k
    if (comp != NULL) {
11893
10.5k
  comp->expr = xmlStrdup(str);
11894
10.5k
    }
11895
15.6k
    return(comp);
11896
23.4k
}
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
500k
{
11927
500k
    xmlXPathParserContextPtr pctxt;
11928
500k
    xmlXPathObjectPtr resObj = NULL;
11929
500k
    int res;
11930
11931
500k
    if (comp == NULL)
11932
0
  return(-1);
11933
500k
    xmlInitParser();
11934
11935
500k
    xmlResetError(&ctxt->lastError);
11936
11937
500k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11938
500k
    if (pctxt == NULL)
11939
0
        return(-1);
11940
500k
    res = xmlXPathRunEval(pctxt, toBool);
11941
11942
500k
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11943
500k
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11944
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11945
500k
        else if (!toBool)
11946
500k
            resObj = xmlXPathValuePop(pctxt);
11947
500k
    }
11948
11949
500k
    if (resObjPtr)
11950
500k
        *resObjPtr = resObj;
11951
0
    else
11952
0
        xmlXPathReleaseObject(ctxt, resObj);
11953
11954
500k
    pctxt->comp = NULL;
11955
500k
    xmlXPathFreeParserContext(pctxt);
11956
11957
500k
    return(res);
11958
500k
}
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
500k
{
11971
500k
    xmlXPathObjectPtr res = NULL;
11972
11973
500k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11974
500k
    return(res);
11975
500k
}
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
5.22k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
12003
#ifdef XPATH_STREAMING
12004
    xmlXPathCompExprPtr comp;
12005
#endif
12006
5.22k
    int oldDepth = 0;
12007
12008
5.22k
    if ((ctxt == NULL) || (ctxt->context == NULL))
12009
0
        return;
12010
5.22k
    if (ctxt->context->lastError.code != 0)
12011
0
        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
5.22k
    {
12027
5.22k
        if (ctxt->context != NULL)
12028
5.22k
            oldDepth = ctxt->context->depth;
12029
5.22k
  xmlXPathCompileExpr(ctxt, 1);
12030
5.22k
        if (ctxt->context != NULL)
12031
5.22k
            ctxt->context->depth = oldDepth;
12032
5.22k
        CHECK_ERROR;
12033
12034
        /* Check for trailing characters. */
12035
4.36k
        if (*ctxt->cur != 0)
12036
4.35k
            XP_ERROR(XPATH_EXPR_ERROR);
12037
12038
4.35k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12039
4.35k
            if (ctxt->context != NULL)
12040
4.35k
                oldDepth = ctxt->context->depth;
12041
4.35k
      xmlXPathOptimizeExpression(ctxt,
12042
4.35k
    &ctxt->comp->steps[ctxt->comp->last]);
12043
4.35k
            if (ctxt->context != NULL)
12044
4.35k
                ctxt->context->depth = oldDepth;
12045
4.35k
        }
12046
4.35k
    }
12047
12048
0
    xmlXPathRunEval(ctxt, 0);
12049
4.35k
}
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
3.94k
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12061
3.94k
    xmlXPathParserContextPtr ctxt;
12062
3.94k
    xmlXPathObjectPtr res;
12063
12064
3.94k
    if (ctx == NULL)
12065
0
        return(NULL);
12066
12067
3.94k
    xmlInitParser();
12068
12069
3.94k
    xmlResetError(&ctx->lastError);
12070
12071
3.94k
    ctxt = xmlXPathNewParserContext(str, ctx);
12072
3.94k
    if (ctxt == NULL)
12073
0
        return NULL;
12074
3.94k
    xmlXPathEvalExpr(ctxt);
12075
12076
3.94k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12077
1.64k
  res = NULL;
12078
2.30k
    } else if (ctxt->valueNr != 1) {
12079
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12080
0
  res = NULL;
12081
2.30k
    } else {
12082
2.30k
  res = xmlXPathValuePop(ctxt);
12083
2.30k
    }
12084
12085
3.94k
    xmlXPathFreeParserContext(ctxt);
12086
3.94k
    return(res);
12087
3.94k
}
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
5.22k
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12099
5.22k
    if ((node == NULL) || (ctx == NULL))
12100
0
        return(-1);
12101
12102
5.22k
    if (node->doc == ctx->doc) {
12103
5.22k
        ctx->node = node;
12104
5.22k
  return(0);
12105
5.22k
    }
12106
0
    return(-1);
12107
5.22k
}
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
3.94k
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12138
3.94k
    return(xmlXPathEval(str, ctxt));
12139
3.94k
}
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 */