Coverage Report

Created: 2026-07-16 06:18

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
639k
#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
6.70k
#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
6.35M
#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
21.4M
#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
182k
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
670k
#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
192k
xmlXPathSFComputeHash(const xmlChar *name) {
187
192k
    unsigned hashValue = 5381;
188
192k
    const xmlChar *ptr;
189
190
1.62M
    for (ptr = name; *ptr; ptr++)
191
1.43M
        hashValue = hashValue * 33 + *ptr;
192
193
192k
    return(hashValue);
194
192k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
6.52k
xmlInitXPathInternal(void) {
202
6.52k
    size_t i;
203
204
6.52k
#if defined(NAN) && defined(INFINITY)
205
6.52k
    xmlXPathNAN = NAN;
206
6.52k
    xmlXPathPINF = INFINITY;
207
6.52k
    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
423k
    for (i = 0; i < SF_HASH_SIZE; i++)
221
417k
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
182k
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
176k
        const char *name = xmlXPathStandardFunctions[i].name;
225
176k
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
221k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
45.6k
            bucketIndex += 1;
229
45.6k
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
45.6k
        }
232
233
176k
        xmlXPathSFHash[bucketIndex] = i;
234
176k
    }
235
6.52k
}
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
1.91M
xmlXPathIsNaN(double val) {
251
1.91M
#ifdef isnan
252
1.91M
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
1.91M
}
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
848k
xmlXPathIsInf(double val) {
266
848k
#ifdef isinf
267
848k
    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
848k
}
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
44.7M
#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
40.4M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
40.4M
    int depth1, depth2;
311
40.4M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
40.4M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
40.4M
    xmlNodePtr cur, root;
314
40.4M
    XML_INTPTR_T l1, l2;
315
316
40.4M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
40.4M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
40.4M
    switch (node1->type) {
326
24.0M
  case XML_ELEMENT_NODE:
327
24.0M
      if (node2->type == XML_ELEMENT_NODE) {
328
13.7M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
900
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
900
        (node1->doc == node2->doc))
331
900
    {
332
900
        l1 = -XML_NODE_SORT_VALUE(node1);
333
900
        l2 = -XML_NODE_SORT_VALUE(node2);
334
900
        if (l1 < l2)
335
900
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
13.7M
        goto turtle_comparison;
340
13.7M
      }
341
10.2M
      break;
342
10.2M
  case XML_ATTRIBUTE_NODE:
343
36.8k
      precedence1 = 1; /* element is owner */
344
36.8k
      miscNode1 = node1;
345
36.8k
      node1 = node1->parent;
346
36.8k
      misc = 1;
347
36.8k
      break;
348
12.8M
  case XML_TEXT_NODE:
349
12.9M
  case XML_CDATA_SECTION_NODE:
350
13.0M
  case XML_COMMENT_NODE:
351
13.1M
  case XML_PI_NODE: {
352
13.1M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
13.1M
      if (node1->prev != NULL) {
357
34.3M
    do {
358
34.3M
        node1 = node1->prev;
359
34.3M
        if (node1->type == XML_ELEMENT_NODE) {
360
11.1M
      precedence1 = 3; /* element in prev-sibl axis */
361
11.1M
      break;
362
11.1M
        }
363
23.1M
        if (node1->prev == NULL) {
364
135k
      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
135k
      node1 = node1->parent;
370
135k
      break;
371
135k
        }
372
23.1M
    } while (1);
373
11.3M
      } else {
374
1.83M
    precedence1 = 2; /* element is parent */
375
1.83M
    node1 = node1->parent;
376
1.83M
      }
377
13.1M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
13.1M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
13.1M
    node1 = miscNode1;
383
13.1M
    precedence1 = 0;
384
13.1M
      } else
385
32.8k
    misc = 1;
386
13.1M
  }
387
13.1M
      break;
388
2.99M
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
2.99M
      return(1);
393
258k
  default:
394
258k
      break;
395
40.4M
    }
396
23.7M
    switch (node2->type) {
397
10.2M
  case XML_ELEMENT_NODE:
398
10.2M
      break;
399
35.3k
  case XML_ATTRIBUTE_NODE:
400
35.3k
      precedence2 = 1; /* element is owner */
401
35.3k
      miscNode2 = node2;
402
35.3k
      node2 = node2->parent;
403
35.3k
      misc = 1;
404
35.3k
      break;
405
12.6M
  case XML_TEXT_NODE:
406
12.7M
  case XML_CDATA_SECTION_NODE:
407
12.8M
  case XML_COMMENT_NODE:
408
12.9M
  case XML_PI_NODE: {
409
12.9M
      miscNode2 = node2;
410
12.9M
      if (node2->prev != NULL) {
411
35.1M
    do {
412
35.1M
        node2 = node2->prev;
413
35.1M
        if (node2->type == XML_ELEMENT_NODE) {
414
10.7M
      precedence2 = 3; /* element in prev-sibl axis */
415
10.7M
      break;
416
10.7M
        }
417
24.4M
        if (node2->prev == NULL) {
418
175k
      precedence2 = 2; /* element is parent */
419
175k
      node2 = node2->parent;
420
175k
      break;
421
175k
        }
422
24.4M
    } while (1);
423
10.8M
      } else {
424
2.08M
    precedence2 = 2; /* element is parent */
425
2.08M
    node2 = node2->parent;
426
2.08M
      }
427
12.9M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
12.9M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
12.8M
      {
430
12.8M
    node2 = miscNode2;
431
12.8M
    precedence2 = 0;
432
12.8M
      } else
433
101k
    misc = 1;
434
12.9M
  }
435
12.9M
      break;
436
5.05k
  case XML_NAMESPACE_DECL:
437
5.05k
      return(1);
438
452k
  default:
439
452k
      break;
440
23.7M
    }
441
23.7M
    if (misc) {
442
153k
  if (node1 == node2) {
443
108k
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
32.8k
    cur = miscNode2->prev;
449
34.3k
    while (cur != NULL) {
450
32.8k
        if (cur == miscNode1)
451
31.3k
      return(1);
452
1.49k
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
1.49k
        cur = cur->prev;
455
1.49k
    }
456
1.53k
    return (-1);
457
75.3k
      } 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
75.3k
    if (precedence1 < precedence2)
464
72.2k
        return(1);
465
3.05k
    else
466
3.05k
        return(-1);
467
75.3k
      }
468
108k
  }
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
45.3k
  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
45.3k
  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
45.3k
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
23.6M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
10.2M
  (node2->type == XML_ELEMENT_NODE) &&
501
34.4k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
1.23k
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
1.23k
  (node1->doc == node2->doc)) {
504
505
1.23k
  l1 = -XML_NODE_SORT_VALUE(node1);
506
1.23k
  l2 = -XML_NODE_SORT_VALUE(node2);
507
1.23k
  if (l1 < l2)
508
1.23k
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
37.3M
turtle_comparison:
514
515
37.3M
    if (node1 == node2->prev)
516
13.3M
  return(1);
517
24.0M
    if (node1 == node2->next)
518
1.54M
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
185M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
166M
  if (cur->parent == node1)
524
3.51M
      return(1);
525
162M
  depth2++;
526
162M
    }
527
18.9M
    root = cur;
528
221M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
207M
  if (cur->parent == node2)
530
5.26M
      return(-1);
531
202M
  depth1++;
532
202M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
13.7M
    if (root != cur) {
537
2.07k
  return(-2);
538
2.07k
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
53.6M
    while (depth1 > depth2) {
543
39.8M
  depth1--;
544
39.8M
  node1 = node1->parent;
545
39.8M
    }
546
35.9M
    while (depth2 > depth1) {
547
22.2M
  depth2--;
548
22.2M
  node2 = node2->parent;
549
22.2M
    }
550
20.4M
    while (node1->parent != node2->parent) {
551
6.76M
  node1 = node1->parent;
552
6.76M
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
6.76M
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
6.76M
    }
557
    /*
558
     * Find who's first.
559
     */
560
13.7M
    if (node1 == node2->prev)
561
969k
  return(1);
562
12.7M
    if (node1 == node2->next)
563
4.45M
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
8.30M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
6.46M
  (node2->type == XML_ELEMENT_NODE) &&
569
4.85M
  (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
561M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
556M
  if (cur == node2)
583
3.09M
      return(1);
584
5.21M
    return(-1); /* assume there is no sibling list corruption */
585
8.30M
}
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
7.71M
#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
40.4M
    {
607
40.4M
        int res = xmlXPathCmpNodesExt(x, y);
608
40.4M
        return res == -2 ? res : -res;
609
40.4M
    }
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
40.4M
#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.28k
    { 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
13.1M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
13.1M
       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
432k
{
678
432k
    if (ctxt == NULL)
679
0
        return;
680
432k
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
432k
                        &ctxt->lastError);
682
432k
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
430k
{
692
430k
    if (ctxt == NULL)
693
0
        return;
694
430k
    ctxt->error = XPATH_MEMORY_ERROR;
695
430k
    xmlXPathErrMemory(ctxt->context);
696
430k
}
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
13.1M
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
13.1M
    va_list ap;
709
13.1M
    xmlStructuredErrorFunc schannel = NULL;
710
13.1M
    xmlGenericErrorFunc channel = NULL;
711
13.1M
    void *data = NULL;
712
13.1M
    xmlNodePtr node = NULL;
713
13.1M
    int res;
714
715
13.1M
    if (ctxt == NULL)
716
0
        return;
717
13.1M
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
13.1M
    if (ctxt->error != 0)
721
13.1M
        return;
722
723
32.9k
    ctxt->error = code;
724
725
32.9k
    if (ctxt->context != NULL) {
726
32.9k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
32.9k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
32.9k
        xmlResetError(err);
734
735
32.9k
        err->domain = XML_FROM_XPATH;
736
32.9k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
32.9k
        err->level = XML_ERR_ERROR;
738
32.9k
        if (ctxt->base != NULL) {
739
32.2k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
32.2k
            if (err->str1 == NULL) {
741
135
                xmlXPathPErrMemory(ctxt);
742
135
                return;
743
135
            }
744
32.2k
        }
745
32.7k
        err->int1 = ctxt->cur - ctxt->base;
746
32.7k
        err->node = ctxt->context->debugNode;
747
748
32.7k
        schannel = ctxt->context->error;
749
32.7k
        data = ctxt->context->userData;
750
32.7k
        node = ctxt->context->debugNode;
751
32.7k
    }
752
753
32.7k
    if (schannel == NULL) {
754
27.8k
        channel = xmlGenericError;
755
27.8k
        data = xmlGenericErrorContext;
756
27.8k
    }
757
758
32.7k
    va_start(ap, fmt);
759
32.7k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
32.7k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
32.7k
                         XML_ERR_ERROR, NULL, 0,
762
32.7k
                         (const char *) ctxt->base, NULL, NULL,
763
32.7k
                         ctxt->cur - ctxt->base, 0,
764
32.7k
                         fmt, ap);
765
32.7k
    va_end(ap);
766
32.7k
    if (res < 0)
767
295
        xmlXPathPErrMemory(ctxt);
768
32.7k
}
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
13.1M
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
13.1M
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
13.1M
}
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
179
              int line ATTRIBUTE_UNUSED, int no) {
792
179
    xmlXPathErr(ctxt, no);
793
179
}
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
101M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
101M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
101M
    if ((opCount > xpctxt->opLimit) ||
807
101M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
702
        xpctxt->opCount = xpctxt->opLimit;
809
702
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
702
        return(-1);
811
702
    }
812
813
101M
    xpctxt->opCount += opCount;
814
101M
    return(0);
815
101M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
103M
    ((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
57.8k
xmlXPathNewCompExpr(void) {
941
57.8k
    xmlXPathCompExprPtr cur;
942
943
57.8k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
57.8k
    if (cur == NULL)
945
268
  return(NULL);
946
57.6k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
57.6k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
57.6k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
57.6k
    cur->nbStep = 0;
953
57.6k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
57.6k
                                     sizeof(xmlXPathStepOp));
955
57.6k
    if (cur->steps == NULL) {
956
118
  xmlFree(cur);
957
118
  return(NULL);
958
118
    }
959
57.5k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
57.5k
    cur->last = -1;
961
57.5k
    return(cur);
962
57.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
59.2k
{
972
59.2k
    xmlXPathStepOpPtr op;
973
59.2k
    int i;
974
975
59.2k
    if (comp == NULL)
976
1.78k
        return;
977
57.5k
    if (comp->dict == NULL) {
978
47.3M
  for (i = 0; i < comp->nbStep; i++) {
979
47.3M
      op = &comp->steps[i];
980
47.3M
      if (op->value4 != NULL) {
981
281k
    if (op->op == XPATH_OP_VALUE)
982
237k
        xmlXPathFreeObject(op->value4);
983
44.5k
    else
984
44.5k
        xmlFree(op->value4);
985
281k
      }
986
47.3M
      if (op->value5 != NULL)
987
1.77M
    xmlFree(op->value5);
988
47.3M
  }
989
57.5k
    } else {
990
0
  for (i = 0; i < comp->nbStep; i++) {
991
0
      op = &comp->steps[i];
992
0
      if (op->value4 != NULL) {
993
0
    if (op->op == XPATH_OP_VALUE)
994
0
        xmlXPathFreeObject(op->value4);
995
0
      }
996
0
  }
997
0
        xmlDictFree(comp->dict);
998
0
    }
999
57.5k
    if (comp->steps != NULL) {
1000
57.5k
        xmlFree(comp->steps);
1001
57.5k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
57.5k
    if (comp->expr != NULL) {
1008
4.20k
        xmlFree(comp->expr);
1009
4.20k
    }
1010
1011
57.5k
    xmlFree(comp);
1012
57.5k
}
1013
1014
/**
1015
 * Add a step to an XPath Compiled Expression
1016
 *
1017
 * @param ctxt  XPath parser context
1018
 * @param ch1  first child index
1019
 * @param ch2  second child index
1020
 * @param op  an op
1021
 * @param value  the first int value
1022
 * @param value2  the second int value
1023
 * @param value3  the third int value
1024
 * @param value4  the first string value
1025
 * @param value5  the second string value
1026
 * @returns -1 in case of failure, the index otherwise
1027
 */
1028
static int
1029
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1030
   xmlXPathOp op, int value,
1031
47.7M
   int value2, int value3, void *value4, void *value5) {
1032
47.7M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
47.7M
    if (comp->nbStep >= comp->maxStep) {
1034
639k
  xmlXPathStepOp *real;
1035
639k
        int newSize;
1036
1037
639k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
639k
                                  10, XPATH_MAX_STEPS);
1039
639k
        if (newSize < 0) {
1040
423k
      xmlXPathPErrMemory(ctxt);
1041
423k
      return(-1);
1042
423k
        }
1043
216k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
216k
  if (real == NULL) {
1045
666
      xmlXPathPErrMemory(ctxt);
1046
666
      return(-1);
1047
666
  }
1048
215k
  comp->steps = real;
1049
215k
  comp->maxStep = newSize;
1050
215k
    }
1051
47.3M
    comp->last = comp->nbStep;
1052
47.3M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
47.3M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
47.3M
    comp->steps[comp->nbStep].op = op;
1055
47.3M
    comp->steps[comp->nbStep].value = value;
1056
47.3M
    comp->steps[comp->nbStep].value2 = value2;
1057
47.3M
    comp->steps[comp->nbStep].value3 = value3;
1058
47.3M
    if ((comp->dict != NULL) &&
1059
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
0
   (op == XPATH_OP_COLLECT))) {
1061
0
        if (value4 != NULL) {
1062
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
0
      xmlFree(value4);
1065
0
  } else
1066
0
      comp->steps[comp->nbStep].value4 = NULL;
1067
0
        if (value5 != NULL) {
1068
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
0
      xmlFree(value5);
1071
0
  } else
1072
0
      comp->steps[comp->nbStep].value5 = NULL;
1073
47.3M
    } else {
1074
47.3M
  comp->steps[comp->nbStep].value4 = value4;
1075
47.3M
  comp->steps[comp->nbStep].value5 = value5;
1076
47.3M
    }
1077
47.3M
    comp->steps[comp->nbStep].cache = NULL;
1078
47.3M
    return(comp->nbStep++);
1079
47.7M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
6.37M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
6.37M
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
359k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
359k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
19.6M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
19.6M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
1.66M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
1.66M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
19.7M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
19.7M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
19.7M
      (val), (val2), 0 ,NULL ,NULL)
1097
1098
/************************************************************************
1099
 *                  *
1100
 *    XPath object cache structures       *
1101
 *                  *
1102
 ************************************************************************/
1103
1104
/* #define XP_DEFAULT_CACHE_ON */
1105
1106
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1107
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1108
struct _xmlXPathContextCache {
1109
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1110
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1111
    int numNodeset;
1112
    int maxNodeset;
1113
    int numMisc;
1114
    int maxMisc;
1115
};
1116
1117
/************************************************************************
1118
 *                  *
1119
 *    Debugging related functions       *
1120
 *                  *
1121
 ************************************************************************/
1122
1123
#ifdef LIBXML_DEBUG_ENABLED
1124
static void
1125
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1126
    int i;
1127
    char shift[100];
1128
1129
    for (i = 0;((i < depth) && (i < 25));i++)
1130
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
    if (cur == NULL) {
1133
  fprintf(output, "%s", shift);
1134
  fprintf(output, "Node is NULL !\n");
1135
  return;
1136
1137
    }
1138
1139
    if ((cur->type == XML_DOCUMENT_NODE) ||
1140
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1141
  fprintf(output, "%s", shift);
1142
  fprintf(output, " /\n");
1143
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1144
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1145
    else
1146
  xmlDebugDumpOneNode(output, cur, depth);
1147
}
1148
static void
1149
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1150
    xmlNodePtr tmp;
1151
    int i;
1152
    char shift[100];
1153
1154
    for (i = 0;((i < depth) && (i < 25));i++)
1155
        shift[2 * i] = shift[2 * i + 1] = ' ';
1156
    shift[2 * i] = shift[2 * i + 1] = 0;
1157
    if (cur == NULL) {
1158
  fprintf(output, "%s", shift);
1159
  fprintf(output, "Node is NULL !\n");
1160
  return;
1161
1162
    }
1163
1164
    while (cur != NULL) {
1165
  tmp = cur;
1166
  cur = cur->next;
1167
  xmlDebugDumpOneNode(output, tmp, depth);
1168
    }
1169
}
1170
1171
static void
1172
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1173
    int i;
1174
    char shift[100];
1175
1176
    for (i = 0;((i < depth) && (i < 25));i++)
1177
        shift[2 * i] = shift[2 * i + 1] = ' ';
1178
    shift[2 * i] = shift[2 * i + 1] = 0;
1179
1180
    if (cur == NULL) {
1181
  fprintf(output, "%s", shift);
1182
  fprintf(output, "NodeSet is NULL !\n");
1183
  return;
1184
1185
    }
1186
1187
    if (cur != NULL) {
1188
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1189
  for (i = 0;i < cur->nodeNr;i++) {
1190
      fprintf(output, "%s", shift);
1191
      fprintf(output, "%d", i + 1);
1192
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1193
  }
1194
    }
1195
}
1196
1197
static void
1198
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1199
    int i;
1200
    char shift[100];
1201
1202
    for (i = 0;((i < depth) && (i < 25));i++)
1203
        shift[2 * i] = shift[2 * i + 1] = ' ';
1204
    shift[2 * i] = shift[2 * i + 1] = 0;
1205
1206
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1207
  fprintf(output, "%s", shift);
1208
  fprintf(output, "Value Tree is NULL !\n");
1209
  return;
1210
1211
    }
1212
1213
    fprintf(output, "%s", shift);
1214
    fprintf(output, "%d", i + 1);
1215
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1216
}
1217
1218
/**
1219
 * Dump the content of the object for debugging purposes
1220
 *
1221
 * @param output  the FILE * to dump the output
1222
 * @param cur  the object to inspect
1223
 * @param depth  indentation level
1224
 */
1225
void
1226
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1227
    int i;
1228
    char shift[100];
1229
1230
    if (output == NULL) return;
1231
1232
    for (i = 0;((i < depth) && (i < 25));i++)
1233
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
    fprintf(output, "%s", shift);
1238
1239
    if (cur == NULL) {
1240
        fprintf(output, "Object is empty (NULL)\n");
1241
  return;
1242
    }
1243
    switch(cur->type) {
1244
        case XPATH_UNDEFINED:
1245
      fprintf(output, "Object is uninitialized\n");
1246
      break;
1247
        case XPATH_NODESET:
1248
      fprintf(output, "Object is a Node Set :\n");
1249
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
      break;
1251
  case XPATH_XSLT_TREE:
1252
      fprintf(output, "Object is an XSLT value tree :\n");
1253
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
      break;
1255
        case XPATH_BOOLEAN:
1256
      fprintf(output, "Object is a Boolean : ");
1257
      if (cur->boolval) fprintf(output, "true\n");
1258
      else fprintf(output, "false\n");
1259
      break;
1260
        case XPATH_NUMBER:
1261
      switch (xmlXPathIsInf(cur->floatval)) {
1262
      case 1:
1263
    fprintf(output, "Object is a number : Infinity\n");
1264
    break;
1265
      case -1:
1266
    fprintf(output, "Object is a number : -Infinity\n");
1267
    break;
1268
      default:
1269
    if (xmlXPathIsNaN(cur->floatval)) {
1270
        fprintf(output, "Object is a number : NaN\n");
1271
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
        fprintf(output, "Object is a number : 0\n");
1274
    } else {
1275
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
    }
1277
      }
1278
      break;
1279
        case XPATH_STRING:
1280
      fprintf(output, "Object is a string : ");
1281
      xmlDebugDumpString(output, cur->stringval);
1282
      fprintf(output, "\n");
1283
      break;
1284
  case XPATH_USERS:
1285
      fprintf(output, "Object is user defined\n");
1286
      break;
1287
    }
1288
}
1289
1290
static void
1291
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1292
                       xmlXPathStepOpPtr op, int depth) {
1293
    int i;
1294
    char shift[100];
1295
1296
    for (i = 0;((i < depth) && (i < 25));i++)
1297
        shift[2 * i] = shift[2 * i + 1] = ' ';
1298
    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300
    fprintf(output, "%s", shift);
1301
    if (op == NULL) {
1302
  fprintf(output, "Step is NULL\n");
1303
  return;
1304
    }
1305
    switch (op->op) {
1306
        case XPATH_OP_END:
1307
      fprintf(output, "END"); break;
1308
        case XPATH_OP_AND:
1309
      fprintf(output, "AND"); break;
1310
        case XPATH_OP_OR:
1311
      fprintf(output, "OR"); break;
1312
        case XPATH_OP_EQUAL:
1313
       if (op->value)
1314
     fprintf(output, "EQUAL =");
1315
       else
1316
     fprintf(output, "EQUAL !=");
1317
       break;
1318
        case XPATH_OP_CMP:
1319
       if (op->value)
1320
     fprintf(output, "CMP <");
1321
       else
1322
     fprintf(output, "CMP >");
1323
       if (!op->value2)
1324
     fprintf(output, "=");
1325
       break;
1326
        case XPATH_OP_PLUS:
1327
       if (op->value == 0)
1328
     fprintf(output, "PLUS -");
1329
       else if (op->value == 1)
1330
     fprintf(output, "PLUS +");
1331
       else if (op->value == 2)
1332
     fprintf(output, "PLUS unary -");
1333
       else if (op->value == 3)
1334
     fprintf(output, "PLUS unary - -");
1335
       break;
1336
        case XPATH_OP_MULT:
1337
       if (op->value == 0)
1338
     fprintf(output, "MULT *");
1339
       else if (op->value == 1)
1340
     fprintf(output, "MULT div");
1341
       else
1342
     fprintf(output, "MULT mod");
1343
       break;
1344
        case XPATH_OP_UNION:
1345
       fprintf(output, "UNION"); break;
1346
        case XPATH_OP_ROOT:
1347
       fprintf(output, "ROOT"); break;
1348
        case XPATH_OP_NODE:
1349
       fprintf(output, "NODE"); break;
1350
        case XPATH_OP_SORT:
1351
       fprintf(output, "SORT"); break;
1352
        case XPATH_OP_COLLECT: {
1353
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1354
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1355
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1356
      const xmlChar *prefix = op->value4;
1357
      const xmlChar *name = op->value5;
1358
1359
      fprintf(output, "COLLECT ");
1360
      switch (axis) {
1361
    case AXIS_ANCESTOR:
1362
        fprintf(output, " 'ancestors' "); break;
1363
    case AXIS_ANCESTOR_OR_SELF:
1364
        fprintf(output, " 'ancestors-or-self' "); break;
1365
    case AXIS_ATTRIBUTE:
1366
        fprintf(output, " 'attributes' "); break;
1367
    case AXIS_CHILD:
1368
        fprintf(output, " 'child' "); break;
1369
    case AXIS_DESCENDANT:
1370
        fprintf(output, " 'descendant' "); break;
1371
    case AXIS_DESCENDANT_OR_SELF:
1372
        fprintf(output, " 'descendant-or-self' "); break;
1373
    case AXIS_FOLLOWING:
1374
        fprintf(output, " 'following' "); break;
1375
    case AXIS_FOLLOWING_SIBLING:
1376
        fprintf(output, " 'following-siblings' "); break;
1377
    case AXIS_NAMESPACE:
1378
        fprintf(output, " 'namespace' "); break;
1379
    case AXIS_PARENT:
1380
        fprintf(output, " 'parent' "); break;
1381
    case AXIS_PRECEDING:
1382
        fprintf(output, " 'preceding' "); break;
1383
    case AXIS_PRECEDING_SIBLING:
1384
        fprintf(output, " 'preceding-sibling' "); break;
1385
    case AXIS_SELF:
1386
        fprintf(output, " 'self' "); break;
1387
      }
1388
      switch (test) {
1389
                case NODE_TEST_NONE:
1390
        fprintf(output, "'none' "); break;
1391
                case NODE_TEST_TYPE:
1392
        fprintf(output, "'type' "); break;
1393
                case NODE_TEST_PI:
1394
        fprintf(output, "'PI' "); break;
1395
                case NODE_TEST_ALL:
1396
        fprintf(output, "'all' "); break;
1397
                case NODE_TEST_NS:
1398
        fprintf(output, "'namespace' "); break;
1399
                case NODE_TEST_NAME:
1400
        fprintf(output, "'name' "); break;
1401
      }
1402
      switch (type) {
1403
                case NODE_TYPE_NODE:
1404
        fprintf(output, "'node' "); break;
1405
                case NODE_TYPE_COMMENT:
1406
        fprintf(output, "'comment' "); break;
1407
                case NODE_TYPE_TEXT:
1408
        fprintf(output, "'text' "); break;
1409
                case NODE_TYPE_PI:
1410
        fprintf(output, "'PI' "); break;
1411
      }
1412
      if (prefix != NULL)
1413
    fprintf(output, "%s:", prefix);
1414
      if (name != NULL)
1415
    fprintf(output, "%s", (const char *) name);
1416
      break;
1417
1418
        }
1419
  case XPATH_OP_VALUE: {
1420
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1421
1422
      fprintf(output, "ELEM ");
1423
      xmlXPathDebugDumpObject(output, object, 0);
1424
      goto finish;
1425
  }
1426
  case XPATH_OP_VARIABLE: {
1427
      const xmlChar *prefix = op->value5;
1428
      const xmlChar *name = op->value4;
1429
1430
      if (prefix != NULL)
1431
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1432
      else
1433
    fprintf(output, "VARIABLE %s", name);
1434
      break;
1435
  }
1436
  case XPATH_OP_FUNCTION: {
1437
      int nbargs = op->value;
1438
      const xmlChar *prefix = op->value5;
1439
      const xmlChar *name = op->value4;
1440
1441
      if (prefix != NULL)
1442
    fprintf(output, "FUNCTION %s:%s(%d args)",
1443
      prefix, name, nbargs);
1444
      else
1445
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1446
      break;
1447
  }
1448
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1449
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1450
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1451
  default:
1452
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1453
    }
1454
    fprintf(output, "\n");
1455
finish:
1456
    /* OP_VALUE has invalid ch1. */
1457
    if (op->op == XPATH_OP_VALUE)
1458
        return;
1459
1460
    if (op->ch1 >= 0)
1461
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1462
    if (op->ch2 >= 0)
1463
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1464
}
1465
1466
/**
1467
 * Dumps the tree of the compiled XPath expression.
1468
 *
1469
 * @param output  the FILE * for the output
1470
 * @param comp  the precompiled XPath expression
1471
 * @param depth  the indentation level.
1472
 */
1473
void
1474
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExpr *comp,
1475
                    int depth) {
1476
    int i;
1477
    char shift[100];
1478
1479
    if ((output == NULL) || (comp == NULL)) return;
1480
1481
    for (i = 0;((i < depth) && (i < 25));i++)
1482
        shift[2 * i] = shift[2 * i + 1] = ' ';
1483
    shift[2 * i] = shift[2 * i + 1] = 0;
1484
1485
    fprintf(output, "%s", shift);
1486
1487
#ifdef XPATH_STREAMING
1488
    if (comp->stream) {
1489
        fprintf(output, "Streaming Expression\n");
1490
    } else
1491
#endif
1492
    {
1493
        fprintf(output, "Compiled Expression : %d elements\n",
1494
                comp->nbStep);
1495
        i = comp->last;
1496
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1497
    }
1498
}
1499
1500
#endif /* LIBXML_DEBUG_ENABLED */
1501
1502
/************************************************************************
1503
 *                  *
1504
 *      XPath object caching        *
1505
 *                  *
1506
 ************************************************************************/
1507
1508
/**
1509
 * Create a new object cache
1510
 *
1511
 * @returns the xmlXPathCache just allocated.
1512
 */
1513
static xmlXPathContextCachePtr
1514
xmlXPathNewCache(void)
1515
26.0k
{
1516
26.0k
    xmlXPathContextCachePtr ret;
1517
1518
26.0k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
26.0k
    if (ret == NULL)
1520
689
  return(NULL);
1521
25.3k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
25.3k
    ret->maxNodeset = 100;
1523
25.3k
    ret->maxMisc = 100;
1524
25.3k
    return(ret);
1525
26.0k
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
12.6k
{
1530
45.7k
    while (list != NULL) {
1531
33.0k
        xmlXPathObjectPtr next;
1532
1533
33.0k
        next = (void *) list->stringval;
1534
1535
33.0k
  if (list->nodesetval != NULL) {
1536
23.1k
      if (list->nodesetval->nodeTab != NULL)
1537
20.4k
    xmlFree(list->nodesetval->nodeTab);
1538
23.1k
      xmlFree(list->nodesetval);
1539
23.1k
  }
1540
33.0k
  xmlFree(list);
1541
1542
33.0k
        list = next;
1543
33.0k
    }
1544
12.6k
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
25.3k
{
1549
25.3k
    if (cache == NULL)
1550
0
  return;
1551
25.3k
    if (cache->nodesetObjs)
1552
7.88k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
25.3k
    if (cache->miscObjs)
1554
4.80k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
25.3k
    xmlFree(cache);
1556
25.3k
}
1557
1558
/**
1559
 * Creates/frees an object cache on the XPath context.
1560
 * If activates XPath objects (xmlXPathObject) will be cached internally
1561
 * to be reused.
1562
 *
1563
 * `options` must be set to 0 to enable XPath object caching.
1564
 * Other values for `options` have currently no effect.
1565
 *
1566
 * `value` sets the maximum number of XPath objects to be cached per slot.
1567
 * There are two slots for node-set and misc objects.
1568
 * Use <0 for the default number (100).
1569
 *
1570
 * @param ctxt  the XPath context
1571
 * @param active  enables/disables (creates/frees) the cache
1572
 * @param value  a value with semantics dependent on `options`
1573
 * @param options  options (currently only the value 0 is used)
1574
 * @returns 0 if the setting succeeded, and -1 on API or internal errors.
1575
 */
1576
int
1577
xmlXPathContextSetCache(xmlXPathContext *ctxt,
1578
      int active,
1579
      int value,
1580
      int options)
1581
26.0k
{
1582
26.0k
    if (ctxt == NULL)
1583
0
  return(-1);
1584
26.0k
    if (active) {
1585
26.0k
  xmlXPathContextCachePtr cache;
1586
1587
26.0k
  if (ctxt->cache == NULL) {
1588
26.0k
      ctxt->cache = xmlXPathNewCache();
1589
26.0k
      if (ctxt->cache == NULL) {
1590
689
                xmlXPathErrMemory(ctxt);
1591
689
    return(-1);
1592
689
            }
1593
26.0k
  }
1594
25.3k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
25.3k
  if (options == 0) {
1596
25.3k
      if (value < 0)
1597
0
    value = 100;
1598
25.3k
      cache->maxNodeset = value;
1599
25.3k
      cache->maxMisc = value;
1600
25.3k
  }
1601
25.3k
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
25.3k
    return(0);
1606
26.0k
}
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
3.12M
{
1621
3.12M
    xmlXPathObjectPtr ret;
1622
3.12M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
3.12M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
462k
  xmlXPathContextCachePtr cache =
1626
462k
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
462k
  if (cache->miscObjs != NULL) {
1629
420k
      ret = cache->miscObjs;
1630
420k
            cache->miscObjs = (void *) ret->stringval;
1631
420k
            cache->numMisc -= 1;
1632
420k
            ret->stringval = NULL;
1633
420k
      ret->type = XPATH_NODESET;
1634
420k
      ret->nodesetval = val;
1635
420k
      return(ret);
1636
420k
  }
1637
462k
    }
1638
1639
2.70M
    ret = xmlXPathWrapNodeSet(val);
1640
2.70M
    if (ret == NULL)
1641
361
        xmlXPathPErrMemory(pctxt);
1642
2.70M
    return(ret);
1643
3.12M
}
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
227k
{
1656
227k
    xmlXPathObjectPtr ret;
1657
227k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
227k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
32.9k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
32.9k
  if (cache->miscObjs != NULL) {
1663
29.0k
      ret = cache->miscObjs;
1664
29.0k
            cache->miscObjs = (void *) ret->stringval;
1665
29.0k
            cache->numMisc -= 1;
1666
29.0k
      ret->type = XPATH_STRING;
1667
29.0k
      ret->stringval = val;
1668
29.0k
      return(ret);
1669
29.0k
  }
1670
32.9k
    }
1671
1672
198k
    ret = xmlXPathWrapString(val);
1673
198k
    if (ret == NULL)
1674
107
        xmlXPathPErrMemory(pctxt);
1675
198k
    return(ret);
1676
227k
}
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
5.70M
{
1690
5.70M
    xmlXPathObjectPtr ret;
1691
5.70M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
5.70M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
2.23M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
2.23M
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
2.22M
      ret = cache->nodesetObjs;
1701
2.22M
            cache->nodesetObjs = (void *) ret->stringval;
1702
2.22M
            cache->numNodeset -= 1;
1703
2.22M
            ret->stringval = NULL;
1704
2.22M
      ret->type = XPATH_NODESET;
1705
2.22M
      ret->boolval = 0;
1706
2.22M
      if (val) {
1707
2.22M
    if ((ret->nodesetval->nodeMax == 0) ||
1708
2.20M
        (val->type == XML_NAMESPACE_DECL))
1709
378k
    {
1710
378k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
15
                        xmlXPathPErrMemory(pctxt);
1712
1.84M
    } else {
1713
1.84M
        ret->nodesetval->nodeTab[0] = val;
1714
1.84M
        ret->nodesetval->nodeNr = 1;
1715
1.84M
    }
1716
2.22M
      }
1717
2.22M
      return(ret);
1718
2.22M
  } else if (cache->miscObjs != NULL) {
1719
3.60k
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
3.60k
      set = xmlXPathNodeSetCreate(val);
1725
3.60k
      if (set == NULL) {
1726
1
                xmlXPathPErrMemory(pctxt);
1727
1
    return(NULL);
1728
1
      }
1729
1730
3.60k
      ret = cache->miscObjs;
1731
3.60k
            cache->miscObjs = (void *) ret->stringval;
1732
3.60k
            cache->numMisc -= 1;
1733
3.60k
            ret->stringval = NULL;
1734
3.60k
      ret->type = XPATH_NODESET;
1735
3.60k
      ret->boolval = 0;
1736
3.60k
      ret->nodesetval = set;
1737
3.60k
      return(ret);
1738
3.60k
  }
1739
2.23M
    }
1740
3.47M
    ret = xmlXPathNewNodeSet(val);
1741
3.47M
    if (ret == NULL)
1742
810
        xmlXPathPErrMemory(pctxt);
1743
3.47M
    return(ret);
1744
5.70M
}
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
1.08M
{
1757
1.08M
    xmlXPathObjectPtr ret;
1758
1.08M
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
1.08M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
456k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
456k
  if (cache->miscObjs != NULL) {
1764
451k
            xmlChar *copy;
1765
1766
451k
            if (val == NULL)
1767
246
                val = BAD_CAST "";
1768
451k
            copy = xmlStrdup(val);
1769
451k
            if (copy == NULL) {
1770
14
                xmlXPathPErrMemory(pctxt);
1771
14
                return(NULL);
1772
14
            }
1773
1774
451k
      ret = cache->miscObjs;
1775
451k
            cache->miscObjs = (void *) ret->stringval;
1776
451k
            cache->numMisc -= 1;
1777
451k
      ret->type = XPATH_STRING;
1778
451k
            ret->stringval = copy;
1779
451k
      return(ret);
1780
451k
  }
1781
456k
    }
1782
1783
636k
    ret = xmlXPathNewString(val);
1784
636k
    if (ret == NULL)
1785
60
        xmlXPathPErrMemory(pctxt);
1786
636k
    return(ret);
1787
1.08M
}
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
20.7k
{
1800
20.7k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
20.7k
}
1802
1803
/**
1804
 * This is the cached version of #xmlXPathNewBoolean.
1805
 * Acquires an xmlXPathObject of type boolean and of value `val`
1806
 *
1807
 * @param pctxt  the XPath context
1808
 * @param val  the boolean value
1809
 * @returns the created or reused object.
1810
 */
1811
static xmlXPathObjectPtr
1812
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1813
1.14M
{
1814
1.14M
    xmlXPathObjectPtr ret;
1815
1.14M
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
1.14M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
148k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
148k
  if (cache->miscObjs != NULL) {
1821
139k
      ret = cache->miscObjs;
1822
139k
            cache->miscObjs = (void *) ret->stringval;
1823
139k
            cache->numMisc -= 1;
1824
139k
            ret->stringval = NULL;
1825
139k
      ret->type = XPATH_BOOLEAN;
1826
139k
      ret->boolval = (val != 0);
1827
139k
      return(ret);
1828
139k
  }
1829
148k
    }
1830
1831
1.01M
    ret = xmlXPathNewBoolean(val);
1832
1.01M
    if (ret == NULL)
1833
172
        xmlXPathPErrMemory(pctxt);
1834
1.01M
    return(ret);
1835
1.14M
}
1836
1837
/**
1838
 * This is the cached version of #xmlXPathNewFloat.
1839
 * Acquires an xmlXPathObject of type double and of value `val`
1840
 *
1841
 * @param pctxt  the XPath context
1842
 * @param val  the double value
1843
 * @returns the created or reused object.
1844
 */
1845
static xmlXPathObjectPtr
1846
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1847
2.49M
{
1848
2.49M
    xmlXPathObjectPtr ret;
1849
2.49M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
2.49M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
1.16M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
1.16M
  if (cache->miscObjs != NULL) {
1855
1.13M
      ret = cache->miscObjs;
1856
1.13M
            cache->miscObjs = (void *) ret->stringval;
1857
1.13M
            cache->numMisc -= 1;
1858
1.13M
            ret->stringval = NULL;
1859
1.13M
      ret->type = XPATH_NUMBER;
1860
1.13M
      ret->floatval = val;
1861
1.13M
      return(ret);
1862
1.13M
  }
1863
1.16M
    }
1864
1865
1.35M
    ret = xmlXPathNewFloat(val);
1866
1.35M
    if (ret == NULL)
1867
274
        xmlXPathPErrMemory(pctxt);
1868
1.35M
    return(ret);
1869
2.49M
}
1870
1871
/**
1872
 * This is the cached version of #xmlXPathObjectCopy.
1873
 * Acquire a copy of a given object
1874
 *
1875
 * @param pctxt  the XPath context
1876
 * @param val  the original object
1877
 * @returns a created or reused created object.
1878
 */
1879
static xmlXPathObjectPtr
1880
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1881
1.25M
{
1882
1.25M
    xmlXPathObjectPtr ret;
1883
1.25M
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
1.25M
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
1.25M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
163k
  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
12.2k
      case XPATH_STRING:
1901
12.2k
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
151k
      case XPATH_NUMBER:
1905
151k
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
163k
  }
1909
163k
    }
1910
1.09M
    ret = xmlXPathObjectCopy(val);
1911
1.09M
    if (ret == NULL)
1912
172
        xmlXPathPErrMemory(pctxt);
1913
1.09M
    return(ret);
1914
1.25M
}
1915
1916
/************************************************************************
1917
 *                  *
1918
 *    Parser stacks related functions and macros    *
1919
 *                  *
1920
 ************************************************************************/
1921
1922
/**
1923
 * Converts an XPath object to its number value
1924
 *
1925
 * @param ctxt  parser context
1926
 * @param val  an XPath object
1927
 * @returns the number value
1928
 */
1929
static double
1930
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1931
2.57M
                             xmlXPathObjectPtr val) {
1932
2.57M
    double ret = 0.0;
1933
1934
2.57M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
2.57M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
1.27M
    case XPATH_NODESET:
1941
1.27M
    case XPATH_XSLT_TREE: {
1942
1.27M
        xmlChar *str;
1943
1944
1.27M
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
1.27M
        if (str == NULL) {
1946
157
            xmlXPathPErrMemory(ctxt);
1947
157
            ret = xmlXPathNAN;
1948
1.27M
        } else {
1949
1.27M
      ret = xmlXPathCastStringToNumber(str);
1950
1.27M
            xmlFree(str);
1951
1.27M
        }
1952
1.27M
  break;
1953
1.27M
    }
1954
1.08M
    case XPATH_STRING:
1955
1.08M
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
1.08M
  break;
1957
152k
    case XPATH_NUMBER:
1958
152k
  ret = val->floatval;
1959
152k
  break;
1960
60.3k
    case XPATH_BOOLEAN:
1961
60.3k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
60.3k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
2.57M
    }
1968
2.57M
    return(ret);
1969
2.57M
}
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
15.7M
{
1980
15.7M
    xmlXPathObjectPtr ret;
1981
1982
15.7M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
47.1k
        return (NULL);
1984
1985
15.7M
    ctxt->valueNr--;
1986
15.7M
    if (ctxt->valueNr > 0)
1987
8.80M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
6.92M
    else
1989
6.92M
        ctxt->value = NULL;
1990
15.7M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
15.7M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
15.7M
    return (ret);
1993
15.7M
}
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
15.8M
{
2008
15.8M
    if (ctxt == NULL) return(-1);
2009
15.8M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
1.96k
        xmlXPathPErrMemory(ctxt);
2014
1.96k
        return(-1);
2015
1.96k
    }
2016
15.8M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
6.70k
        xmlXPathObjectPtr *tmp;
2018
6.70k
        int newSize;
2019
2020
6.70k
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
6.70k
                                  10, XPATH_MAX_STACK_DEPTH);
2022
6.70k
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
6.70k
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
6.70k
        if (tmp == NULL) {
2029
6
            xmlXPathPErrMemory(ctxt);
2030
6
            xmlXPathFreeObject(value);
2031
6
            return (-1);
2032
6
        }
2033
6.69k
  ctxt->valueTab = tmp;
2034
6.69k
        ctxt->valueMax = newSize;
2035
6.69k
    }
2036
15.8M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
15.8M
    ctxt->value = value;
2038
15.8M
    return (ctxt->valueNr++);
2039
15.8M
}
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
314M
#define CUR (*ctxt->cur)
2194
119k
#define SKIP(val) ctxt->cur += (val)
2195
15.9M
#define NXT(val) ctxt->cur[(val)]
2196
18.7M
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
145M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
79.7M
#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
32.7k
#define UPPER_DOUBLE 1E9
2213
8.86k
#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
25.4k
#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
53.0k
{
2230
53.0k
    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
53.0k
    default:
2240
53.0k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
53.0k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
53.0k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
29.3k
                   (number == (int) number)) {
2248
20.2k
      char work[30];
2249
20.2k
      char *ptr, *cur;
2250
20.2k
      int value = (int) number;
2251
2252
20.2k
            ptr = &buffer[0];
2253
20.2k
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
20.2k
      } else {
2256
20.2k
    snprintf(work, 29, "%d", value);
2257
20.2k
    cur = &work[0];
2258
67.6k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
47.3k
        *ptr++ = *cur++;
2260
47.3k
    }
2261
20.2k
      }
2262
20.2k
      if (ptr - buffer < buffersize) {
2263
20.2k
    *ptr = 0;
2264
20.2k
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
32.7k
  } 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
32.7k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
32.7k
      int integer_place, fraction_place;
2280
32.7k
      char *ptr;
2281
32.7k
      char *after_fraction;
2282
32.7k
      double absolute_value;
2283
32.7k
      int size;
2284
2285
32.7k
      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
32.7k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
8.86k
      (absolute_value < LOWER_DOUBLE)) &&
2294
25.4k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
25.4k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
25.4k
    fraction_place = DBL_DIG - 1;
2298
25.4k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
25.4k
       integer_place, fraction_place, number);
2300
130k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
25.4k
      }
2303
7.31k
      else {
2304
    /* Use regular notation */
2305
7.31k
    if (absolute_value > 0.0) {
2306
7.31k
        integer_place = (int)log10(absolute_value);
2307
7.31k
        if (integer_place > 0)
2308
1.63k
            fraction_place = DBL_DIG - integer_place - 1;
2309
5.68k
        else
2310
5.68k
            fraction_place = DBL_DIG - integer_place;
2311
7.31k
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
7.31k
    size = snprintf(work, sizeof(work), "%0.*f",
2315
7.31k
        fraction_place, number);
2316
7.31k
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
49.8k
      while (work[0] == ' ') {
2320
358k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
17.0k
    size--;
2322
17.0k
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
32.7k
      after_fraction = work + size;
2326
32.7k
      ptr = after_fraction;
2327
327k
      while (*(--ptr) == '0')
2328
294k
    ;
2329
32.7k
      if (*ptr != '.')
2330
19.0k
          ptr++;
2331
138k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
32.7k
      size = strlen(work) + 1;
2335
32.7k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
32.7k
      memmove(buffer, work, size);
2340
32.7k
  }
2341
53.0k
  break;
2342
53.0k
    }
2343
53.0k
}
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
5.99k
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
5.99k
    XML_INTPTR_T count = 0;
2366
5.99k
    xmlNodePtr cur;
2367
2368
5.99k
    if (doc == NULL)
2369
0
  return(-1);
2370
5.99k
    cur = doc->children;
2371
61.7k
    while (cur != NULL) {
2372
55.7k
  if (cur->type == XML_ELEMENT_NODE) {
2373
11.6k
            count += 1;
2374
11.6k
            cur->content = XML_INT_TO_PTR(-count);
2375
11.6k
      if (cur->children != NULL) {
2376
8.81k
    cur = cur->children;
2377
8.81k
    continue;
2378
8.81k
      }
2379
11.6k
  }
2380
46.9k
  if (cur->next != NULL) {
2381
40.8k
      cur = cur->next;
2382
40.8k
      continue;
2383
40.8k
  }
2384
14.7k
  do {
2385
14.7k
      cur = cur->parent;
2386
14.7k
      if (cur == NULL)
2387
0
    break;
2388
14.7k
      if (cur == (xmlNodePtr) doc) {
2389
5.97k
    cur = NULL;
2390
5.97k
    break;
2391
5.97k
      }
2392
8.81k
      if (cur->next != NULL) {
2393
91
    cur = cur->next;
2394
91
    break;
2395
91
      }
2396
8.81k
  } while (cur != NULL);
2397
6.06k
    }
2398
5.99k
    return(count);
2399
5.99k
}
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
346k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
346k
    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
346k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
346k
#endif /* WITH_TIM_SORT */
2591
346k
}
2592
2593
17.6M
#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
4.21M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
4.21M
    xmlNsPtr cur;
2606
2607
4.21M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
4.21M
    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
4.21M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
4.21M
    if (cur == NULL)
2617
62
  return(NULL);
2618
4.21M
    memset(cur, 0, sizeof(xmlNs));
2619
4.21M
    cur->type = XML_NAMESPACE_DECL;
2620
4.21M
    if (ns->href != NULL) {
2621
4.17M
  cur->href = xmlStrdup(ns->href);
2622
4.17M
        if (cur->href == NULL) {
2623
60
            xmlFree(cur);
2624
60
            return(NULL);
2625
60
        }
2626
4.17M
    }
2627
4.21M
    if (ns->prefix != NULL) {
2628
3.64M
  cur->prefix = xmlStrdup(ns->prefix);
2629
3.64M
        if (cur->prefix == NULL) {
2630
65
            xmlFree((xmlChar *) cur->href);
2631
65
            xmlFree(cur);
2632
65
            return(NULL);
2633
65
        }
2634
3.64M
    }
2635
4.21M
    cur->next = (xmlNsPtr) node;
2636
4.21M
    return((xmlNodePtr) cur);
2637
4.21M
}
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
4.21M
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
4.21M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
4.21M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
4.21M
  if (ns->href != NULL)
2653
4.17M
      xmlFree((xmlChar *)ns->href);
2654
4.21M
  if (ns->prefix != NULL)
2655
3.64M
      xmlFree((xmlChar *)ns->prefix);
2656
4.21M
  xmlFree(ns);
2657
4.21M
    }
2658
4.21M
}
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
8.04M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
8.04M
    xmlNodeSetPtr ret;
2669
2670
8.04M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
8.04M
    if (ret == NULL)
2672
619
  return(NULL);
2673
8.04M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
8.04M
    if (val != NULL) {
2675
3.47M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
3.47M
               sizeof(xmlNodePtr));
2677
3.47M
  if (ret->nodeTab == NULL) {
2678
268
      xmlFree(ret);
2679
268
      return(NULL);
2680
268
  }
2681
3.47M
  memset(ret->nodeTab, 0 ,
2682
3.47M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
3.47M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
3.47M
  if (val->type == XML_NAMESPACE_DECL) {
2685
451k
      xmlNsPtr ns = (xmlNsPtr) val;
2686
451k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
451k
            if (nsNode == NULL) {
2689
19
                xmlXPathFreeNodeSet(ret);
2690
19
                return(NULL);
2691
19
            }
2692
451k
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
451k
  } else
2694
3.02M
      ret->nodeTab[ret->nodeNr++] = val;
2695
3.47M
    }
2696
8.04M
    return(ret);
2697
8.04M
}
2698
2699
/**
2700
 * checks whether `cur` contains `val`
2701
 *
2702
 * @param cur  the node-set
2703
 * @param val  the node
2704
 * @returns true (1) if `cur` contains `val`, false (0) otherwise
2705
 */
2706
int
2707
0
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
0
    int i;
2709
2710
0
    if ((cur == NULL) || (val == NULL)) return(0);
2711
0
    if (val->type == XML_NAMESPACE_DECL) {
2712
0
  for (i = 0; i < cur->nodeNr; i++) {
2713
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2714
0
    xmlNsPtr ns1, ns2;
2715
2716
0
    ns1 = (xmlNsPtr) val;
2717
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2718
0
    if (ns1 == ns2)
2719
0
        return(1);
2720
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2721
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2722
0
        return(1);
2723
0
      }
2724
0
  }
2725
0
    } else {
2726
0
  for (i = 0; i < cur->nodeNr; i++) {
2727
0
      if (cur->nodeTab[i] == val)
2728
0
    return(1);
2729
0
  }
2730
0
    }
2731
0
    return(0);
2732
0
}
2733
2734
static int
2735
6.35M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
6.35M
    xmlNodePtr *temp;
2737
6.35M
    int newSize;
2738
2739
6.35M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
6.35M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
6.35M
    if (newSize < 0)
2742
0
        return(-1);
2743
6.35M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
6.35M
    if (temp == NULL)
2745
809
        return(-1);
2746
6.35M
    cur->nodeMax = newSize;
2747
6.35M
    cur->nodeTab = temp;
2748
2749
6.35M
    return(0);
2750
6.35M
}
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
3.16M
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
3.16M
    int i;
2763
3.16M
    xmlNodePtr nsNode;
2764
2765
3.16M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
3.16M
        (ns->type != XML_NAMESPACE_DECL) ||
2767
3.16M
  (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
13.7M
    for (i = 0;i < cur->nodeNr;i++) {
2775
10.5M
        if ((cur->nodeTab[i] != NULL) &&
2776
10.5M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
10.5M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
10.5M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
10.5M
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
3.16M
    if (cur->nodeNr >= cur->nodeMax) {
2786
50.7k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
22
            return(-1);
2788
50.7k
    }
2789
3.16M
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
3.16M
    if(nsNode == NULL)
2791
78
        return(-1);
2792
3.16M
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
3.16M
    return(0);
2794
3.16M
}
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
22.0k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
22.0k
    int i;
2806
2807
22.0k
    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
36.4k
    for (i = 0;i < cur->nodeNr;i++)
2814
27.0k
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
9.32k
    if (cur->nodeNr >= cur->nodeMax) {
2820
8.80k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
12
            return(-1);
2822
8.80k
    }
2823
2824
9.31k
    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
9.31k
  cur->nodeTab[cur->nodeNr++] = val;
2833
9.31k
    return(0);
2834
9.31k
}
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
60.9M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
60.9M
    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
60.9M
    if (cur->nodeNr >= cur->nodeMax) {
2853
4.97M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
416
            return(-1);
2855
4.97M
    }
2856
2857
60.9M
    if (val->type == XML_NAMESPACE_DECL) {
2858
400k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
400k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
400k
        if (nsNode == NULL)
2862
34
            return(-1);
2863
400k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
400k
    } else
2865
60.5M
  cur->nodeTab[cur->nodeNr++] = val;
2866
60.9M
    return(0);
2867
60.9M
}
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
1.68M
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
1.68M
    int i, j, initNr, skip;
2882
1.68M
    xmlNodePtr n1, n2;
2883
2884
1.68M
    if (val1 == NULL) {
2885
12
  val1 = xmlXPathNodeSetCreate(NULL);
2886
12
        if (val1 == NULL)
2887
0
            return (NULL);
2888
12
    }
2889
1.68M
    if (val2 == NULL)
2890
90
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
1.68M
    initNr = val1->nodeNr;
2894
2895
9.15M
    for (i = 0;i < val2->nodeNr;i++) {
2896
7.46M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
7.46M
  skip = 0;
2901
1.12G
  for (j = 0; j < initNr; j++) {
2902
1.11G
      n1 = val1->nodeTab[j];
2903
1.11G
      if (n1 == n2) {
2904
348k
    skip = 1;
2905
348k
    break;
2906
1.11G
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
1.07G
           (n2->type == XML_NAMESPACE_DECL)) {
2908
56.9k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
4.26k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
4.26k
      ((xmlNsPtr) n2)->prefix)))
2911
2.83k
    {
2912
2.83k
        skip = 1;
2913
2.83k
        break;
2914
2.83k
    }
2915
56.9k
      }
2916
1.11G
  }
2917
7.46M
  if (skip)
2918
351k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
7.11M
        if (val1->nodeNr >= val1->nodeMax) {
2924
877k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
72
                goto error;
2926
877k
        }
2927
7.11M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
195k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
195k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
195k
            if (nsNode == NULL)
2932
56
                goto error;
2933
195k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
195k
  } else
2935
6.91M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
7.11M
    }
2937
2938
1.68M
    return(val1);
2939
2940
128
error:
2941
128
    xmlXPathFreeNodeSet(val1);
2942
128
    return(NULL);
2943
1.68M
}
2944
2945
2946
/**
2947
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
2948
 * Checks for duplicate nodes. Clears set2.
2949
 *
2950
 * Frees `set1` in case of error.
2951
 *
2952
 * @param set1  the first NodeSet or NULL
2953
 * @param set2  the second NodeSet
2954
 * @returns `set1` once extended or NULL in case of error.
2955
 */
2956
static xmlNodeSetPtr
2957
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2958
1.95M
{
2959
1.95M
    {
2960
1.95M
  int i, j, initNbSet1;
2961
1.95M
  xmlNodePtr n1, n2;
2962
2963
1.95M
  initNbSet1 = set1->nodeNr;
2964
34.3M
  for (i = 0;i < set2->nodeNr;i++) {
2965
32.3M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
9.82G
      for (j = 0; j < initNbSet1; j++) {
2970
9.81G
    n1 = set1->nodeTab[j];
2971
9.81G
    if (n1 == n2) {
2972
28.9M
        goto skip_node;
2973
9.78G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
46.7M
        (n2->type == XML_NAMESPACE_DECL))
2975
46.7M
    {
2976
46.7M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
70.5k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
70.5k
      ((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
46.7M
    }
2987
9.81G
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
3.45M
            if (set1->nodeNr >= set1->nodeMax) {
2992
214k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
116
                    goto error;
2994
214k
            }
2995
3.45M
      set1->nodeTab[set1->nodeNr++] = n2;
2996
32.3M
skip_node:
2997
32.3M
            set2->nodeTab[i] = NULL;
2998
32.3M
  }
2999
1.95M
    }
3000
1.95M
    set2->nodeNr = 0;
3001
1.95M
    return(set1);
3002
3003
116
error:
3004
116
    xmlXPathFreeNodeSet(set1);
3005
116
    xmlXPathNodeSetClear(set2, 1);
3006
116
    return(NULL);
3007
1.95M
}
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
850k
{
3022
850k
    {
3023
850k
  int i;
3024
850k
  xmlNodePtr n2;
3025
3026
5.44M
  for (i = 0;i < set2->nodeNr;i++) {
3027
4.59M
      n2 = set2->nodeTab[i];
3028
4.59M
            if (set1->nodeNr >= set1->nodeMax) {
3029
224k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
171
                    goto error;
3031
224k
            }
3032
4.59M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
4.59M
            set2->nodeTab[i] = NULL;
3034
4.59M
  }
3035
850k
    }
3036
850k
    set2->nodeNr = 0;
3037
850k
    return(set1);
3038
3039
171
error:
3040
171
    xmlXPathFreeNodeSet(set1);
3041
171
    xmlXPathNodeSetClear(set2, 1);
3042
171
    return(NULL);
3043
850k
}
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
8.01M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
8.01M
    if (obj == NULL) return;
3103
8.01M
    if (obj->nodeTab != NULL) {
3104
4.87M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
46.6M
  for (i = 0;i < obj->nodeNr;i++)
3108
41.7M
      if ((obj->nodeTab[i] != NULL) &&
3109
41.7M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
2.52M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
4.87M
  xmlFree(obj->nodeTab);
3112
4.87M
    }
3113
8.01M
    xmlFree(obj);
3114
8.01M
}
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
26.1k
{
3128
26.1k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
26.1k
    else if ((hasNsNodes)) {
3131
20.5k
  int i;
3132
20.5k
  xmlNodePtr node;
3133
3134
1.17M
  for (i = pos; i < set->nodeNr; i++) {
3135
1.15M
      node = set->nodeTab[i];
3136
1.15M
      if ((node != NULL) &&
3137
1.15M
    (node->type == XML_NAMESPACE_DECL))
3138
420k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
1.15M
  }
3140
20.5k
    }
3141
26.1k
    set->nodeNr = pos;
3142
26.1k
}
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
7.03k
{
3155
7.03k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
7.03k
}
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
16.6k
{
3168
16.6k
    int i;
3169
16.6k
    xmlNodePtr node;
3170
3171
16.6k
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
355k
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
338k
        node = set->nodeTab[i];
3175
338k
        if ((node != NULL) &&
3176
338k
            (node->type == XML_NAMESPACE_DECL))
3177
74.2k
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
338k
    }
3179
16.6k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
16.6k
    set->nodeNr = 1;
3181
16.6k
}
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
3.48M
xmlXPathNewNodeSet(xmlNode *val) {
3192
3.48M
    xmlXPathObjectPtr ret;
3193
3194
3.48M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
3.48M
    if (ret == NULL)
3196
274
  return(NULL);
3197
3.48M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
3.48M
    ret->type = XPATH_NODESET;
3199
3.48M
    ret->boolval = 0;
3200
3.48M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
3.48M
    if (ret->nodesetval == NULL) {
3202
561
        xmlFree(ret);
3203
561
        return(NULL);
3204
561
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
3.47M
    return(ret);
3207
3.48M
}
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
2.70M
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
2.70M
    xmlXPathObjectPtr ret;
3269
3270
2.70M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
2.70M
    if (ret == NULL) {
3272
361
        xmlXPathFreeNodeSet(val);
3273
361
  return(NULL);
3274
361
    }
3275
2.70M
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
2.70M
    ret->type = XPATH_NODESET;
3277
2.70M
    ret->nodesetval = val;
3278
2.70M
    return(ret);
3279
2.70M
}
3280
3281
/**
3282
 * Free up the xmlXPathObject `obj` but don't deallocate the objects in
3283
 * the list contrary to #xmlXPathFreeObject.
3284
 *
3285
 * @param obj  an existing NodeSetList object
3286
 */
3287
void
3288
0
xmlXPathFreeNodeSetList(xmlXPathObject *obj) {
3289
0
    if (obj == NULL) return;
3290
0
    xmlFree(obj);
3291
0
}
3292
3293
/**
3294
 * Implements the EXSLT - Sets difference() function:
3295
 *    node-set set:difference (node-set, node-set)
3296
 *
3297
 * @param nodes1  a node-set
3298
 * @param nodes2  a node-set
3299
 * @returns the difference between the two node sets, or nodes1 if
3300
 *         nodes2 is empty
3301
 */
3302
xmlNodeSet *
3303
0
xmlXPathDifference (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3304
0
    xmlNodeSetPtr ret;
3305
0
    int i, l1;
3306
0
    xmlNodePtr cur;
3307
3308
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3309
0
  return(nodes1);
3310
3311
0
    ret = xmlXPathNodeSetCreate(NULL);
3312
0
    if (ret == NULL)
3313
0
        return(NULL);
3314
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3315
0
  return(ret);
3316
3317
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3318
3319
0
    for (i = 0; i < l1; i++) {
3320
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3321
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3322
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3323
0
                xmlXPathFreeNodeSet(ret);
3324
0
          return(NULL);
3325
0
            }
3326
0
  }
3327
0
    }
3328
0
    return(ret);
3329
0
}
3330
3331
/**
3332
 * Implements the EXSLT - Sets intersection() function:
3333
 *    node-set set:intersection (node-set, node-set)
3334
 *
3335
 * @param nodes1  a node-set
3336
 * @param nodes2  a node-set
3337
 * @returns a node set comprising the nodes that are within both the
3338
 *         node sets passed as arguments
3339
 */
3340
xmlNodeSet *
3341
0
xmlXPathIntersection (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3342
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3343
0
    int i, l1;
3344
0
    xmlNodePtr cur;
3345
3346
0
    if (ret == NULL)
3347
0
        return(ret);
3348
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3349
0
  return(ret);
3350
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3351
0
  return(ret);
3352
3353
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3354
3355
0
    for (i = 0; i < l1; i++) {
3356
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3357
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3358
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3359
0
                xmlXPathFreeNodeSet(ret);
3360
0
          return(NULL);
3361
0
            }
3362
0
  }
3363
0
    }
3364
0
    return(ret);
3365
0
}
3366
3367
/**
3368
 * Implements the EXSLT - Sets distinct() function:
3369
 *    node-set set:distinct (node-set)
3370
 *
3371
 * @param nodes  a node-set, sorted by document order
3372
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3373
 *         it is empty
3374
 */
3375
xmlNodeSet *
3376
0
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3377
0
    xmlNodeSetPtr ret;
3378
0
    xmlHashTablePtr hash;
3379
0
    int i, l;
3380
0
    xmlChar * strval;
3381
0
    xmlNodePtr cur;
3382
3383
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3384
0
  return(nodes);
3385
3386
0
    ret = xmlXPathNodeSetCreate(NULL);
3387
0
    if (ret == NULL)
3388
0
        return(ret);
3389
0
    l = xmlXPathNodeSetGetLength(nodes);
3390
0
    hash = xmlHashCreate (l);
3391
0
    for (i = 0; i < l; i++) {
3392
0
  cur = xmlXPathNodeSetItem(nodes, i);
3393
0
  strval = xmlXPathCastNodeToString(cur);
3394
0
  if (xmlHashLookup(hash, strval) == NULL) {
3395
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3396
0
                xmlFree(strval);
3397
0
                goto error;
3398
0
            }
3399
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3400
0
          goto error;
3401
0
  } else {
3402
0
      xmlFree(strval);
3403
0
  }
3404
0
    }
3405
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3406
0
    return(ret);
3407
3408
0
error:
3409
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3410
0
    xmlXPathFreeNodeSet(ret);
3411
0
    return(NULL);
3412
0
}
3413
3414
/**
3415
 * Implements the EXSLT - Sets distinct() function:
3416
 *    node-set set:distinct (node-set)
3417
 * `nodes` is sorted by document order, then exslSetsDistinctSorted
3418
 * is called with the sorted node-set
3419
 *
3420
 * @param nodes  a node-set
3421
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3422
 *         it is empty
3423
 */
3424
xmlNodeSet *
3425
0
xmlXPathDistinct (xmlNodeSet *nodes) {
3426
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3427
0
  return(nodes);
3428
3429
0
    xmlXPathNodeSetSort(nodes);
3430
0
    return(xmlXPathDistinctSorted(nodes));
3431
0
}
3432
3433
/**
3434
 * Implements the EXSLT - Sets has-same-nodes function:
3435
 *    boolean set:has-same-node(node-set, node-set)
3436
 *
3437
 * @param nodes1  a node-set
3438
 * @param nodes2  a node-set
3439
 * @returns true (1) if `nodes1` shares any node with `nodes2`, false (0)
3440
 *         otherwise
3441
 */
3442
int
3443
0
xmlXPathHasSameNodes (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3444
0
    int i, l;
3445
0
    xmlNodePtr cur;
3446
3447
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3448
0
  xmlXPathNodeSetIsEmpty(nodes2))
3449
0
  return(0);
3450
3451
0
    l = xmlXPathNodeSetGetLength(nodes1);
3452
0
    for (i = 0; i < l; i++) {
3453
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3454
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3455
0
      return(1);
3456
0
    }
3457
0
    return(0);
3458
0
}
3459
3460
/**
3461
 * Implements the EXSLT - Sets leading() function:
3462
 *    node-set set:leading (node-set, node-set)
3463
 *
3464
 * @param nodes  a node-set, sorted by document order
3465
 * @param node  a node
3466
 * @returns the nodes in `nodes` that precede `node` in document order,
3467
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3468
 *         doesn't contain `node`
3469
 */
3470
xmlNodeSet *
3471
0
xmlXPathNodeLeadingSorted (xmlNodeSet *nodes, xmlNode *node) {
3472
0
    int i, l;
3473
0
    xmlNodePtr cur;
3474
0
    xmlNodeSetPtr ret;
3475
3476
0
    if (node == NULL)
3477
0
  return(nodes);
3478
3479
0
    ret = xmlXPathNodeSetCreate(NULL);
3480
0
    if (ret == NULL)
3481
0
        return(ret);
3482
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3483
0
  (!xmlXPathNodeSetContains(nodes, node)))
3484
0
  return(ret);
3485
3486
0
    l = xmlXPathNodeSetGetLength(nodes);
3487
0
    for (i = 0; i < l; i++) {
3488
0
  cur = xmlXPathNodeSetItem(nodes, i);
3489
0
  if (cur == node)
3490
0
      break;
3491
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3492
0
            xmlXPathFreeNodeSet(ret);
3493
0
      return(NULL);
3494
0
        }
3495
0
    }
3496
0
    return(ret);
3497
0
}
3498
3499
/**
3500
 * Implements the EXSLT - Sets leading() function:
3501
 *    node-set set:leading (node-set, node-set)
3502
 * `nodes` is sorted by document order, then exslSetsNodeLeadingSorted
3503
 * is called.
3504
 *
3505
 * @param nodes  a node-set
3506
 * @param node  a node
3507
 * @returns the nodes in `nodes` that precede `node` in document order,
3508
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3509
 *         doesn't contain `node`
3510
 */
3511
xmlNodeSet *
3512
0
xmlXPathNodeLeading (xmlNodeSet *nodes, xmlNode *node) {
3513
0
    xmlXPathNodeSetSort(nodes);
3514
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3515
0
}
3516
3517
/**
3518
 * Implements the EXSLT - Sets leading() function:
3519
 *    node-set set:leading (node-set, node-set)
3520
 *
3521
 * @param nodes1  a node-set, sorted by document order
3522
 * @param nodes2  a node-set, sorted by document order
3523
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3524
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3525
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3526
 */
3527
xmlNodeSet *
3528
0
xmlXPathLeadingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3529
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3530
0
  return(nodes1);
3531
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3532
0
             xmlXPathNodeSetItem(nodes2, 1)));
3533
0
}
3534
3535
/**
3536
 * Implements the EXSLT - Sets leading() function:
3537
 *    node-set set:leading (node-set, node-set)
3538
 * `nodes1` and `nodes2` are sorted by document order, then
3539
 * exslSetsLeadingSorted is called.
3540
 *
3541
 * @param nodes1  a node-set
3542
 * @param nodes2  a node-set
3543
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3544
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3545
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3546
 */
3547
xmlNodeSet *
3548
0
xmlXPathLeading (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3549
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3550
0
  return(nodes1);
3551
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3552
0
  return(xmlXPathNodeSetCreate(NULL));
3553
0
    xmlXPathNodeSetSort(nodes1);
3554
0
    xmlXPathNodeSetSort(nodes2);
3555
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3556
0
             xmlXPathNodeSetItem(nodes2, 1)));
3557
0
}
3558
3559
/**
3560
 * Implements the EXSLT - Sets trailing() function:
3561
 *    node-set set:trailing (node-set, node-set)
3562
 *
3563
 * @param nodes  a node-set, sorted by document order
3564
 * @param node  a node
3565
 * @returns the nodes in `nodes` that follow `node` in document order,
3566
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3567
 *         doesn't contain `node`
3568
 */
3569
xmlNodeSet *
3570
0
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3571
0
    int i, l;
3572
0
    xmlNodePtr cur;
3573
0
    xmlNodeSetPtr ret;
3574
3575
0
    if (node == NULL)
3576
0
  return(nodes);
3577
3578
0
    ret = xmlXPathNodeSetCreate(NULL);
3579
0
    if (ret == NULL)
3580
0
        return(ret);
3581
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3582
0
  (!xmlXPathNodeSetContains(nodes, node)))
3583
0
  return(ret);
3584
3585
0
    l = xmlXPathNodeSetGetLength(nodes);
3586
0
    for (i = l - 1; i >= 0; i--) {
3587
0
  cur = xmlXPathNodeSetItem(nodes, i);
3588
0
  if (cur == node)
3589
0
      break;
3590
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3591
0
            xmlXPathFreeNodeSet(ret);
3592
0
      return(NULL);
3593
0
        }
3594
0
    }
3595
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3596
0
    return(ret);
3597
0
}
3598
3599
/**
3600
 * Implements the EXSLT - Sets trailing() function:
3601
 *    node-set set:trailing (node-set, node-set)
3602
 * `nodes` is sorted by document order, then #xmlXPathNodeTrailingSorted
3603
 * is called.
3604
 *
3605
 * @param nodes  a node-set
3606
 * @param node  a node
3607
 * @returns the nodes in `nodes` that follow `node` in document order,
3608
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3609
 *         doesn't contain `node`
3610
 */
3611
xmlNodeSet *
3612
0
xmlXPathNodeTrailing (xmlNodeSet *nodes, xmlNode *node) {
3613
0
    xmlXPathNodeSetSort(nodes);
3614
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3615
0
}
3616
3617
/**
3618
 * Implements the EXSLT - Sets trailing() function:
3619
 *    node-set set:trailing (node-set, node-set)
3620
 *
3621
 * @param nodes1  a node-set, sorted by document order
3622
 * @param nodes2  a node-set, sorted by document order
3623
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3624
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3625
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3626
 */
3627
xmlNodeSet *
3628
0
xmlXPathTrailingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3629
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3630
0
  return(nodes1);
3631
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3632
0
              xmlXPathNodeSetItem(nodes2, 0)));
3633
0
}
3634
3635
/**
3636
 * Implements the EXSLT - Sets trailing() function:
3637
 *    node-set set:trailing (node-set, node-set)
3638
 * `nodes1` and `nodes2` are sorted by document order, then
3639
 * #xmlXPathTrailingSorted is called.
3640
 *
3641
 * @param nodes1  a node-set
3642
 * @param nodes2  a node-set
3643
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3644
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3645
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3646
 */
3647
xmlNodeSet *
3648
0
xmlXPathTrailing (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3649
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3650
0
  return(nodes1);
3651
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3652
0
  return(xmlXPathNodeSetCreate(NULL));
3653
0
    xmlXPathNodeSetSort(nodes1);
3654
0
    xmlXPathNodeSetSort(nodes2);
3655
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3656
0
              xmlXPathNodeSetItem(nodes2, 0)));
3657
0
}
3658
3659
/************************************************************************
3660
 *                  *
3661
 *    Routines to handle extra functions      *
3662
 *                  *
3663
 ************************************************************************/
3664
3665
/**
3666
 * Register a new function. If `f` is NULL it unregisters the function
3667
 *
3668
 * @param ctxt  the XPath context
3669
 * @param name  the function name
3670
 * @param f  the function implementation or NULL
3671
 * @returns 0 in case of success, -1 in case of error
3672
 */
3673
int
3674
xmlXPathRegisterFunc(xmlXPathContext *ctxt, const xmlChar *name,
3675
0
         xmlXPathFunction f) {
3676
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
0
}
3678
3679
/**
3680
 * Register a new function. If `f` is NULL it unregisters the function
3681
 *
3682
 * @param ctxt  the XPath context
3683
 * @param name  the function name
3684
 * @param ns_uri  the function namespace URI
3685
 * @param f  the function implementation or NULL
3686
 * @returns 0 in case of success, -1 in case of error
3687
 */
3688
int
3689
xmlXPathRegisterFuncNS(xmlXPathContext *ctxt, const xmlChar *name,
3690
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
0
    int ret;
3692
0
    void *payload;
3693
3694
0
    if (ctxt == NULL)
3695
0
  return(-1);
3696
0
    if (name == NULL)
3697
0
  return(-1);
3698
3699
0
    if (ctxt->funcHash == NULL)
3700
0
  ctxt->funcHash = xmlHashCreate(0);
3701
0
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
0
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
0
    memcpy(&payload, &f, sizeof(f));
3708
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
0
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
0
    return(0);
3715
0
}
3716
3717
/**
3718
 * Registers an external mechanism to do function lookup.
3719
 *
3720
 * @param ctxt  the XPath context
3721
 * @param f  the lookup function
3722
 * @param funcCtxt  the lookup data
3723
 */
3724
void
3725
xmlXPathRegisterFuncLookup (xmlXPathContext *ctxt,
3726
          xmlXPathFuncLookupFunc f,
3727
0
          void *funcCtxt) {
3728
0
    if (ctxt == NULL)
3729
0
  return;
3730
0
    ctxt->funcLookupFunc = f;
3731
0
    ctxt->funcLookupData = funcCtxt;
3732
0
}
3733
3734
/**
3735
 * Search in the Function array of the context for the given
3736
 * function.
3737
 *
3738
 * @param ctxt  the XPath context
3739
 * @param name  the function name
3740
 * @returns the xmlXPathFunction or NULL if not found
3741
 */
3742
xmlXPathFunction
3743
16.1k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
16.1k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
16.1k
}
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
16.2k
       const xmlChar *ns_uri) {
3759
16.2k
    xmlXPathFunction ret;
3760
16.2k
    void *payload;
3761
3762
16.2k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
16.2k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
16.2k
    if (ns_uri == NULL) {
3768
16.1k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
24.7k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
23.1k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
23.1k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
23.1k
                       (char *) name) == 0)
3775
14.5k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
8.53k
            bucketIndex += 1;
3778
8.53k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
8.53k
        }
3781
16.1k
    }
3782
3783
1.66k
    if (ctxt->funcLookupFunc != NULL) {
3784
0
  xmlXPathFuncLookupFunc f;
3785
3786
0
  f = ctxt->funcLookupFunc;
3787
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
0
  if (ret != NULL)
3789
0
      return(ret);
3790
0
    }
3791
3792
1.66k
    if (ctxt->funcHash == NULL)
3793
1.66k
  return(NULL);
3794
3795
0
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
0
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
0
    return(ret);
3799
1.66k
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
46.0k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
46.0k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
46.0k
    xmlHashFree(ctxt->funcHash, NULL);
3812
46.0k
    ctxt->funcHash = NULL;
3813
46.0k
}
3814
3815
/************************************************************************
3816
 *                  *
3817
 *      Routines to handle Variables      *
3818
 *                  *
3819
 ************************************************************************/
3820
3821
/**
3822
 * Register a new variable value. If `value` is NULL it unregisters
3823
 * the variable
3824
 *
3825
 * @param ctxt  the XPath context
3826
 * @param name  the variable name
3827
 * @param value  the variable value or NULL
3828
 * @returns 0 in case of success, -1 in case of error
3829
 */
3830
int
3831
xmlXPathRegisterVariable(xmlXPathContext *ctxt, const xmlChar *name,
3832
0
       xmlXPathObject *value) {
3833
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
0
}
3835
3836
/**
3837
 * Register a new variable value. If `value` is NULL it unregisters
3838
 * the variable
3839
 *
3840
 * @param ctxt  the XPath context
3841
 * @param name  the variable name
3842
 * @param ns_uri  the variable namespace URI
3843
 * @param value  the variable value or NULL
3844
 * @returns 0 in case of success, -1 in case of error
3845
 */
3846
int
3847
xmlXPathRegisterVariableNS(xmlXPathContext *ctxt, const xmlChar *name,
3848
         const xmlChar *ns_uri,
3849
0
         xmlXPathObject *value) {
3850
0
    if (ctxt == NULL)
3851
0
  return(-1);
3852
0
    if (name == NULL)
3853
0
  return(-1);
3854
3855
0
    if (ctxt->varHash == NULL)
3856
0
  ctxt->varHash = xmlHashCreate(0);
3857
0
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
0
    if (value == NULL)
3860
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
0
                             xmlXPathFreeObjectEntry));
3862
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
0
             (void *) value, xmlXPathFreeObjectEntry));
3864
0
}
3865
3866
/**
3867
 * register an external mechanism to do variable lookup
3868
 *
3869
 * @param ctxt  the XPath context
3870
 * @param f  the lookup function
3871
 * @param data  the lookup data
3872
 */
3873
void
3874
xmlXPathRegisterVariableLookup(xmlXPathContext *ctxt,
3875
0
   xmlXPathVariableLookupFunc f, void *data) {
3876
0
    if (ctxt == NULL)
3877
0
  return;
3878
0
    ctxt->varLookupFunc = f;
3879
0
    ctxt->varLookupData = data;
3880
0
}
3881
3882
/**
3883
 * Search in the Variable array of the context for the given
3884
 * variable value.
3885
 *
3886
 * @param ctxt  the XPath context
3887
 * @param name  the variable name
3888
 * @returns a copy of the value or NULL if not found
3889
 */
3890
xmlXPathObject *
3891
247
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
247
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
247
    if (ctxt->varLookupFunc != NULL) {
3896
0
  xmlXPathObjectPtr ret;
3897
3898
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3899
0
          (ctxt->varLookupData, name, NULL);
3900
0
  return(ret);
3901
0
    }
3902
247
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
247
}
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
294
       const xmlChar *ns_uri) {
3917
294
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
294
    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
294
    if (ctxt->varHash == NULL)
3929
294
  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
46.0k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
46.0k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
46.0k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
46.0k
    ctxt->varHash = NULL;
3948
46.0k
}
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
1.21k
         const xmlChar *ns_uri) {
3962
1.21k
    xmlChar *copy;
3963
3964
1.21k
    if (ctxt == NULL)
3965
0
  return(-1);
3966
1.21k
    if (prefix == NULL)
3967
0
  return(-1);
3968
1.21k
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
1.21k
    if (ctxt->nsHash == NULL)
3972
158
  ctxt->nsHash = xmlHashCreate(10);
3973
1.21k
    if (ctxt->nsHash == NULL) {
3974
9
        xmlXPathErrMemory(ctxt);
3975
9
  return(-1);
3976
9
    }
3977
1.20k
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
1.20k
    copy = xmlStrdup(ns_uri);
3982
1.20k
    if (copy == NULL) {
3983
5
        xmlXPathErrMemory(ctxt);
3984
5
        return(-1);
3985
5
    }
3986
1.19k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
1.19k
                           xmlHashDefaultDeallocator) < 0) {
3988
4
        xmlXPathErrMemory(ctxt);
3989
4
        xmlFree(copy);
3990
4
        return(-1);
3991
4
    }
3992
3993
1.19k
    return(0);
3994
1.19k
}
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
15.1k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
15.1k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
15.1k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
15.1k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
14.3k
  return(XML_XML_NAMESPACE);
4013
4014
839
    if (ctxt->namespaces != NULL) {
4015
0
  int i;
4016
4017
0
  for (i = 0;i < ctxt->nsNr;i++) {
4018
0
      if ((ctxt->namespaces[i] != NULL) &&
4019
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4020
0
    return(ctxt->namespaces[i]->href);
4021
0
  }
4022
0
    }
4023
4024
839
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
839
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
46.0k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
46.0k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
46.0k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
46.0k
    ctxt->nsHash = NULL;
4039
46.0k
}
4040
4041
/************************************************************************
4042
 *                  *
4043
 *      Routines to handle Values     *
4044
 *                  *
4045
 ************************************************************************/
4046
4047
/* Allocations are terrible, one needs to optimize all this !!! */
4048
4049
/**
4050
 * Create a new xmlXPathObject of type double and of value `val`
4051
 *
4052
 * @param val  the double value
4053
 * @returns the newly created object.
4054
 */
4055
xmlXPathObject *
4056
1.35M
xmlXPathNewFloat(double val) {
4057
1.35M
    xmlXPathObjectPtr ret;
4058
4059
1.35M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
1.35M
    if (ret == NULL)
4061
274
  return(NULL);
4062
1.35M
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
1.35M
    ret->type = XPATH_NUMBER;
4064
1.35M
    ret->floatval = val;
4065
1.35M
    return(ret);
4066
1.35M
}
4067
4068
/**
4069
 * Create a new xmlXPathObject of type boolean and of value `val`
4070
 *
4071
 * @param val  the boolean value
4072
 * @returns the newly created object.
4073
 */
4074
xmlXPathObject *
4075
1.01M
xmlXPathNewBoolean(int val) {
4076
1.01M
    xmlXPathObjectPtr ret;
4077
4078
1.01M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
1.01M
    if (ret == NULL)
4080
172
  return(NULL);
4081
1.00M
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
1.00M
    ret->type = XPATH_BOOLEAN;
4083
1.00M
    ret->boolval = (val != 0);
4084
1.00M
    return(ret);
4085
1.01M
}
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
638k
xmlXPathNewString(const xmlChar *val) {
4095
638k
    xmlXPathObjectPtr ret;
4096
4097
638k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
638k
    if (ret == NULL)
4099
39
  return(NULL);
4100
638k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
638k
    ret->type = XPATH_STRING;
4102
638k
    if (val == NULL)
4103
560
        val = BAD_CAST "";
4104
638k
    ret->stringval = xmlStrdup(val);
4105
638k
    if (ret->stringval == NULL) {
4106
44
        xmlFree(ret);
4107
44
        return(NULL);
4108
44
    }
4109
638k
    return(ret);
4110
638k
}
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
198k
xmlXPathWrapString (xmlChar *val) {
4122
198k
    xmlXPathObjectPtr ret;
4123
4124
198k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
198k
    if (ret == NULL) {
4126
107
        xmlFree(val);
4127
107
  return(NULL);
4128
107
    }
4129
198k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
198k
    ret->type = XPATH_STRING;
4131
198k
    ret->stringval = val;
4132
198k
    return(ret);
4133
198k
}
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
1.09M
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
1.09M
    xmlXPathObjectPtr ret;
4185
4186
1.09M
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
1.09M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
1.09M
    if (ret == NULL)
4191
144
  return(NULL);
4192
1.09M
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
1.09M
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
1.00M
  case XPATH_NUMBER:
4196
1.00M
      break;
4197
87.8k
  case XPATH_STRING:
4198
87.8k
      ret->stringval = xmlStrdup(val->stringval);
4199
87.8k
            if (ret->stringval == NULL) {
4200
28
                xmlFree(ret);
4201
28
                return(NULL);
4202
28
            }
4203
87.8k
      break;
4204
87.8k
  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
1.09M
    }
4222
1.09M
    return(ret);
4223
1.09M
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
10.4M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
10.4M
    if (obj == NULL) return;
4233
10.4M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
6.15M
        if (obj->nodesetval != NULL)
4235
6.15M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
6.15M
    } else if (obj->type == XPATH_STRING) {
4237
916k
  if (obj->stringval != NULL)
4238
916k
      xmlFree(obj->stringval);
4239
916k
    }
4240
10.4M
    xmlFree(obj);
4241
10.4M
}
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
14.3M
{
4258
14.3M
    if (obj == NULL)
4259
58
  return;
4260
14.3M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
9.89M
   xmlXPathFreeObject(obj);
4262
9.89M
    } else {
4263
4.45M
  xmlXPathContextCachePtr cache =
4264
4.45M
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
4.45M
  switch (obj->type) {
4267
2.67M
      case XPATH_NODESET:
4268
2.67M
      case XPATH_XSLT_TREE:
4269
2.67M
    if (obj->nodesetval != NULL) {
4270
2.67M
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
2.57M
      (cache->numNodeset < cache->maxNodeset)) {
4272
2.24M
                        obj->stringval = (void *) cache->nodesetObjs;
4273
2.24M
                        cache->nodesetObjs = obj;
4274
2.24M
                        cache->numNodeset += 1;
4275
2.24M
      goto obj_cached;
4276
2.24M
        } else {
4277
428k
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
428k
      obj->nodesetval = NULL;
4279
428k
        }
4280
2.67M
    }
4281
428k
    break;
4282
488k
      case XPATH_STRING:
4283
488k
    if (obj->stringval != NULL)
4284
488k
        xmlFree(obj->stringval);
4285
488k
                obj->stringval = NULL;
4286
488k
    break;
4287
146k
      case XPATH_BOOLEAN:
4288
1.29M
      case XPATH_NUMBER:
4289
1.29M
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
4.45M
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
2.21M
        if (cache->numMisc >= cache->maxMisc)
4298
25.6k
      goto free_obj;
4299
2.18M
        obj->stringval = (void *) cache->miscObjs;
4300
2.18M
        cache->miscObjs = obj;
4301
2.18M
        cache->numMisc += 1;
4302
4303
4.43M
obj_cached:
4304
4.43M
        obj->boolval = 0;
4305
4.43M
  if (obj->nodesetval != NULL) {
4306
2.24M
      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
2.24M
      if (tmpset->nodeNr > 0) {
4313
2.22M
    int i;
4314
2.22M
    xmlNodePtr node;
4315
4316
4.51M
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
2.28M
        node = tmpset->nodeTab[i];
4318
2.28M
        if ((node != NULL) &&
4319
2.28M
      (node->type == XML_NAMESPACE_DECL))
4320
371k
        {
4321
371k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
371k
        }
4323
2.28M
    }
4324
2.22M
      }
4325
2.24M
      tmpset->nodeNr = 0;
4326
2.24M
        }
4327
4328
4.43M
  return;
4329
4330
25.6k
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
25.6k
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
25.6k
  xmlFree(obj);
4337
25.6k
    }
4338
14.3M
}
4339
4340
4341
/************************************************************************
4342
 *                  *
4343
 *      Type Casting Routines       *
4344
 *                  *
4345
 ************************************************************************/
4346
4347
/**
4348
 * Converts a boolean to its string value.
4349
 *
4350
 * @param val  a boolean
4351
 * @returns a newly allocated string.
4352
 */
4353
xmlChar *
4354
26.3k
xmlXPathCastBooleanToString (int val) {
4355
26.3k
    xmlChar *ret;
4356
26.3k
    if (val)
4357
6.55k
  ret = xmlStrdup((const xmlChar *) "true");
4358
19.7k
    else
4359
19.7k
  ret = xmlStrdup((const xmlChar *) "false");
4360
26.3k
    return(ret);
4361
26.3k
}
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
91.8k
xmlXPathCastNumberToString (double val) {
4371
91.8k
    xmlChar *ret;
4372
91.8k
    switch (xmlXPathIsInf(val)) {
4373
1.14k
    case 1:
4374
1.14k
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
1.14k
  break;
4376
962
    case -1:
4377
962
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
962
  break;
4379
89.7k
    default:
4380
89.7k
  if (xmlXPathIsNaN(val)) {
4381
30.6k
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
59.0k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
6.06k
      ret = xmlStrdup((const xmlChar *) "0");
4385
53.0k
  } else {
4386
      /* could be improved */
4387
53.0k
      char buf[100];
4388
53.0k
      xmlXPathFormatNumber(val, buf, 99);
4389
53.0k
      buf[99] = 0;
4390
53.0k
      ret = xmlStrdup((const xmlChar *) buf);
4391
53.0k
  }
4392
91.8k
    }
4393
91.8k
    return(ret);
4394
91.8k
}
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
9.36M
xmlXPathCastNodeToString (xmlNode *node) {
4404
9.36M
    return(xmlNodeGetContent(node));
4405
9.36M
}
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
1.38M
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
1.38M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
873k
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
509k
    if (ns->nodeNr > 1)
4419
97.5k
  xmlXPathNodeSetSort(ns);
4420
509k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
1.38M
}
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
227k
xmlXPathCastToString(xmlXPathObject *val) {
4432
227k
    xmlChar *ret = NULL;
4433
4434
227k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
227k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
105k
        case XPATH_NODESET:
4441
105k
        case XPATH_XSLT_TREE:
4442
105k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
105k
      break;
4444
3.76k
  case XPATH_STRING:
4445
3.76k
      return(xmlStrdup(val->stringval));
4446
26.3k
        case XPATH_BOOLEAN:
4447
26.3k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
26.3k
      break;
4449
91.8k
  case XPATH_NUMBER: {
4450
91.8k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
91.8k
      break;
4452
105k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
227k
    }
4458
223k
    return(ret);
4459
227k
}
4460
4461
/**
4462
 * Converts an existing object to its string() equivalent
4463
 *
4464
 * @param val  an XPath object
4465
 * @returns the new object, the old one is freed (or the operation
4466
 *         is done directly on `val`)
4467
 */
4468
xmlXPathObject *
4469
0
xmlXPathConvertString(xmlXPathObject *val) {
4470
0
    xmlChar *res = NULL;
4471
4472
0
    if (val == NULL)
4473
0
  return(xmlXPathNewCString(""));
4474
4475
0
    switch (val->type) {
4476
0
    case XPATH_UNDEFINED:
4477
0
  break;
4478
0
    case XPATH_NODESET:
4479
0
    case XPATH_XSLT_TREE:
4480
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4481
0
  break;
4482
0
    case XPATH_STRING:
4483
0
  return(val);
4484
0
    case XPATH_BOOLEAN:
4485
0
  res = xmlXPathCastBooleanToString(val->boolval);
4486
0
  break;
4487
0
    case XPATH_NUMBER:
4488
0
  res = xmlXPathCastNumberToString(val->floatval);
4489
0
  break;
4490
0
    case XPATH_USERS:
4491
  /* TODO */
4492
0
  break;
4493
0
    }
4494
0
    xmlXPathFreeObject(val);
4495
0
    if (res == NULL)
4496
0
  return(xmlXPathNewCString(""));
4497
0
    return(xmlXPathWrapString(res));
4498
0
}
4499
4500
/**
4501
 * Converts a boolean to its number value
4502
 *
4503
 * @param val  a boolean
4504
 * @returns the number value
4505
 */
4506
double
4507
60.3k
xmlXPathCastBooleanToNumber(int val) {
4508
60.3k
    if (val)
4509
12.1k
  return(1.0);
4510
48.2k
    return(0.0);
4511
60.3k
}
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
8.87M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
8.87M
    return(xmlXPathStringEvalNumber(val));
4522
8.87M
}
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
6.51M
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
6.51M
    xmlChar *strval;
4534
6.51M
    double ret;
4535
4536
6.51M
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
6.51M
    strval = xmlXPathCastNodeToString(node);
4539
6.51M
    if (strval == NULL) {
4540
50
        xmlXPathPErrMemory(ctxt);
4541
50
  return(xmlXPathNAN);
4542
50
    }
4543
6.51M
    ret = xmlXPathCastStringToNumber(strval);
4544
6.51M
    xmlFree(strval);
4545
4546
6.51M
    return(ret);
4547
6.51M
}
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
131k
xmlXPathCastNumberToBoolean (double val) {
4618
131k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
109k
   return(0);
4620
22.0k
     return(1);
4621
131k
}
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
1.84k
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
1.84k
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
874
  return(0);
4633
973
    return(1);
4634
1.84k
}
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
29.2k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
29.2k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
24.5k
  return(0);
4646
4.69k
    return(1);
4647
29.2k
}
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
42.7k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
42.7k
    int ret = 0;
4658
4659
42.7k
    if (val == NULL)
4660
0
  return(0);
4661
42.7k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
29.2k
    case XPATH_NODESET:
4666
29.2k
    case XPATH_XSLT_TREE:
4667
29.2k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
29.2k
  break;
4669
1.84k
    case XPATH_STRING:
4670
1.84k
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
1.84k
  break;
4672
11.6k
    case XPATH_NUMBER:
4673
11.6k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
11.6k
  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
42.7k
    }
4683
42.7k
    return(ret);
4684
42.7k
}
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
46.1k
xmlXPathNewContext(xmlDoc *doc) {
4721
46.1k
    xmlXPathContextPtr ret;
4722
4723
46.1k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
46.1k
    if (ret == NULL)
4725
120
  return(NULL);
4726
46.0k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
46.0k
    ret->doc = doc;
4728
46.0k
    ret->node = NULL;
4729
4730
46.0k
    ret->varHash = NULL;
4731
4732
46.0k
    ret->nb_types = 0;
4733
46.0k
    ret->max_types = 0;
4734
46.0k
    ret->types = NULL;
4735
4736
46.0k
    ret->nb_axis = 0;
4737
46.0k
    ret->max_axis = 0;
4738
46.0k
    ret->axis = NULL;
4739
4740
46.0k
    ret->nsHash = NULL;
4741
46.0k
    ret->user = NULL;
4742
4743
46.0k
    ret->contextSize = -1;
4744
46.0k
    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
46.0k
    return(ret);
4754
46.1k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
46.0k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
46.0k
    if (ctxt == NULL) return;
4764
4765
46.0k
    if (ctxt->cache != NULL)
4766
25.3k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
46.0k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
46.0k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
46.0k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
46.0k
    xmlResetError(&ctxt->lastError);
4771
46.0k
    xmlFree(ctxt);
4772
46.0k
}
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
6.92k
                        xmlStructuredErrorFunc handler, void *data) {
4786
6.92k
    if (ctxt == NULL)
4787
0
        return;
4788
4789
6.92k
    ctxt->error = handler;
4790
6.92k
    ctxt->userData = data;
4791
6.92k
}
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
58.0k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
58.0k
    xmlXPathParserContextPtr ret;
4809
4810
58.0k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
58.0k
    if (ret == NULL) {
4812
132
        xmlXPathErrMemory(ctxt);
4813
132
  return(NULL);
4814
132
    }
4815
57.8k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
57.8k
    ret->cur = ret->base = str;
4817
57.8k
    ret->context = ctxt;
4818
4819
57.8k
    ret->comp = xmlXPathNewCompExpr();
4820
57.8k
    if (ret->comp == NULL) {
4821
386
        xmlXPathErrMemory(ctxt);
4822
386
  xmlFree(ret->valueTab);
4823
386
  xmlFree(ret);
4824
386
  return(NULL);
4825
386
    }
4826
57.5k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
57.5k
    return(ret);
4832
57.8k
}
4833
4834
/**
4835
 * Create a new xmlXPathParserContext when processing a compiled expression
4836
 *
4837
 * @param comp  the XPath compiled expression
4838
 * @param ctxt  the XPath context
4839
 * @returns the xmlXPathParserContext just allocated.
4840
 */
4841
static xmlXPathParserContextPtr
4842
4.20k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
4.20k
    xmlXPathParserContextPtr ret;
4844
4845
4.20k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
4.20k
    if (ret == NULL) {
4847
3
        xmlXPathErrMemory(ctxt);
4848
3
  return(NULL);
4849
3
    }
4850
4.20k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
4.20k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
4.20k
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
4.20k
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
4.20k
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
4.20k
    ret->valueNr = 0;
4865
4.20k
    ret->value = NULL;
4866
4867
4.20k
    ret->context = ctxt;
4868
4.20k
    ret->comp = comp;
4869
4870
4.20k
    return(ret);
4871
4.20k
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
61.7k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
61.7k
    int i;
4881
4882
61.7k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
61.7k
    if (ctxt->valueTab != NULL) {
4886
166k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
110k
            if (ctxt->context)
4888
110k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
110k
        }
4892
55.6k
        xmlFree(ctxt->valueTab);
4893
55.6k
    }
4894
61.7k
    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
53.2k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
53.2k
    }
4903
61.7k
    xmlFree(ctxt);
4904
61.7k
}
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
502k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
502k
    int len = 2;
4922
502k
    const xmlChar * string = NULL;
4923
502k
    xmlNodePtr tmp = NULL;
4924
502k
    unsigned int ret = 0;
4925
4926
502k
    if (node == NULL)
4927
0
  return(0);
4928
4929
502k
    if (node->type == XML_DOCUMENT_NODE) {
4930
44.4k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
44.4k
  if (tmp == NULL)
4932
781
      node = node->children;
4933
43.6k
  else
4934
43.6k
      node = tmp;
4935
4936
44.4k
  if (node == NULL)
4937
578
      return(0);
4938
44.4k
    }
4939
4940
501k
    switch (node->type) {
4941
1.26k
  case XML_COMMENT_NODE:
4942
2.99k
  case XML_PI_NODE:
4943
3.56k
  case XML_CDATA_SECTION_NODE:
4944
33.5k
  case XML_TEXT_NODE:
4945
33.5k
      string = node->content;
4946
33.5k
      if (string == NULL)
4947
1.73k
    return(0);
4948
31.7k
      if (string[0] == 0)
4949
935
    return(0);
4950
30.8k
      return(string[0] + (string[1] << 8));
4951
293k
  case XML_NAMESPACE_DECL:
4952
293k
      string = ((xmlNsPtr)node)->href;
4953
293k
      if (string == NULL)
4954
214
    return(0);
4955
292k
      if (string[0] == 0)
4956
79.2k
    return(0);
4957
213k
      return(string[0] + (string[1] << 8));
4958
1.63k
  case XML_ATTRIBUTE_NODE:
4959
1.63k
      tmp = ((xmlAttrPtr) node)->children;
4960
1.63k
      break;
4961
173k
  case XML_ELEMENT_NODE:
4962
173k
      tmp = node->children;
4963
173k
      break;
4964
197
  default:
4965
197
      return(0);
4966
501k
    }
4967
678k
    while (tmp != NULL) {
4968
601k
  switch (tmp->type) {
4969
15.7k
      case XML_CDATA_SECTION_NODE:
4970
136k
      case XML_TEXT_NODE:
4971
136k
    string = tmp->content;
4972
136k
    break;
4973
464k
      default:
4974
464k
                string = NULL;
4975
464k
    break;
4976
601k
  }
4977
601k
  if ((string != NULL) && (string[0] != 0)) {
4978
134k
      if (len == 1) {
4979
31.3k
    return(ret + (string[0] << 8));
4980
31.3k
      }
4981
103k
      if (string[1] == 0) {
4982
37.3k
    len = 1;
4983
37.3k
    ret = string[0];
4984
66.0k
      } else {
4985
66.0k
    return(string[0] + (string[1] << 8));
4986
66.0k
      }
4987
103k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
503k
        if ((tmp->children != NULL) &&
4992
235k
            (tmp->type != XML_DTD_NODE) &&
4993
235k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
235k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
235k
            tmp = tmp->children;
4996
235k
            continue;
4997
235k
  }
4998
268k
  if (tmp == node)
4999
0
      break;
5000
5001
268k
  if (tmp->next != NULL) {
5002
252k
      tmp = tmp->next;
5003
252k
      continue;
5004
252k
  }
5005
5006
52.2k
  do {
5007
52.2k
      tmp = tmp->parent;
5008
52.2k
      if (tmp == NULL)
5009
0
    break;
5010
52.2k
      if (tmp == node) {
5011
12.3k
    tmp = NULL;
5012
12.3k
    break;
5013
12.3k
      }
5014
39.9k
      if (tmp->next != NULL) {
5015
3.75k
    tmp = tmp->next;
5016
3.75k
    break;
5017
3.75k
      }
5018
39.9k
  } while (tmp != NULL);
5019
16.1k
    }
5020
77.3k
    return(ret);
5021
174k
}
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
9.85k
xmlXPathStringHash(const xmlChar * string) {
5032
9.85k
    if (string == NULL)
5033
0
  return(0);
5034
9.85k
    if (string[0] == 0)
5035
2.89k
  return(0);
5036
6.95k
    return(string[0] + (string[1] << 8));
5037
9.85k
}
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
152k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
152k
    int i, ret = 0;
5063
152k
    xmlNodeSetPtr ns;
5064
152k
    xmlChar *str2;
5065
5066
152k
    if ((f == NULL) || (arg == NULL) ||
5067
152k
  ((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
152k
    ns = arg->nodesetval;
5073
152k
    if (ns != NULL) {
5074
542k
  for (i = 0;i < ns->nodeNr;i++) {
5075
394k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
394k
       if (str2 != NULL) {
5077
394k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
394k
     xmlFree(str2);
5079
394k
     xmlXPathNumberFunction(ctxt, 1);
5080
394k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
394k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
394k
     if (ret)
5083
3.68k
         break;
5084
394k
       } else {
5085
21
                 xmlXPathPErrMemory(ctxt);
5086
21
             }
5087
394k
  }
5088
152k
    }
5089
152k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
152k
    xmlXPathReleaseObject(ctxt->context, f);
5091
152k
    return(ret);
5092
152k
}
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
4.75k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
4.75k
    int i, ret = 0;
5117
4.75k
    xmlNodeSetPtr ns;
5118
4.75k
    xmlChar *str2;
5119
5120
4.75k
    if ((s == NULL) || (arg == NULL) ||
5121
4.75k
  ((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
4.75k
    ns = arg->nodesetval;
5127
4.75k
    if (ns != NULL) {
5128
25.6k
  for (i = 0;i < ns->nodeNr;i++) {
5129
21.3k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
21.3k
       if (str2 != NULL) {
5131
21.3k
     xmlXPathValuePush(ctxt,
5132
21.3k
         xmlXPathCacheNewString(ctxt, str2));
5133
21.3k
     xmlFree(str2);
5134
21.3k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
21.3k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
21.3k
     if (ret)
5137
432
         break;
5138
21.3k
       } else {
5139
5
                 xmlXPathPErrMemory(ctxt);
5140
5
             }
5141
21.3k
  }
5142
4.75k
    }
5143
4.75k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
4.75k
    xmlXPathReleaseObject(ctxt->context, s);
5145
4.75k
    return(ret);
5146
4.75k
}
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
128k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
128k
    int i, j, init = 0;
5180
128k
    double val1;
5181
128k
    double *values2;
5182
128k
    int ret = 0;
5183
128k
    xmlNodeSetPtr ns1;
5184
128k
    xmlNodeSetPtr ns2;
5185
5186
128k
    if ((arg1 == NULL) ||
5187
128k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
128k
    if ((arg2 == NULL) ||
5192
128k
  ((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
128k
    ns1 = arg1->nodesetval;
5199
128k
    ns2 = arg2->nodesetval;
5200
5201
128k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
86.7k
  xmlXPathFreeObject(arg1);
5203
86.7k
  xmlXPathFreeObject(arg2);
5204
86.7k
  return(0);
5205
86.7k
    }
5206
41.7k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
28.9k
  xmlXPathFreeObject(arg1);
5208
28.9k
  xmlXPathFreeObject(arg2);
5209
28.9k
  return(0);
5210
28.9k
    }
5211
5212
12.7k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
12.7k
    if (values2 == NULL) {
5214
4
        xmlXPathPErrMemory(ctxt);
5215
4
  xmlXPathFreeObject(arg1);
5216
4
  xmlXPathFreeObject(arg2);
5217
4
  return(0);
5218
4
    }
5219
81.4k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
72.0k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
72.0k
  if (xmlXPathIsNaN(val1))
5222
63.1k
      continue;
5223
68.2k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
62.7k
      if (init == 0) {
5225
51.9k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
51.9k
                                                          ns2->nodeTab[j]);
5227
51.9k
      }
5228
62.7k
      if (xmlXPathIsNaN(values2[j]))
5229
48.1k
    continue;
5230
14.5k
      if (inf && strict)
5231
3.80k
    ret = (val1 < values2[j]);
5232
10.7k
      else if (inf && !strict)
5233
1.24k
    ret = (val1 <= values2[j]);
5234
9.54k
      else if (!inf && strict)
5235
8.38k
    ret = (val1 > values2[j]);
5236
1.16k
      else if (!inf && !strict)
5237
1.16k
    ret = (val1 >= values2[j]);
5238
14.5k
      if (ret)
5239
3.40k
    break;
5240
14.5k
  }
5241
8.92k
  if (ret)
5242
3.40k
      break;
5243
5.52k
  init = 1;
5244
5.52k
    }
5245
12.7k
    xmlFree(values2);
5246
12.7k
    xmlXPathFreeObject(arg1);
5247
12.7k
    xmlXPathFreeObject(arg2);
5248
12.7k
    return(ret);
5249
12.7k
}
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
174k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
174k
    if ((val == NULL) || (arg == NULL) ||
5274
174k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
174k
    switch(val->type) {
5278
152k
        case XPATH_NUMBER:
5279
152k
      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
4.75k
        case XPATH_STRING:
5284
4.75k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
17.6k
        case XPATH_BOOLEAN:
5286
17.6k
      xmlXPathValuePush(ctxt, arg);
5287
17.6k
      xmlXPathBooleanFunction(ctxt, 1);
5288
17.6k
      xmlXPathValuePush(ctxt, val);
5289
17.6k
      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
174k
    }
5295
0
    return(0);
5296
174k
}
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
17.3k
{
5315
17.3k
    int i;
5316
17.3k
    xmlNodeSetPtr ns;
5317
17.3k
    xmlChar *str2;
5318
17.3k
    unsigned int hash;
5319
5320
17.3k
    if ((str == NULL) || (arg == NULL) ||
5321
17.3k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
17.3k
    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
17.3k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
7.53k
        return (0);
5330
9.85k
    hash = xmlXPathStringHash(str);
5331
48.7k
    for (i = 0; i < ns->nodeNr; i++) {
5332
43.7k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
9.04k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
9.04k
            if (str2 == NULL) {
5335
10
                xmlXPathPErrMemory(ctxt);
5336
10
                return(0);
5337
10
            }
5338
9.03k
            if (xmlStrEqual(str, str2)) {
5339
3.79k
                xmlFree(str2);
5340
3.79k
    if (neq)
5341
2.66k
        continue;
5342
1.12k
                return (1);
5343
5.24k
            } else if (neq) {
5344
2.27k
    xmlFree(str2);
5345
2.27k
    return (1);
5346
2.27k
      }
5347
2.97k
            xmlFree(str2);
5348
34.6k
        } else if (neq)
5349
1.44k
      return (1);
5350
43.7k
    }
5351
5.00k
    return (0);
5352
9.85k
}
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
58.4k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
58.4k
  int i, ret=0;
5372
58.4k
  xmlNodeSetPtr ns;
5373
58.4k
  xmlChar *str2;
5374
58.4k
  xmlXPathObjectPtr val;
5375
58.4k
  double v;
5376
5377
58.4k
    if ((arg == NULL) ||
5378
58.4k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
58.4k
    ns = arg->nodesetval;
5382
58.4k
    if (ns != NULL) {
5383
648k
  for (i=0;i<ns->nodeNr;i++) {
5384
593k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
593k
      if (str2 != NULL) {
5386
593k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
593k
    xmlFree(str2);
5388
593k
    xmlXPathNumberFunction(ctxt, 1);
5389
593k
                CHECK_ERROR0;
5390
593k
    val = xmlXPathValuePop(ctxt);
5391
593k
    v = val->floatval;
5392
593k
    xmlXPathReleaseObject(ctxt->context, val);
5393
593k
    if (!xmlXPathIsNaN(v)) {
5394
9.72k
        if ((!neq) && (v==f)) {
5395
2.01k
      ret = 1;
5396
2.01k
      break;
5397
7.71k
        } else if ((neq) && (v!=f)) {
5398
733
      ret = 1;
5399
733
      break;
5400
733
        }
5401
583k
    } else { /* NaN is unequal to any value */
5402
583k
        if (neq)
5403
7.85k
      ret = 1;
5404
583k
    }
5405
593k
      } else {
5406
22
                xmlXPathPErrMemory(ctxt);
5407
22
            }
5408
593k
  }
5409
58.4k
    }
5410
5411
58.3k
    return(ret);
5412
58.4k
}
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
72.5k
                      xmlXPathObjectPtr arg2, int neq) {
5434
72.5k
    int i, j;
5435
72.5k
    unsigned int *hashs1;
5436
72.5k
    unsigned int *hashs2;
5437
72.5k
    xmlChar **values1;
5438
72.5k
    xmlChar **values2;
5439
72.5k
    int ret = 0;
5440
72.5k
    xmlNodeSetPtr ns1;
5441
72.5k
    xmlNodeSetPtr ns2;
5442
5443
72.5k
    if ((arg1 == NULL) ||
5444
72.5k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
72.5k
    if ((arg2 == NULL) ||
5447
72.5k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
72.5k
    ns1 = arg1->nodesetval;
5451
72.5k
    ns2 = arg2->nodesetval;
5452
5453
72.5k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
18.6k
  return(0);
5455
53.9k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
13.2k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
40.6k
    if (neq == 0)
5462
428k
  for (i = 0;i < ns1->nodeNr;i++)
5463
972k
      for (j = 0;j < ns2->nodeNr;j++)
5464
573k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
3.89k
        return(1);
5466
5467
36.7k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
36.7k
    if (values1 == NULL) {
5469
5
        xmlXPathPErrMemory(ctxt);
5470
5
  return(0);
5471
5
    }
5472
36.7k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
36.7k
    if (hashs1 == NULL) {
5474
4
        xmlXPathPErrMemory(ctxt);
5475
4
  xmlFree(values1);
5476
4
  return(0);
5477
4
    }
5478
36.7k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
36.7k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
36.7k
    if (values2 == NULL) {
5481
9
        xmlXPathPErrMemory(ctxt);
5482
9
  xmlFree(hashs1);
5483
9
  xmlFree(values1);
5484
9
  return(0);
5485
9
    }
5486
36.7k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
36.7k
    if (hashs2 == NULL) {
5488
4
        xmlXPathPErrMemory(ctxt);
5489
4
  xmlFree(hashs1);
5490
4
  xmlFree(values1);
5491
4
  xmlFree(values2);
5492
4
  return(0);
5493
4
    }
5494
36.7k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
358k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
332k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
746k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
425k
      if (i == 0)
5499
125k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
425k
      if (hashs1[i] != hashs2[j]) {
5501
408k
    if (neq) {
5502
7.91k
        ret = 1;
5503
7.91k
        break;
5504
7.91k
    }
5505
408k
      }
5506
16.6k
      else {
5507
16.6k
    if (values1[i] == NULL) {
5508
12.0k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
12.0k
                    if (values1[i] == NULL)
5510
19
                        xmlXPathPErrMemory(ctxt);
5511
12.0k
                }
5512
16.6k
    if (values2[j] == NULL) {
5513
11.2k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
11.2k
                    if (values2[j] == NULL)
5515
9
                        xmlXPathPErrMemory(ctxt);
5516
11.2k
                }
5517
16.6k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
16.6k
    if (ret)
5519
3.01k
        break;
5520
16.6k
      }
5521
425k
  }
5522
332k
  if (ret)
5523
10.9k
      break;
5524
332k
    }
5525
458k
    for (i = 0;i < ns1->nodeNr;i++)
5526
421k
  if (values1[i] != NULL)
5527
12.0k
      xmlFree(values1[i]);
5528
332k
    for (j = 0;j < ns2->nodeNr;j++)
5529
296k
  if (values2[j] != NULL)
5530
11.2k
      xmlFree(values2[j]);
5531
36.7k
    xmlFree(values1);
5532
36.7k
    xmlFree(values2);
5533
36.7k
    xmlFree(hashs1);
5534
36.7k
    xmlFree(hashs2);
5535
36.7k
    return(ret);
5536
36.7k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
415k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
415k
    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
415k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
157k
        case XPATH_BOOLEAN:
5550
157k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
98.7k
    case XPATH_BOOLEAN:
5554
98.7k
        ret = (arg1->boolval == arg2->boolval);
5555
98.7k
        break;
5556
43.4k
    case XPATH_NUMBER:
5557
43.4k
        ret = (arg1->boolval ==
5558
43.4k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
43.4k
        break;
5560
15.0k
    case XPATH_STRING:
5561
15.0k
        if ((arg2->stringval == NULL) ||
5562
15.0k
      (arg2->stringval[0] == 0)) ret = 0;
5563
12.0k
        else
5564
12.0k
      ret = 1;
5565
15.0k
        ret = (arg1->boolval == ret);
5566
15.0k
        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
157k
      }
5574
157k
      break;
5575
244k
        case XPATH_NUMBER:
5576
244k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
76.2k
    case XPATH_BOOLEAN:
5580
76.2k
        ret = (arg2->boolval==
5581
76.2k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
76.2k
        break;
5583
7.77k
    case XPATH_STRING:
5584
7.77k
        xmlXPathValuePush(ctxt, arg2);
5585
7.77k
        xmlXPathNumberFunction(ctxt, 1);
5586
7.77k
        arg2 = xmlXPathValuePop(ctxt);
5587
7.77k
                    if (ctxt->error)
5588
5
                        break;
5589
                    /* Falls through. */
5590
168k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
168k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
155k
          xmlXPathIsNaN(arg2->floatval)) {
5594
28.7k
            ret = 0;
5595
139k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
3.77k
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
1.02k
          ret = 1;
5598
2.75k
      else
5599
2.75k
          ret = 0;
5600
135k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
4.06k
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
1.44k
          ret = 1;
5603
2.61k
      else
5604
2.61k
          ret = 0;
5605
131k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
1.41k
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
1.41k
      else
5609
1.41k
          ret = 0;
5610
130k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
1.04k
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
1.04k
      else
5614
1.04k
          ret = 0;
5615
129k
        } else {
5616
129k
            ret = (arg1->floatval == arg2->floatval);
5617
129k
        }
5618
168k
        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
244k
      }
5626
244k
      break;
5627
244k
        case XPATH_STRING:
5628
13.4k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
2.89k
    case XPATH_BOOLEAN:
5632
2.89k
        if ((arg1->stringval == NULL) ||
5633
2.89k
      (arg1->stringval[0] == 0)) ret = 0;
5634
1.53k
        else
5635
1.53k
      ret = 1;
5636
2.89k
        ret = (arg2->boolval == ret);
5637
2.89k
        break;
5638
1.39k
    case XPATH_STRING:
5639
1.39k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
1.39k
        break;
5641
9.16k
    case XPATH_NUMBER:
5642
9.16k
        xmlXPathValuePush(ctxt, arg1);
5643
9.16k
        xmlXPathNumberFunction(ctxt, 1);
5644
9.16k
        arg1 = xmlXPathValuePop(ctxt);
5645
9.16k
                    if (ctxt->error)
5646
10
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
9.15k
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
7.10k
          xmlXPathIsNaN(arg2->floatval)) {
5650
2.95k
            ret = 0;
5651
6.20k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
1.35k
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
506
          ret = 1;
5654
848
      else
5655
848
          ret = 0;
5656
4.85k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
1.97k
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
789
          ret = 1;
5659
1.18k
      else
5660
1.18k
          ret = 0;
5661
2.87k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
1.12k
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
1.12k
      else
5665
1.12k
          ret = 0;
5666
1.75k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
567
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
567
      else
5670
567
          ret = 0;
5671
1.18k
        } else {
5672
1.18k
            ret = (arg1->floatval == arg2->floatval);
5673
1.18k
        }
5674
9.15k
        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
13.4k
      }
5682
13.4k
      break;
5683
13.4k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
415k
    }
5690
415k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
415k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
415k
    return(ret);
5693
415k
}
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
595k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
595k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
595k
    int ret = 0;
5705
5706
595k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
595k
    arg2 = xmlXPathValuePop(ctxt);
5708
595k
    arg1 = xmlXPathValuePop(ctxt);
5709
595k
    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
595k
    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
595k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
419k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
222k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
116k
    argtmp = arg2;
5732
116k
    arg2 = arg1;
5733
116k
    arg1 = argtmp;
5734
116k
  }
5735
222k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
59.0k
      case XPATH_NODESET:
5739
59.0k
      case XPATH_XSLT_TREE:
5740
59.0k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
59.0k
    break;
5742
104k
      case XPATH_BOOLEAN:
5743
104k
    if ((arg1->nodesetval == NULL) ||
5744
104k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
43.9k
    else
5746
43.9k
        ret = 1;
5747
104k
    ret = (ret == arg2->boolval);
5748
104k
    break;
5749
46.6k
      case XPATH_NUMBER:
5750
46.6k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
46.6k
    break;
5752
12.1k
      case XPATH_STRING:
5753
12.1k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
12.1k
                                                 arg2->stringval, 0);
5755
12.1k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
222k
  }
5760
222k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
222k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
222k
  return(ret);
5763
222k
    }
5764
5765
372k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
595k
}
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
86.8k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
86.8k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
86.8k
    int ret = 0;
5778
5779
86.8k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
86.8k
    arg2 = xmlXPathValuePop(ctxt);
5781
86.8k
    arg1 = xmlXPathValuePop(ctxt);
5782
86.8k
    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
86.8k
    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
86.8k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
58.3k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
44.3k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
14.9k
    argtmp = arg2;
5805
14.9k
    arg2 = arg1;
5806
14.9k
    arg1 = argtmp;
5807
14.9k
  }
5808
44.3k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
13.5k
      case XPATH_NODESET:
5812
13.5k
      case XPATH_XSLT_TREE:
5813
13.5k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
13.5k
    break;
5815
13.8k
      case XPATH_BOOLEAN:
5816
13.8k
    if ((arg1->nodesetval == NULL) ||
5817
13.8k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
5.01k
    else
5819
5.01k
        ret = 1;
5820
13.8k
    ret = (ret != arg2->boolval);
5821
13.8k
    break;
5822
11.8k
      case XPATH_NUMBER:
5823
11.8k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
11.8k
    break;
5825
5.20k
      case XPATH_STRING:
5826
5.20k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
5.20k
                                                 arg2->stringval, 1);
5828
5.20k
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
44.3k
  }
5833
44.3k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
44.3k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
44.3k
  return(ret);
5836
44.3k
    }
5837
5838
42.4k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
86.8k
}
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
798k
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
798k
    int ret = 0, arg1i = 0, arg2i = 0;
5866
798k
    xmlXPathObjectPtr arg1, arg2;
5867
5868
798k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
798k
    arg2 = xmlXPathValuePop(ctxt);
5870
798k
    arg1 = xmlXPathValuePop(ctxt);
5871
798k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
30
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
30
  else
5875
30
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
30
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
798k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
524k
      (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
302k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
273k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
128k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
174k
  } else {
5890
174k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
29.1k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
29.1k
                                arg1, arg2);
5893
145k
      } else {
5894
145k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
145k
                                arg2, arg1);
5896
145k
      }
5897
174k
  }
5898
302k
  return(ret);
5899
302k
    }
5900
5901
495k
    if (arg1->type != XPATH_NUMBER) {
5902
50.4k
  xmlXPathValuePush(ctxt, arg1);
5903
50.4k
  xmlXPathNumberFunction(ctxt, 1);
5904
50.4k
  arg1 = xmlXPathValuePop(ctxt);
5905
50.4k
    }
5906
495k
    if (arg2->type != XPATH_NUMBER) {
5907
43.8k
  xmlXPathValuePush(ctxt, arg2);
5908
43.8k
  xmlXPathNumberFunction(ctxt, 1);
5909
43.8k
  arg2 = xmlXPathValuePop(ctxt);
5910
43.8k
    }
5911
495k
    if (ctxt->error)
5912
1.71k
        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
493k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
425k
  ret=0;
5920
425k
    } else {
5921
68.2k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
68.2k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
68.2k
  if (inf && strict) {
5924
27.3k
      if ((arg1i == -1 && arg2i != -1) ||
5925
26.1k
    (arg2i == 1 && arg1i != 1)) {
5926
2.38k
    ret = 1;
5927
24.9k
      } else if (arg1i == 0 && arg2i == 0) {
5928
21.1k
    ret = (arg1->floatval < arg2->floatval);
5929
21.1k
      } else {
5930
3.79k
    ret = 0;
5931
3.79k
      }
5932
27.3k
  }
5933
40.8k
  else if (inf && !strict) {
5934
9.19k
      if (arg1i == -1 || arg2i == 1) {
5935
3.13k
    ret = 1;
5936
6.06k
      } else if (arg1i == 0 && arg2i == 0) {
5937
3.50k
    ret = (arg1->floatval <= arg2->floatval);
5938
3.50k
      } else {
5939
2.56k
    ret = 0;
5940
2.56k
      }
5941
9.19k
  }
5942
31.6k
  else if (!inf && strict) {
5943
21.0k
      if ((arg1i == 1 && arg2i != 1) ||
5944
19.5k
    (arg2i == -1 && arg1i != -1)) {
5945
2.84k
    ret = 1;
5946
18.2k
      } else if (arg1i == 0 && arg2i == 0) {
5947
14.1k
    ret = (arg1->floatval > arg2->floatval);
5948
14.1k
      } else {
5949
4.10k
    ret = 0;
5950
4.10k
      }
5951
21.0k
  }
5952
10.6k
  else if (!inf && !strict) {
5953
10.6k
      if (arg1i == 1 || arg2i == -1) {
5954
4.58k
    ret = 1;
5955
6.02k
      } else if (arg1i == 0 && arg2i == 0) {
5956
3.96k
    ret = (arg1->floatval >= arg2->floatval);
5957
3.96k
      } else {
5958
2.06k
    ret = 0;
5959
2.06k
      }
5960
10.6k
  }
5961
68.2k
    }
5962
495k
error:
5963
495k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
495k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
495k
    return(ret);
5966
493k
}
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
234k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
234k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
234k
    CAST_TO_NUMBER;
5979
234k
    CHECK_TYPE(XPATH_NUMBER);
5980
234k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
234k
}
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
95.8k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
95.8k
    xmlXPathObjectPtr arg;
5993
95.8k
    double val;
5994
5995
95.8k
    arg = xmlXPathValuePop(ctxt);
5996
95.8k
    if (arg == NULL)
5997
95.8k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
95.8k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
95.8k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
95.8k
    CAST_TO_NUMBER;
6001
95.8k
    CHECK_TYPE(XPATH_NUMBER);
6002
95.8k
    ctxt->value->floatval += val;
6003
95.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
172k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
172k
    xmlXPathObjectPtr arg;
6015
172k
    double val;
6016
6017
172k
    arg = xmlXPathValuePop(ctxt);
6018
172k
    if (arg == NULL)
6019
172k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
172k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
172k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
172k
    CAST_TO_NUMBER;
6023
172k
    CHECK_TYPE(XPATH_NUMBER);
6024
172k
    ctxt->value->floatval -= val;
6025
172k
}
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
694k
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
694k
    xmlXPathObjectPtr arg;
6037
694k
    double val;
6038
6039
694k
    arg = xmlXPathValuePop(ctxt);
6040
694k
    if (arg == NULL)
6041
694k
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
694k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
694k
    xmlXPathReleaseObject(ctxt->context, arg);
6044
694k
    CAST_TO_NUMBER;
6045
694k
    CHECK_TYPE(XPATH_NUMBER);
6046
694k
    ctxt->value->floatval *= val;
6047
694k
}
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
8.76k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
8.76k
    xmlXPathObjectPtr arg;
6060
8.76k
    double val;
6061
6062
8.76k
    arg = xmlXPathValuePop(ctxt);
6063
8.76k
    if (arg == NULL)
6064
8.76k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
8.76k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
8.76k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
8.76k
    CAST_TO_NUMBER;
6068
8.76k
    CHECK_TYPE(XPATH_NUMBER);
6069
8.75k
    ctxt->value->floatval /= val;
6070
8.75k
}
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
3.96k
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
3.96k
    xmlXPathObjectPtr arg;
6082
3.96k
    double arg1, arg2;
6083
6084
3.96k
    arg = xmlXPathValuePop(ctxt);
6085
3.96k
    if (arg == NULL)
6086
3.96k
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
3.96k
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
3.96k
    xmlXPathReleaseObject(ctxt->context, arg);
6089
3.96k
    CAST_TO_NUMBER;
6090
3.96k
    CHECK_TYPE(XPATH_NUMBER);
6091
3.95k
    arg1 = ctxt->value->floatval;
6092
3.95k
    if (arg2 == 0)
6093
940
  ctxt->value->floatval = xmlXPathNAN;
6094
3.01k
    else {
6095
3.01k
  ctxt->value->floatval = fmod(arg1, arg2);
6096
3.01k
    }
6097
3.95k
}
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
5.58k
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
5.58k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
5.58k
    if (cur == NULL)
6141
3.08k
        return(ctxt->context->node);
6142
2.49k
    return(NULL);
6143
5.58k
}
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
3.83M
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
3.83M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
3.83M
    if (cur == NULL) {
6157
1.91M
  if (ctxt->context->node == NULL) return(NULL);
6158
1.91M
  switch (ctxt->context->node->type) {
6159
1.32M
            case XML_ELEMENT_NODE:
6160
1.80M
            case XML_TEXT_NODE:
6161
1.84M
            case XML_CDATA_SECTION_NODE:
6162
1.84M
            case XML_ENTITY_REF_NODE:
6163
1.84M
            case XML_ENTITY_NODE:
6164
1.85M
            case XML_PI_NODE:
6165
1.86M
            case XML_COMMENT_NODE:
6166
1.86M
            case XML_NOTATION_NODE:
6167
1.86M
            case XML_DTD_NODE:
6168
1.86M
    return(ctxt->context->node->children);
6169
25.0k
            case XML_DOCUMENT_NODE:
6170
25.0k
            case XML_DOCUMENT_TYPE_NODE:
6171
25.0k
            case XML_DOCUMENT_FRAG_NODE:
6172
25.0k
            case XML_HTML_DOCUMENT_NODE:
6173
25.0k
    return(((xmlDocPtr) ctxt->context->node)->children);
6174
0
      case XML_ELEMENT_DECL:
6175
0
      case XML_ATTRIBUTE_DECL:
6176
0
      case XML_ENTITY_DECL:
6177
512
            case XML_ATTRIBUTE_NODE:
6178
20.9k
      case XML_NAMESPACE_DECL:
6179
20.9k
      case XML_XINCLUDE_START:
6180
20.9k
      case XML_XINCLUDE_END:
6181
20.9k
    return(NULL);
6182
1.91M
  }
6183
0
  return(NULL);
6184
1.91M
    }
6185
1.92M
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
1.92M
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
1.92M
    return(cur->next);
6189
1.92M
}
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
6.06M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
6.06M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
6.06M
    if (cur == NULL) {
6203
3.31M
  cur = ctxt->context->node;
6204
3.31M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
3.31M
  switch (cur->type) {
6209
1.95M
            case XML_ELEMENT_NODE:
6210
1.95M
      case XML_DOCUMENT_FRAG_NODE:
6211
1.95M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
1.95M
            case XML_ENTITY_NODE:
6213
1.95M
    cur = cur->children;
6214
1.95M
    if (cur != NULL) {
6215
752k
        if (cur->type == XML_ELEMENT_NODE)
6216
453k
      return(cur);
6217
314k
        do {
6218
314k
      cur = cur->next;
6219
314k
        } while ((cur != NULL) &&
6220
202k
      (cur->type != XML_ELEMENT_NODE));
6221
299k
        return(cur);
6222
752k
    }
6223
1.20M
    return(NULL);
6224
731k
            case XML_DOCUMENT_NODE:
6225
731k
            case XML_HTML_DOCUMENT_NODE:
6226
731k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
627k
      default:
6228
627k
    return(NULL);
6229
3.31M
  }
6230
0
  return(NULL);
6231
3.31M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
2.74M
    switch (cur->type) {
6236
2.74M
  case XML_ELEMENT_NODE:
6237
2.74M
  case XML_TEXT_NODE:
6238
2.74M
  case XML_ENTITY_REF_NODE:
6239
2.74M
  case XML_ENTITY_NODE:
6240
2.74M
  case XML_CDATA_SECTION_NODE:
6241
2.74M
  case XML_PI_NODE:
6242
2.74M
  case XML_COMMENT_NODE:
6243
2.74M
  case XML_XINCLUDE_END:
6244
2.74M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
2.74M
    }
6249
2.74M
    if (cur->next != NULL) {
6250
1.55M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
1.21M
      return(cur->next);
6252
339k
  cur = cur->next;
6253
350k
  do {
6254
350k
      cur = cur->next;
6255
350k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
339k
  return(cur);
6257
1.55M
    }
6258
1.19M
    return(NULL);
6259
2.74M
}
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
54.9M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
54.9M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
54.9M
    if (cur == NULL) {
6274
248k
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
248k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
247k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
9.71k
      return(NULL);
6279
6280
238k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
77.6k
      return(ctxt->context->doc->children);
6282
160k
        return(ctxt->context->node->children);
6283
238k
    }
6284
6285
54.7M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
54.7M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
6.52M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
6.51M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
6.51M
      if (cur->type != XML_DTD_NODE)
6297
6.49M
    return(cur);
6298
6.51M
  }
6299
6.52M
    }
6300
6301
48.2M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
46.8M
    while (cur->next != NULL) {
6304
45.3M
  cur = cur->next;
6305
45.3M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
45.3M
      (cur->type != XML_DTD_NODE))
6307
45.3M
      return(cur);
6308
45.3M
    }
6309
6310
6.42M
    do {
6311
6.42M
        cur = cur->parent;
6312
6.42M
  if (cur == NULL) break;
6313
6.42M
  if (cur == ctxt->context->node) return(NULL);
6314
5.69M
  if (cur->next != NULL) {
6315
710k
      cur = cur->next;
6316
710k
      return(cur);
6317
710k
  }
6318
5.69M
    } while (cur != NULL);
6319
0
    return(cur);
6320
1.44M
}
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
53.7M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
53.7M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
53.7M
    if (cur == NULL)
6337
2.10M
        return(ctxt->context->node);
6338
6339
51.6M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
51.6M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
51.6M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
34.8k
        return(NULL);
6344
6345
51.6M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
51.6M
}
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
501k
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
501k
    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
501k
    if (cur == NULL) {
6365
273k
  if (ctxt->context->node == NULL) return(NULL);
6366
273k
  switch (ctxt->context->node->type) {
6367
178k
            case XML_ELEMENT_NODE:
6368
244k
            case XML_TEXT_NODE:
6369
245k
            case XML_CDATA_SECTION_NODE:
6370
245k
            case XML_ENTITY_REF_NODE:
6371
245k
            case XML_ENTITY_NODE:
6372
247k
            case XML_PI_NODE:
6373
248k
            case XML_COMMENT_NODE:
6374
248k
            case XML_NOTATION_NODE:
6375
248k
            case XML_DTD_NODE:
6376
248k
      case XML_ELEMENT_DECL:
6377
248k
      case XML_ATTRIBUTE_DECL:
6378
248k
      case XML_XINCLUDE_START:
6379
248k
      case XML_XINCLUDE_END:
6380
248k
      case XML_ENTITY_DECL:
6381
248k
    if (ctxt->context->node->parent == NULL)
6382
69
        return((xmlNodePtr) ctxt->context->doc);
6383
248k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
231k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
231k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
231k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
248k
    return(ctxt->context->node->parent);
6389
989
            case XML_ATTRIBUTE_NODE: {
6390
989
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
989
    return(att->parent);
6393
248k
      }
6394
22.3k
            case XML_DOCUMENT_NODE:
6395
22.3k
            case XML_DOCUMENT_TYPE_NODE:
6396
22.3k
            case XML_DOCUMENT_FRAG_NODE:
6397
22.3k
            case XML_HTML_DOCUMENT_NODE:
6398
22.3k
                return(NULL);
6399
1.27k
      case XML_NAMESPACE_DECL: {
6400
1.27k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
1.27k
    if ((ns->next != NULL) &&
6403
1.27k
        (ns->next->type != XML_NAMESPACE_DECL))
6404
1.27k
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
1.27k
      }
6407
273k
  }
6408
273k
    }
6409
228k
    return(NULL);
6410
501k
}
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
1.05M
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
1.05M
    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
1.05M
    if (cur == NULL) {
6433
83.3k
  if (ctxt->context->node == NULL) return(NULL);
6434
83.3k
  switch (ctxt->context->node->type) {
6435
63.5k
            case XML_ELEMENT_NODE:
6436
75.3k
            case XML_TEXT_NODE:
6437
76.0k
            case XML_CDATA_SECTION_NODE:
6438
76.0k
            case XML_ENTITY_REF_NODE:
6439
76.0k
            case XML_ENTITY_NODE:
6440
77.1k
            case XML_PI_NODE:
6441
77.8k
            case XML_COMMENT_NODE:
6442
77.8k
      case XML_DTD_NODE:
6443
77.8k
      case XML_ELEMENT_DECL:
6444
77.8k
      case XML_ATTRIBUTE_DECL:
6445
77.8k
      case XML_ENTITY_DECL:
6446
77.8k
            case XML_NOTATION_NODE:
6447
77.8k
      case XML_XINCLUDE_START:
6448
77.8k
      case XML_XINCLUDE_END:
6449
77.8k
    if (ctxt->context->node->parent == NULL)
6450
18
        return((xmlNodePtr) ctxt->context->doc);
6451
77.8k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
73.4k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
73.4k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
73.4k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
77.8k
    return(ctxt->context->node->parent);
6457
1.14k
            case XML_ATTRIBUTE_NODE: {
6458
1.14k
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
1.14k
    return(tmp->parent);
6461
77.8k
      }
6462
3.44k
            case XML_DOCUMENT_NODE:
6463
3.44k
            case XML_DOCUMENT_TYPE_NODE:
6464
3.44k
            case XML_DOCUMENT_FRAG_NODE:
6465
3.44k
            case XML_HTML_DOCUMENT_NODE:
6466
3.44k
                return(NULL);
6467
889
      case XML_NAMESPACE_DECL: {
6468
889
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
889
    if ((ns->next != NULL) &&
6471
889
        (ns->next->type != XML_NAMESPACE_DECL))
6472
889
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
889
      }
6476
83.3k
  }
6477
0
  return(NULL);
6478
83.3k
    }
6479
971k
    if (cur == ctxt->context->doc->children)
6480
69.8k
  return((xmlNodePtr) ctxt->context->doc);
6481
901k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
148k
  return(NULL);
6483
753k
    switch (cur->type) {
6484
712k
  case XML_ELEMENT_NODE:
6485
733k
  case XML_TEXT_NODE:
6486
733k
  case XML_CDATA_SECTION_NODE:
6487
733k
  case XML_ENTITY_REF_NODE:
6488
733k
  case XML_ENTITY_NODE:
6489
737k
  case XML_PI_NODE:
6490
739k
  case XML_COMMENT_NODE:
6491
739k
  case XML_NOTATION_NODE:
6492
745k
  case XML_DTD_NODE:
6493
745k
        case XML_ELEMENT_DECL:
6494
745k
        case XML_ATTRIBUTE_DECL:
6495
751k
        case XML_ENTITY_DECL:
6496
751k
  case XML_XINCLUDE_START:
6497
751k
  case XML_XINCLUDE_END:
6498
751k
      if (cur->parent == NULL)
6499
84
    return(NULL);
6500
751k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
670k
    ((cur->parent->name[0] == ' ') ||
6502
670k
     (xmlStrEqual(cur->parent->name,
6503
670k
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
751k
      return(cur->parent);
6506
398
  case XML_ATTRIBUTE_NODE: {
6507
398
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
398
      return(att->parent);
6510
751k
  }
6511
1.09k
  case XML_NAMESPACE_DECL: {
6512
1.09k
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
1.09k
      if ((ns->next != NULL) &&
6515
1.09k
          (ns->next->type != XML_NAMESPACE_DECL))
6516
1.09k
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
1.09k
  }
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
753k
    }
6526
0
    return(NULL);
6527
753k
}
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
687k
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
687k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
687k
    if (cur == NULL)
6544
69.4k
        return(ctxt->context->node);
6545
618k
    return(xmlXPathNextAncestor(ctxt, cur));
6546
687k
}
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
16.5k
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
16.5k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
16.5k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
16.2k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
972
        return(NULL);
6563
6564
15.5k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6565
0
        return(NULL);
6566
6567
15.5k
    if (cur == NULL)
6568
3.52k
        cur = ctxt->context->node;
6569
6570
15.5k
    if (cur->type == XML_DOCUMENT_NODE)
6571
1.04k
        return(NULL);
6572
6573
14.5k
    return(cur->next);
6574
15.5k
}
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
58.0k
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6588
58.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589
58.0k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6590
57.6k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6591
1.23k
        return(NULL);
6592
6593
56.7k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6594
0
        return(NULL);
6595
6596
56.7k
    if (cur == NULL) {
6597
12.4k
        cur = ctxt->context->node;
6598
44.3k
    } else if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6599
304
        cur = cur->prev;
6600
304
        if (cur == NULL)
6601
0
            cur = ctxt->context->node;
6602
304
    }
6603
6604
56.7k
    if (cur->type == XML_DOCUMENT_NODE)
6605
912
        return(NULL);
6606
6607
55.8k
    return(cur->prev);
6608
56.7k
}
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
5.15M
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6623
5.15M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6624
5.15M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6625
5.12M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6626
1.75M
        return(cur->children);
6627
6628
3.39M
    if (cur == NULL) {
6629
25.2k
        cur = ctxt->context->node;
6630
25.2k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6631
396
            cur = cur->parent;
6632
24.8k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6633
1.99k
            xmlNsPtr ns = (xmlNsPtr) cur;
6634
6635
1.99k
            if ((ns->next == NULL) ||
6636
1.99k
                (ns->next->type == XML_NAMESPACE_DECL))
6637
0
                return (NULL);
6638
1.99k
            cur = (xmlNodePtr) ns->next;
6639
1.99k
        }
6640
25.2k
    }
6641
6642
    /* ERROR */
6643
3.39M
    if (cur == NULL)
6644
0
        return(NULL);
6645
6646
3.39M
    if (cur->type == XML_DOCUMENT_NODE)
6647
1.75k
        return(NULL);
6648
6649
3.39M
    if (cur->next != NULL)
6650
2.84M
        return(cur->next);
6651
6652
1.01M
    do {
6653
1.01M
        cur = cur->parent;
6654
1.01M
        if (cur == NULL)
6655
0
            break;
6656
1.01M
        if (cur == (xmlNodePtr) ctxt->context->doc)
6657
23.4k
            return(NULL);
6658
990k
        if (cur->next != NULL && cur->type != XML_DOCUMENT_NODE)
6659
526k
            return(cur->next);
6660
990k
    } while (cur != NULL);
6661
6662
0
    return(cur);
6663
549k
}
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
2.75M
{
6757
2.75M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6758
2.75M
    if (cur == NULL) {
6759
39.5k
        cur = ctxt->context->node;
6760
39.5k
        if (cur == NULL)
6761
0
            return (NULL);
6762
39.5k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6763
501
            cur = cur->parent;
6764
39.0k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6765
1.14k
            xmlNsPtr ns = (xmlNsPtr) cur;
6766
6767
1.14k
            if ((ns->next == NULL) ||
6768
1.14k
                (ns->next->type == XML_NAMESPACE_DECL))
6769
0
                return (NULL);
6770
1.14k
            cur = (xmlNodePtr) ns->next;
6771
1.14k
        }
6772
39.5k
        ctxt->ancestor = cur->parent;
6773
39.5k
    }
6774
6775
2.75M
    if (cur->type == XML_NAMESPACE_DECL || cur->type == XML_DOCUMENT_NODE)
6776
2.14k
        return(NULL);
6777
6778
2.75M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6779
1.72k
  cur = cur->prev;
6780
6781
3.00M
    while (cur->prev == NULL) {
6782
531k
        cur = cur->parent;
6783
531k
        if (cur == NULL)
6784
6.01k
            return (NULL);
6785
525k
        if (cur == ctxt->context->doc->children)
6786
31.0k
            return (NULL);
6787
494k
        if (cur != ctxt->ancestor)
6788
235k
            return (cur);
6789
258k
        ctxt->ancestor = cur->parent;
6790
258k
    }
6791
6792
2.47M
    if (cur->type == XML_DOCUMENT_NODE)
6793
0
        return(NULL);
6794
6795
2.47M
    cur = cur->prev;
6796
2.73M
    while (cur->last != NULL)
6797
257k
        cur = cur->last;
6798
2.47M
    return (cur);
6799
2.47M
}
6800
6801
/**
6802
 * Traversal function for the "namespace" direction
6803
 * the namespace axis contains the namespace nodes of the context node;
6804
 * the order of nodes on this axis is implementation-defined; the axis will
6805
 * be empty unless the context node is an element
6806
 *
6807
 * We keep the XML namespace node at the end of the list.
6808
 *
6809
 * @param ctxt  the XPath Parser context
6810
 * @param cur  the current attribute in the traversal
6811
 * @returns the next element following that axis
6812
 */
6813
xmlNode *
6814
3.93M
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6815
3.93M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6816
3.93M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6817
3.77M
    if (cur == NULL) {
6818
605k
        if (ctxt->context->tmpNsList != NULL)
6819
1.56k
      xmlFree(ctxt->context->tmpNsList);
6820
605k
  ctxt->context->tmpNsNr = 0;
6821
605k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6822
605k
                             &ctxt->context->tmpNsList) < 0) {
6823
11
            xmlXPathPErrMemory(ctxt);
6824
11
            return(NULL);
6825
11
        }
6826
605k
        if (ctxt->context->tmpNsList != NULL) {
6827
3.12M
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6828
2.57M
                ctxt->context->tmpNsNr++;
6829
2.57M
            }
6830
547k
        }
6831
605k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6832
605k
    }
6833
3.17M
    if (ctxt->context->tmpNsNr > 0) {
6834
2.57M
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6835
2.57M
    } else {
6836
599k
  if (ctxt->context->tmpNsList != NULL)
6837
545k
      xmlFree(ctxt->context->tmpNsList);
6838
599k
  ctxt->context->tmpNsList = NULL;
6839
599k
  return(NULL);
6840
599k
    }
6841
3.17M
}
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
699k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6853
699k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854
699k
    if (ctxt->context->node == NULL)
6855
0
  return(NULL);
6856
699k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6857
168k
  return(NULL);
6858
530k
    if (cur == NULL) {
6859
473k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6860
0
      return(NULL);
6861
473k
        return((xmlNodePtr)ctxt->context->node->properties);
6862
473k
    }
6863
57.4k
    return((xmlNodePtr)cur->next);
6864
530k
}
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
2.89M
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6888
2.89M
    if ((ctxt == NULL) || (ctxt->context == NULL))
6889
0
  return;
6890
2.89M
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6891
2.89M
                                            (xmlNodePtr) ctxt->context->doc));
6892
2.89M
}
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
323k
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6912
970k
    CHECK_ARITY(0);
6913
970k
    if (ctxt->context->contextSize >= 0) {
6914
323k
  xmlXPathValuePush(ctxt,
6915
323k
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6916
323k
    } else {
6917
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6918
0
    }
6919
970k
}
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
165k
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6933
495k
    CHECK_ARITY(0);
6934
495k
    if (ctxt->context->proximityPosition >= 0) {
6935
165k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6936
165k
            (double) ctxt->context->proximityPosition));
6937
165k
    } else {
6938
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6939
0
    }
6940
495k
}
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
2.05k
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6951
2.05k
    xmlXPathObjectPtr cur;
6952
6953
6.12k
    CHECK_ARITY(1);
6954
6.12k
    if ((ctxt->value == NULL) ||
6955
2.03k
  ((ctxt->value->type != XPATH_NODESET) &&
6956
56
   (ctxt->value->type != XPATH_XSLT_TREE)))
6957
1.97k
  XP_ERROR(XPATH_INVALID_TYPE);
6958
1.97k
    cur = xmlXPathValuePop(ctxt);
6959
6960
1.97k
    if ((cur == NULL) || (cur->nodesetval == NULL))
6961
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6962
1.97k
    else
6963
1.97k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6964
1.97k
      (double) cur->nodesetval->nodeNr));
6965
1.97k
    xmlXPathReleaseObject(ctxt->context, cur);
6966
1.97k
}
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.36M
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6977
1.36M
    xmlNodeSetPtr ret;
6978
1.36M
    const xmlChar *cur = ids;
6979
1.36M
    xmlChar *ID;
6980
1.36M
    xmlAttrPtr attr;
6981
1.36M
    xmlNodePtr elem = NULL;
6982
6983
1.36M
    if (ids == NULL) return(NULL);
6984
6985
1.36M
    ret = xmlXPathNodeSetCreate(NULL);
6986
1.36M
    if (ret == NULL)
6987
32
        return(ret);
6988
6989
1.36M
    while (IS_BLANK_CH(*cur)) cur++;
6990
17.7M
    while (*cur != 0) {
6991
187M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6992
171M
      cur++;
6993
6994
16.4M
        ID = xmlStrndup(ids, cur - ids);
6995
16.4M
  if (ID == NULL) {
6996
76
            xmlXPathFreeNodeSet(ret);
6997
76
            return(NULL);
6998
76
        }
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
16.4M
        attr = xmlGetID(doc, ID);
7007
16.4M
        xmlFree(ID);
7008
16.4M
        if (attr != NULL) {
7009
22.0k
            if (attr->type == XML_ATTRIBUTE_NODE)
7010
22.0k
                elem = attr->parent;
7011
0
            else if (attr->type == XML_ELEMENT_NODE)
7012
0
                elem = (xmlNodePtr) attr;
7013
0
            else
7014
0
                elem = NULL;
7015
22.0k
            if (elem != NULL) {
7016
22.0k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7017
12
                    xmlXPathFreeNodeSet(ret);
7018
12
                    return(NULL);
7019
12
                }
7020
22.0k
            }
7021
22.0k
        }
7022
7023
16.4M
  while (IS_BLANK_CH(*cur)) cur++;
7024
16.4M
  ids = cur;
7025
16.4M
    }
7026
1.36M
    return(ret);
7027
1.36M
}
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
63.4k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7048
63.4k
    xmlChar *tokens;
7049
63.4k
    xmlNodeSetPtr ret;
7050
63.4k
    xmlXPathObjectPtr obj;
7051
7052
189k
    CHECK_ARITY(1);
7053
189k
    obj = xmlXPathValuePop(ctxt);
7054
189k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7055
63.2k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7056
21.2k
  xmlNodeSetPtr ns;
7057
21.2k
  int i;
7058
7059
21.2k
  ret = xmlXPathNodeSetCreate(NULL);
7060
21.2k
        if (ret == NULL)
7061
11
            xmlXPathPErrMemory(ctxt);
7062
7063
21.2k
  if (obj->nodesetval != NULL) {
7064
1.34M
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7065
1.32M
    tokens =
7066
1.32M
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7067
1.32M
                if (tokens == NULL)
7068
16
                    xmlXPathPErrMemory(ctxt);
7069
1.32M
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7070
1.32M
                if (ns == NULL)
7071
90
                    xmlXPathPErrMemory(ctxt);
7072
1.32M
    ret = xmlXPathNodeSetMerge(ret, ns);
7073
1.32M
                if (ret == NULL)
7074
3
                    xmlXPathPErrMemory(ctxt);
7075
1.32M
    xmlXPathFreeNodeSet(ns);
7076
1.32M
    if (tokens != NULL)
7077
1.32M
        xmlFree(tokens);
7078
1.32M
      }
7079
21.2k
  }
7080
21.2k
  xmlXPathReleaseObject(ctxt->context, obj);
7081
21.2k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7082
21.2k
  return;
7083
21.2k
    }
7084
41.9k
    tokens = xmlXPathCastToString(obj);
7085
41.9k
    if (tokens == NULL)
7086
21
        xmlXPathPErrMemory(ctxt);
7087
41.9k
    xmlXPathReleaseObject(ctxt->context, obj);
7088
41.9k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7089
41.9k
    if (ret == NULL)
7090
67
        xmlXPathPErrMemory(ctxt);
7091
41.9k
    xmlFree(tokens);
7092
41.9k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7093
41.9k
}
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
12.4k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7109
12.4k
    xmlXPathObjectPtr cur;
7110
7111
12.4k
    if (ctxt == NULL) return;
7112
7113
12.4k
    if (nargs == 0) {
7114
1.45k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7115
1.45k
  nargs = 1;
7116
1.45k
    }
7117
7118
37.1k
    CHECK_ARITY(1);
7119
37.1k
    if ((ctxt->value == NULL) ||
7120
12.3k
  ((ctxt->value->type != XPATH_NODESET) &&
7121
16
   (ctxt->value->type != XPATH_XSLT_TREE)))
7122
12.3k
  XP_ERROR(XPATH_INVALID_TYPE);
7123
12.3k
    cur = xmlXPathValuePop(ctxt);
7124
7125
12.3k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7126
548
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7127
11.8k
    } else {
7128
11.8k
  int i = 0; /* Should be first in document order !!!!! */
7129
11.8k
  switch (cur->nodesetval->nodeTab[i]->type) {
7130
636
  case XML_ELEMENT_NODE:
7131
831
  case XML_ATTRIBUTE_NODE:
7132
2.81k
  case XML_PI_NODE:
7133
2.81k
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7134
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7135
2.81k
      else
7136
2.81k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7137
2.81k
      cur->nodesetval->nodeTab[i]->name));
7138
2.81k
      break;
7139
2.31k
  case XML_NAMESPACE_DECL:
7140
2.31k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7141
2.31k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7142
2.31k
      break;
7143
6.69k
  default:
7144
6.69k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7145
11.8k
  }
7146
11.8k
    }
7147
12.3k
    xmlXPathReleaseObject(ctxt->context, cur);
7148
12.3k
}
7149
7150
/**
7151
 * Implement the namespace-uri() XPath function
7152
 *    string namespace-uri(node-set?)
7153
 * The namespace-uri function returns a string containing the
7154
 * namespace URI of the expanded name of the node in the argument
7155
 * node-set that is first in document order. If the node-set is empty,
7156
 * the first node has no name, or the expanded name has no namespace
7157
 * URI, an empty string is returned. If the argument is omitted it
7158
 * defaults to the context node.
7159
 *
7160
 * @param ctxt  the XPath Parser context
7161
 * @param nargs  the number of arguments
7162
 */
7163
void
7164
1.96k
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7165
1.96k
    xmlXPathObjectPtr cur;
7166
7167
1.96k
    if (ctxt == NULL) return;
7168
7169
1.96k
    if (nargs == 0) {
7170
1.12k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7171
1.12k
  nargs = 1;
7172
1.12k
    }
7173
5.89k
    CHECK_ARITY(1);
7174
5.89k
    if ((ctxt->value == NULL) ||
7175
1.96k
  ((ctxt->value->type != XPATH_NODESET) &&
7176
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7177
1.96k
  XP_ERROR(XPATH_INVALID_TYPE);
7178
1.96k
    cur = xmlXPathValuePop(ctxt);
7179
7180
1.96k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7181
589
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7182
1.37k
    } else {
7183
1.37k
  int i = 0; /* Should be first in document order !!!!! */
7184
1.37k
  switch (cur->nodesetval->nodeTab[i]->type) {
7185
869
  case XML_ELEMENT_NODE:
7186
869
  case XML_ATTRIBUTE_NODE:
7187
869
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7188
668
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7189
201
      else
7190
201
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7191
201
        cur->nodesetval->nodeTab[i]->ns->href));
7192
869
      break;
7193
506
  default:
7194
506
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7195
1.37k
  }
7196
1.37k
    }
7197
1.96k
    xmlXPathReleaseObject(ctxt->context, cur);
7198
1.96k
}
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
31.8k
{
7224
31.8k
    xmlXPathObjectPtr cur;
7225
7226
31.8k
    if (nargs == 0) {
7227
25.0k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7228
25.0k
        nargs = 1;
7229
25.0k
    }
7230
7231
95.2k
    CHECK_ARITY(1);
7232
95.2k
    if ((ctxt->value == NULL) ||
7233
31.7k
        ((ctxt->value->type != XPATH_NODESET) &&
7234
15
         (ctxt->value->type != XPATH_XSLT_TREE)))
7235
31.7k
        XP_ERROR(XPATH_INVALID_TYPE);
7236
31.7k
    cur = xmlXPathValuePop(ctxt);
7237
7238
31.7k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7239
2.91k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7240
28.8k
    } else {
7241
28.8k
        int i = 0;              /* Should be first in document order !!!!! */
7242
7243
28.8k
        switch (cur->nodesetval->nodeTab[i]->type) {
7244
18.5k
            case XML_ELEMENT_NODE:
7245
18.5k
            case XML_ATTRIBUTE_NODE:
7246
18.5k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7247
0
        xmlXPathValuePush(ctxt,
7248
0
      xmlXPathCacheNewCString(ctxt, ""));
7249
18.5k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7250
17.8k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7251
17.8k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7252
17.8k
          cur->nodesetval->nodeTab[i]->name));
7253
17.8k
    } else {
7254
614
        xmlChar *fullname;
7255
7256
614
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7257
614
             cur->nodesetval->nodeTab[i]->ns->prefix,
7258
614
             NULL, 0);
7259
614
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7260
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7261
614
        if (fullname == NULL)
7262
3
                        xmlXPathPErrMemory(ctxt);
7263
614
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7264
614
                }
7265
18.5k
                break;
7266
10.2k
            default:
7267
10.2k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7268
10.2k
        cur->nodesetval->nodeTab[i]));
7269
10.2k
                xmlXPathLocalNameFunction(ctxt, 1);
7270
28.8k
        }
7271
28.8k
    }
7272
31.7k
    xmlXPathReleaseObject(ctxt->context, cur);
7273
31.7k
}
7274
7275
7276
/**
7277
 * Implement the string() XPath function
7278
 *    string string(object?)
7279
 * The string function converts an object to a string as follows:
7280
 *    - A node-set is converted to a string by returning the value of
7281
 *      the node in the node-set that is first in document order.
7282
 *      If the node-set is empty, an empty string is returned.
7283
 *    - A number is converted to a string as follows
7284
 *      + NaN is converted to the string NaN
7285
 *      + positive zero is converted to the string 0
7286
 *      + negative zero is converted to the string 0
7287
 *      + positive infinity is converted to the string Infinity
7288
 *      + negative infinity is converted to the string -Infinity
7289
 *      + if the number is an integer, the number is represented in
7290
 *        decimal form as a Number with no decimal point and no leading
7291
 *        zeros, preceded by a minus sign (-) if the number is negative
7292
 *      + otherwise, the number is represented in decimal form as a
7293
 *        Number including a decimal point with at least one digit
7294
 *        before the decimal point and at least one digit after the
7295
 *        decimal point, preceded by a minus sign (-) if the number
7296
 *        is negative; there must be no leading zeros before the decimal
7297
 *        point apart possibly from the one required digit immediately
7298
 *        before the decimal point; beyond the one required digit
7299
 *        after the decimal point there must be as many, but only as
7300
 *        many, more digits as are needed to uniquely distinguish the
7301
 *        number from all other IEEE 754 numeric values.
7302
 *    - The boolean false value is converted to the string false.
7303
 *      The boolean true value is converted to the string true.
7304
 *
7305
 * If the argument is omitted, it defaults to a node-set with the
7306
 * context node as its only member.
7307
 *
7308
 * @param ctxt  the XPath Parser context
7309
 * @param nargs  the number of arguments
7310
 */
7311
void
7312
188k
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7313
188k
    xmlXPathObjectPtr cur;
7314
188k
    xmlChar *stringval;
7315
7316
188k
    if (ctxt == NULL) return;
7317
188k
    if (nargs == 0) {
7318
1.89k
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7319
1.89k
        if (stringval == NULL)
7320
3
            xmlXPathPErrMemory(ctxt);
7321
1.89k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7322
1.89k
  return;
7323
1.89k
    }
7324
7325
745k
    CHECK_ARITY(1);
7326
745k
    cur = xmlXPathValuePop(ctxt);
7327
745k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7328
186k
    if (cur->type != XPATH_STRING) {
7329
185k
        stringval = xmlXPathCastToString(cur);
7330
185k
        if (stringval == NULL)
7331
85
            xmlXPathPErrMemory(ctxt);
7332
185k
        xmlXPathReleaseObject(ctxt->context, cur);
7333
185k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7334
185k
    }
7335
186k
    xmlXPathValuePush(ctxt, cur);
7336
186k
}
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
2.76k
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7351
2.76k
    xmlXPathObjectPtr cur;
7352
7353
2.76k
    if (nargs == 0) {
7354
1.03k
        if ((ctxt == NULL) || (ctxt->context == NULL))
7355
0
      return;
7356
1.03k
  if (ctxt->context->node == NULL) {
7357
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7358
1.03k
  } else {
7359
1.03k
      xmlChar *content;
7360
7361
1.03k
      content = xmlXPathCastNodeToString(ctxt->context->node);
7362
1.03k
            if (content == NULL)
7363
3
                xmlXPathPErrMemory(ctxt);
7364
1.03k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7365
1.03k
    xmlUTF8Strlen(content)));
7366
1.03k
      xmlFree(content);
7367
1.03k
  }
7368
1.03k
  return;
7369
1.03k
    }
7370
6.86k
    CHECK_ARITY(1);
7371
6.86k
    CAST_TO_STRING;
7372
6.86k
    CHECK_TYPE(XPATH_STRING);
7373
1.70k
    cur = xmlXPathValuePop(ctxt);
7374
1.70k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7375
1.70k
  xmlUTF8Strlen(cur->stringval)));
7376
1.70k
    xmlXPathReleaseObject(ctxt->context, cur);
7377
1.70k
}
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
4.19k
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7389
4.19k
    xmlXPathObjectPtr cur, newobj;
7390
4.19k
    xmlChar *tmp;
7391
7392
4.19k
    if (ctxt == NULL) return;
7393
4.19k
    if (nargs < 2) {
7394
7
  CHECK_ARITY(2);
7395
7
    }
7396
7397
4.18k
    CAST_TO_STRING;
7398
4.18k
    cur = xmlXPathValuePop(ctxt);
7399
4.18k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7400
3
  xmlXPathReleaseObject(ctxt->context, cur);
7401
3
  return;
7402
3
    }
7403
4.18k
    nargs--;
7404
7405
16.8k
    while (nargs > 0) {
7406
12.6k
  CAST_TO_STRING;
7407
12.6k
  newobj = xmlXPathValuePop(ctxt);
7408
12.6k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7409
5
      xmlXPathReleaseObject(ctxt->context, newobj);
7410
5
      xmlXPathReleaseObject(ctxt->context, cur);
7411
5
      XP_ERROR(XPATH_INVALID_TYPE);
7412
0
  }
7413
12.6k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7414
12.6k
        if (tmp == NULL)
7415
5
            xmlXPathPErrMemory(ctxt);
7416
12.6k
  newobj->stringval = cur->stringval;
7417
12.6k
  cur->stringval = tmp;
7418
12.6k
  xmlXPathReleaseObject(ctxt->context, newobj);
7419
12.6k
  nargs--;
7420
12.6k
    }
7421
4.17k
    xmlXPathValuePush(ctxt, cur);
7422
4.17k
}
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
2.89k
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7435
2.89k
    xmlXPathObjectPtr hay, needle;
7436
7437
8.58k
    CHECK_ARITY(2);
7438
8.58k
    CAST_TO_STRING;
7439
8.58k
    CHECK_TYPE(XPATH_STRING);
7440
2.84k
    needle = xmlXPathValuePop(ctxt);
7441
2.84k
    CAST_TO_STRING;
7442
2.84k
    hay = xmlXPathValuePop(ctxt);
7443
7444
2.84k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7445
4
  xmlXPathReleaseObject(ctxt->context, hay);
7446
4
  xmlXPathReleaseObject(ctxt->context, needle);
7447
4
  XP_ERROR(XPATH_INVALID_TYPE);
7448
0
    }
7449
2.84k
    if (xmlStrstr(hay->stringval, needle->stringval))
7450
1.65k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7451
1.18k
    else
7452
1.18k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7453
2.84k
    xmlXPathReleaseObject(ctxt->context, hay);
7454
2.84k
    xmlXPathReleaseObject(ctxt->context, needle);
7455
2.84k
}
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
3.63k
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7468
3.63k
    xmlXPathObjectPtr hay, needle;
7469
3.63k
    int n;
7470
7471
10.8k
    CHECK_ARITY(2);
7472
10.8k
    CAST_TO_STRING;
7473
10.8k
    CHECK_TYPE(XPATH_STRING);
7474
3.61k
    needle = xmlXPathValuePop(ctxt);
7475
3.61k
    CAST_TO_STRING;
7476
3.61k
    hay = xmlXPathValuePop(ctxt);
7477
7478
3.61k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7479
6
  xmlXPathReleaseObject(ctxt->context, hay);
7480
6
  xmlXPathReleaseObject(ctxt->context, needle);
7481
6
  XP_ERROR(XPATH_INVALID_TYPE);
7482
0
    }
7483
3.60k
    n = xmlStrlen(needle->stringval);
7484
3.60k
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7485
1.98k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7486
1.62k
    else
7487
1.62k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7488
3.60k
    xmlXPathReleaseObject(ctxt->context, hay);
7489
3.60k
    xmlXPathReleaseObject(ctxt->context, needle);
7490
3.60k
}
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
18.7k
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7521
18.7k
    xmlXPathObjectPtr str, start, len;
7522
18.7k
    double le=0, in;
7523
18.7k
    int i = 1, j = INT_MAX;
7524
7525
18.7k
    if (nargs < 2) {
7526
32
  CHECK_ARITY(2);
7527
32
    }
7528
18.6k
    if (nargs > 3) {
7529
49
  CHECK_ARITY(3);
7530
49
    }
7531
    /*
7532
     * take care of possible last (position) argument
7533
    */
7534
18.6k
    if (nargs == 3) {
7535
7.73k
  CAST_TO_NUMBER;
7536
7.73k
  CHECK_TYPE(XPATH_NUMBER);
7537
7.73k
  len = xmlXPathValuePop(ctxt);
7538
7.73k
  le = len->floatval;
7539
7.73k
  xmlXPathReleaseObject(ctxt->context, len);
7540
7.73k
    }
7541
7542
18.6k
    CAST_TO_NUMBER;
7543
18.6k
    CHECK_TYPE(XPATH_NUMBER);
7544
18.6k
    start = xmlXPathValuePop(ctxt);
7545
18.6k
    in = start->floatval;
7546
18.6k
    xmlXPathReleaseObject(ctxt->context, start);
7547
18.6k
    CAST_TO_STRING;
7548
18.6k
    CHECK_TYPE(XPATH_STRING);
7549
18.6k
    str = xmlXPathValuePop(ctxt);
7550
7551
18.6k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7552
2.57k
        i = INT_MAX;
7553
16.0k
    } else if (in >= 1.0) {
7554
11.3k
        i = (int)in;
7555
11.3k
        if (in - floor(in) >= 0.5)
7556
1.11k
            i += 1;
7557
11.3k
    }
7558
7559
18.6k
    if (nargs == 3) {
7560
7.72k
        double rin, rle, end;
7561
7562
7.72k
        rin = floor(in);
7563
7.72k
        if (in - rin >= 0.5)
7564
1.08k
            rin += 1.0;
7565
7566
7.72k
        rle = floor(le);
7567
7.72k
        if (le - rle >= 0.5)
7568
1.46k
            rle += 1.0;
7569
7570
7.72k
        end = rin + rle;
7571
7.72k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7572
2.23k
            j = 1;
7573
5.48k
        } else if (end < INT_MAX) {
7574
4.41k
            j = (int)end;
7575
4.41k
        }
7576
7.72k
    }
7577
7578
18.6k
    i -= 1;
7579
18.6k
    j -= 1;
7580
7581
18.6k
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7582
9.83k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7583
9.83k
        if (ret == NULL)
7584
5
            xmlXPathPErrMemory(ctxt);
7585
9.83k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7586
9.83k
  xmlFree(ret);
7587
9.83k
    } else {
7588
8.79k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7589
8.79k
    }
7590
7591
18.6k
    xmlXPathReleaseObject(ctxt->context, str);
7592
18.6k
}
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
5.89k
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7608
5.89k
    xmlXPathObjectPtr str = NULL;
7609
5.89k
    xmlXPathObjectPtr find = NULL;
7610
5.89k
    const xmlChar *point;
7611
5.89k
    xmlChar *result;
7612
7613
17.6k
    CHECK_ARITY(2);
7614
17.6k
    CAST_TO_STRING;
7615
17.6k
    find = xmlXPathValuePop(ctxt);
7616
17.6k
    CAST_TO_STRING;
7617
17.6k
    str = xmlXPathValuePop(ctxt);
7618
17.6k
    if (ctxt->error != 0)
7619
7
        goto error;
7620
7621
5.88k
    point = xmlStrstr(str->stringval, find->stringval);
7622
5.88k
    if (point == NULL) {
7623
1.68k
        result = xmlStrdup(BAD_CAST "");
7624
4.19k
    } else {
7625
4.19k
        result = xmlStrndup(str->stringval, point - str->stringval);
7626
4.19k
    }
7627
5.88k
    if (result == NULL) {
7628
3
        xmlXPathPErrMemory(ctxt);
7629
3
        goto error;
7630
3
    }
7631
5.87k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7632
7633
5.88k
error:
7634
5.88k
    xmlXPathReleaseObject(ctxt->context, str);
7635
5.88k
    xmlXPathReleaseObject(ctxt->context, find);
7636
5.88k
}
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
2.83k
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7653
2.83k
    xmlXPathObjectPtr str = NULL;
7654
2.83k
    xmlXPathObjectPtr find = NULL;
7655
2.83k
    const xmlChar *point;
7656
2.83k
    xmlChar *result;
7657
7658
8.43k
    CHECK_ARITY(2);
7659
8.43k
    CAST_TO_STRING;
7660
8.43k
    find = xmlXPathValuePop(ctxt);
7661
8.43k
    CAST_TO_STRING;
7662
8.43k
    str = xmlXPathValuePop(ctxt);
7663
8.43k
    if (ctxt->error != 0)
7664
3
        goto error;
7665
7666
2.79k
    point = xmlStrstr(str->stringval, find->stringval);
7667
2.79k
    if (point == NULL) {
7668
922
        result = xmlStrdup(BAD_CAST "");
7669
1.87k
    } else {
7670
1.87k
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7671
1.87k
    }
7672
2.79k
    if (result == NULL) {
7673
4
        xmlXPathPErrMemory(ctxt);
7674
4
        goto error;
7675
4
    }
7676
2.79k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7677
7678
2.80k
error:
7679
2.80k
    xmlXPathReleaseObject(ctxt->context, str);
7680
2.80k
    xmlXPathReleaseObject(ctxt->context, find);
7681
2.80k
}
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
3.31k
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7698
3.31k
    xmlChar *source, *target;
7699
3.31k
    int blank;
7700
7701
3.31k
    if (ctxt == NULL) return;
7702
3.31k
    if (nargs == 0) {
7703
        /* Use current context node */
7704
1.95k
        source = xmlXPathCastNodeToString(ctxt->context->node);
7705
1.95k
        if (source == NULL)
7706
2
            xmlXPathPErrMemory(ctxt);
7707
1.95k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7708
1.95k
        nargs = 1;
7709
1.95k
    }
7710
7711
9.91k
    CHECK_ARITY(1);
7712
9.91k
    CAST_TO_STRING;
7713
9.91k
    CHECK_TYPE(XPATH_STRING);
7714
3.30k
    source = ctxt->value->stringval;
7715
3.30k
    if (source == NULL)
7716
3
        return;
7717
3.29k
    target = source;
7718
7719
    /* Skip leading whitespaces */
7720
3.29k
    while (IS_BLANK_CH(*source))
7721
1.70k
        source++;
7722
7723
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7724
3.29k
    blank = 0;
7725
79.4k
    while (*source) {
7726
76.1k
        if (IS_BLANK_CH(*source)) {
7727
21.3k
      blank = 1;
7728
54.7k
        } else {
7729
54.7k
            if (blank) {
7730
5.65k
                *target++ = 0x20;
7731
5.65k
                blank = 0;
7732
5.65k
            }
7733
54.7k
            *target++ = *source;
7734
54.7k
        }
7735
76.1k
        source++;
7736
76.1k
    }
7737
3.29k
    *target = 0;
7738
3.29k
}
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
29.0k
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7763
29.0k
    xmlXPathObjectPtr str = NULL;
7764
29.0k
    xmlXPathObjectPtr from = NULL;
7765
29.0k
    xmlXPathObjectPtr to = NULL;
7766
29.0k
    xmlBufPtr target;
7767
29.0k
    int offset, max;
7768
29.0k
    int ch;
7769
29.0k
    const xmlChar *point;
7770
29.0k
    xmlChar *cptr, *content;
7771
7772
87.0k
    CHECK_ARITY(3);
7773
7774
87.0k
    CAST_TO_STRING;
7775
87.0k
    to = xmlXPathValuePop(ctxt);
7776
87.0k
    CAST_TO_STRING;
7777
87.0k
    from = xmlXPathValuePop(ctxt);
7778
87.0k
    CAST_TO_STRING;
7779
87.0k
    str = xmlXPathValuePop(ctxt);
7780
87.0k
    if (ctxt->error != 0)
7781
47
        goto error;
7782
7783
    /*
7784
     * Account for quadratic runtime
7785
     */
7786
28.9k
    if (ctxt->context->opLimit != 0) {
7787
26.1k
        unsigned long f1 = xmlStrlen(from->stringval);
7788
26.1k
        unsigned long f2 = xmlStrlen(str->stringval);
7789
7790
26.1k
        if ((f1 > 0) && (f2 > 0)) {
7791
23.3k
            unsigned long p;
7792
7793
23.3k
            f1 = f1 / 10 + 1;
7794
23.3k
            f2 = f2 / 10 + 1;
7795
23.3k
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7796
23.3k
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7797
101
                goto error;
7798
23.3k
        }
7799
26.1k
    }
7800
7801
28.8k
    target = xmlBufCreate(50);
7802
28.8k
    if (target == NULL) {
7803
12
        xmlXPathPErrMemory(ctxt);
7804
12
        goto error;
7805
12
    }
7806
7807
28.8k
    max = xmlUTF8Strlen(to->stringval);
7808
1.26M
    for (cptr = str->stringval; (ch=*cptr); ) {
7809
1.23M
        offset = xmlUTF8Strloc(from->stringval, cptr);
7810
1.23M
        if (offset >= 0) {
7811
822k
            if (offset < max) {
7812
721k
                point = xmlUTF8Strpos(to->stringval, offset);
7813
721k
                if (point)
7814
721k
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7815
721k
            }
7816
822k
        } else
7817
413k
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7818
7819
        /* Step to next character in input */
7820
1.23M
        cptr++;
7821
1.23M
        if ( ch & 0x80 ) {
7822
            /* if not simple ascii, verify proper format */
7823
648k
            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
1.94M
            while ( (ch <<= 1) & 0x80 )
7829
1.29M
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7830
2
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7831
2
                    break;
7832
2
                }
7833
648k
            if (ch & 0x80) /* must have had error encountered */
7834
2
                break;
7835
648k
        }
7836
1.23M
    }
7837
7838
28.8k
    content = xmlBufDetach(target);
7839
28.8k
    if (content == NULL)
7840
18
        xmlXPathPErrMemory(ctxt);
7841
28.8k
    else
7842
28.8k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7843
28.8k
    xmlBufFree(target);
7844
28.9k
error:
7845
28.9k
    xmlXPathReleaseObject(ctxt->context, str);
7846
28.9k
    xmlXPathReleaseObject(ctxt->context, from);
7847
28.9k
    xmlXPathReleaseObject(ctxt->context, to);
7848
28.9k
}
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
64.2k
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7864
64.2k
    xmlXPathObjectPtr cur;
7865
7866
192k
    CHECK_ARITY(1);
7867
192k
    cur = xmlXPathValuePop(ctxt);
7868
192k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7869
64.2k
    if (cur->type != XPATH_BOOLEAN) {
7870
42.7k
        int boolval = xmlXPathCastToBoolean(cur);
7871
7872
42.7k
        xmlXPathReleaseObject(ctxt->context, cur);
7873
42.7k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7874
42.7k
    }
7875
64.2k
    xmlXPathValuePush(ctxt, cur);
7876
64.2k
}
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
2.08k
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7889
6.15k
    CHECK_ARITY(1);
7890
6.15k
    CAST_TO_BOOLEAN;
7891
6.15k
    CHECK_TYPE(XPATH_BOOLEAN);
7892
2.03k
    ctxt->value->boolval = ! ctxt->value->boolval;
7893
2.03k
}
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
1.61k
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7904
4.75k
    CHECK_ARITY(0);
7905
4.75k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7906
4.75k
}
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
907
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7917
2.64k
    CHECK_ARITY(0);
7918
2.64k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7919
2.64k
}
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
50.1k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7943
50.1k
    xmlXPathObjectPtr val;
7944
50.1k
    xmlNodePtr cur;
7945
50.1k
    xmlChar *theLang = NULL;
7946
50.1k
    const xmlChar *lang;
7947
50.1k
    int ret = 0;
7948
50.1k
    int i;
7949
7950
150k
    CHECK_ARITY(1);
7951
150k
    CAST_TO_STRING;
7952
150k
    CHECK_TYPE(XPATH_STRING);
7953
50.0k
    val = xmlXPathValuePop(ctxt);
7954
50.0k
    lang = val->stringval;
7955
50.0k
    cur = ctxt->context->node;
7956
573k
    while (cur != NULL) {
7957
525k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7958
525k
                                &theLang) < 0)
7959
3
            xmlXPathPErrMemory(ctxt);
7960
525k
        if (theLang != NULL)
7961
2.03k
            break;
7962
523k
        cur = cur->parent;
7963
523k
    }
7964
50.0k
    if ((theLang != NULL) && (lang != NULL)) {
7965
4.85k
        for (i = 0;lang[i] != 0;i++)
7966
3.31k
            if (toupper(lang[i]) != toupper(theLang[i]))
7967
491
                goto not_equal;
7968
1.53k
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7969
1.11k
            ret = 1;
7970
1.53k
    }
7971
50.0k
not_equal:
7972
50.0k
    if (theLang != NULL)
7973
2.03k
  xmlFree((void *)theLang);
7974
7975
50.0k
    xmlXPathReleaseObject(ctxt->context, val);
7976
50.0k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7977
50.0k
}
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.59M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7988
1.59M
    xmlXPathObjectPtr cur;
7989
1.59M
    double res;
7990
7991
1.59M
    if (ctxt == NULL) return;
7992
1.59M
    if (nargs == 0) {
7993
2.02k
  if (ctxt->context->node == NULL) {
7994
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7995
2.02k
  } else {
7996
2.02k
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7997
2.02k
            if (content == NULL)
7998
1
                xmlXPathPErrMemory(ctxt);
7999
8000
2.02k
      res = xmlXPathStringEvalNumber(content);
8001
2.02k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8002
2.02k
      xmlFree(content);
8003
2.02k
  }
8004
2.02k
  return;
8005
2.02k
    }
8006
8007
6.38M
    CHECK_ARITY(1);
8008
6.38M
    cur = xmlXPathValuePop(ctxt);
8009
6.38M
    if (cur->type != XPATH_NUMBER) {
8010
1.59M
        double floatval;
8011
8012
1.59M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8013
1.59M
        xmlXPathReleaseObject(ctxt->context, cur);
8014
1.59M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8015
1.59M
    }
8016
6.38M
    xmlXPathValuePush(ctxt, cur);
8017
6.38M
}
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
25.4k
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
25.4k
    xmlXPathObjectPtr cur;
8031
25.4k
    int i;
8032
25.4k
    double res = 0.0;
8033
8034
76.4k
    CHECK_ARITY(1);
8035
76.4k
    if ((ctxt->value == NULL) ||
8036
25.4k
  ((ctxt->value->type != XPATH_NODESET) &&
8037
22
   (ctxt->value->type != XPATH_XSLT_TREE)))
8038
25.4k
  XP_ERROR(XPATH_INVALID_TYPE);
8039
25.4k
    cur = xmlXPathValuePop(ctxt);
8040
8041
25.4k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8042
6.41M
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8043
6.39M
      res += xmlXPathNodeToNumberInternal(ctxt,
8044
6.39M
                                                cur->nodesetval->nodeTab[i]);
8045
6.39M
  }
8046
23.6k
    }
8047
25.4k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8048
25.4k
    xmlXPathReleaseObject(ctxt->context, cur);
8049
25.4k
}
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
1.25k
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8062
3.66k
    CHECK_ARITY(1);
8063
3.66k
    CAST_TO_NUMBER;
8064
3.66k
    CHECK_TYPE(XPATH_NUMBER);
8065
8066
1.20k
    ctxt->value->floatval = floor(ctxt->value->floatval);
8067
1.20k
}
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
1.21k
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8080
3.60k
    CHECK_ARITY(1);
8081
3.60k
    CAST_TO_NUMBER;
8082
3.60k
    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
1.19k
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8089
1.19k
#endif
8090
1.19k
}
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
3.13k
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8104
3.13k
    double f;
8105
8106
9.30k
    CHECK_ARITY(1);
8107
9.30k
    CAST_TO_NUMBER;
8108
9.30k
    CHECK_TYPE(XPATH_NUMBER);
8109
8110
3.08k
    f = ctxt->value->floatval;
8111
8112
3.08k
    if ((f >= -0.5) && (f < 0.5)) {
8113
        /* Handles negative zero. */
8114
963
        ctxt->value->floatval *= 0.0;
8115
963
    }
8116
2.11k
    else {
8117
2.11k
        double rounded = floor(f);
8118
2.11k
        if (f - rounded >= 0.5)
8119
614
            rounded += 1.0;
8120
2.11k
        ctxt->value->floatval = rounded;
8121
2.11k
    }
8122
3.08k
}
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
1.86M
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8148
1.86M
    const xmlChar *end;
8149
1.86M
    xmlChar *ret;
8150
8151
1.86M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8152
8153
1.86M
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8154
1.86M
    if (end == NULL) {
8155
9
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8156
0
    }
8157
1.86M
    if (end == ctxt->cur)
8158
22.0k
        return(NULL);
8159
8160
1.84M
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8161
1.84M
    if (ret == NULL)
8162
111
        xmlXPathPErrMemory(ctxt);
8163
1.84M
    ctxt->cur = end;
8164
1.84M
    return(ret);
8165
1.86M
}
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
39.4k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8179
39.4k
    xmlChar *ret = NULL;
8180
8181
39.4k
    *prefix = NULL;
8182
39.4k
    ret = xmlXPathParseNCName(ctxt);
8183
39.4k
    if (ret && CUR == ':') {
8184
7.22k
        *prefix = ret;
8185
7.22k
  NEXT;
8186
7.22k
  ret = xmlXPathParseNCName(ctxt);
8187
7.22k
    }
8188
39.4k
    return(ret);
8189
39.4k
}
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
75.5k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8200
75.5k
    const xmlChar *end;
8201
75.5k
    xmlChar *ret;
8202
8203
75.5k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8204
8205
75.5k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8206
75.5k
    if (end == NULL) {
8207
19
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8208
0
    }
8209
75.5k
    if (end == ctxt->cur)
8210
24.6k
        return(NULL);
8211
8212
50.9k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8213
50.9k
    if (ret == NULL)
8214
62
        xmlXPathPErrMemory(ctxt);
8215
50.9k
    ctxt->cur = end;
8216
50.9k
    return(ret);
8217
75.5k
}
8218
8219
91.0k
#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
8.87M
xmlXPathStringEvalNumber(const xmlChar *str) {
8237
8.87M
    const xmlChar *cur = str;
8238
8.87M
    double ret;
8239
8.87M
    int ok = 0;
8240
8.87M
    int isneg = 0;
8241
8.87M
    int exponent = 0;
8242
8.87M
    int is_exponent_negative = 0;
8243
8.87M
#ifdef __GNUC__
8244
8.87M
    unsigned long tmp = 0;
8245
8.87M
    double temp;
8246
8.87M
#endif
8247
8.87M
    if (cur == NULL) return(0);
8248
8.87M
    while (IS_BLANK_CH(*cur)) cur++;
8249
8.87M
    if (*cur == '-') {
8250
75.6k
  isneg = 1;
8251
75.6k
  cur++;
8252
75.6k
    }
8253
8.87M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8254
8.71M
        return(xmlXPathNAN);
8255
8.71M
    }
8256
8257
165k
#ifdef __GNUC__
8258
    /*
8259
     * tmp/temp is a workaround against a gcc compiler bug
8260
     * http://veillard.com/gcc.bug
8261
     */
8262
165k
    ret = 0;
8263
288k
    while ((*cur >= '0') && (*cur <= '9')) {
8264
123k
  ret = ret * 10;
8265
123k
  tmp = (*cur - '0');
8266
123k
  ok = 1;
8267
123k
  cur++;
8268
123k
  temp = (double) tmp;
8269
123k
  ret = ret + temp;
8270
123k
    }
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
165k
    if (*cur == '.') {
8281
98.9k
  int v, frac = 0, max;
8282
98.9k
  double fraction = 0;
8283
8284
98.9k
        cur++;
8285
98.9k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8286
28.1k
      return(xmlXPathNAN);
8287
28.1k
  }
8288
99.5k
        while (*cur == '0') {
8289
28.8k
      frac = frac + 1;
8290
28.8k
      cur++;
8291
28.8k
        }
8292
70.7k
        max = frac + MAX_FRAC;
8293
204k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8294
133k
      v = (*cur - '0');
8295
133k
      fraction = fraction * 10 + v;
8296
133k
      frac = frac + 1;
8297
133k
      cur++;
8298
133k
  }
8299
70.7k
  fraction /= pow(10.0, frac);
8300
70.7k
  ret = ret + fraction;
8301
78.0k
  while ((*cur >= '0') && (*cur <= '9'))
8302
7.23k
      cur++;
8303
70.7k
    }
8304
136k
    if ((*cur == 'e') || (*cur == 'E')) {
8305
38.4k
      cur++;
8306
38.4k
      if (*cur == '-') {
8307
14.0k
  is_exponent_negative = 1;
8308
14.0k
  cur++;
8309
24.4k
      } else if (*cur == '+') {
8310
8.65k
        cur++;
8311
8.65k
      }
8312
161k
      while ((*cur >= '0') && (*cur <= '9')) {
8313
123k
        if (exponent < 1000000)
8314
108k
    exponent = exponent * 10 + (*cur - '0');
8315
123k
  cur++;
8316
123k
      }
8317
38.4k
    }
8318
136k
    while (IS_BLANK_CH(*cur)) cur++;
8319
136k
    if (*cur != 0) return(xmlXPathNAN);
8320
80.6k
    if (isneg) ret = -ret;
8321
80.6k
    if (is_exponent_negative) exponent = -exponent;
8322
80.6k
    ret *= pow(10.0, (double)exponent);
8323
80.6k
    return(ret);
8324
136k
}
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
224k
{
8338
224k
    double ret = 0.0;
8339
224k
    int ok = 0;
8340
224k
    int exponent = 0;
8341
224k
    int is_exponent_negative = 0;
8342
224k
    xmlXPathObjectPtr num;
8343
224k
#ifdef __GNUC__
8344
224k
    unsigned long tmp = 0;
8345
224k
    double temp;
8346
224k
#endif
8347
8348
224k
    CHECK_ERROR;
8349
223k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8350
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8351
0
    }
8352
223k
#ifdef __GNUC__
8353
    /*
8354
     * tmp/temp is a workaround against a gcc compiler bug
8355
     * http://veillard.com/gcc.bug
8356
     */
8357
223k
    ret = 0;
8358
853k
    while ((CUR >= '0') && (CUR <= '9')) {
8359
629k
  ret = ret * 10;
8360
629k
  tmp = (CUR - '0');
8361
629k
        ok = 1;
8362
629k
        NEXT;
8363
629k
  temp = (double) tmp;
8364
629k
  ret = ret + temp;
8365
629k
    }
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
223k
    if (CUR == '.') {
8375
20.2k
  int v, frac = 0, max;
8376
20.2k
  double fraction = 0;
8377
8378
20.2k
        NEXT;
8379
20.2k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8380
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8381
0
        }
8382
26.4k
        while (CUR == '0') {
8383
6.16k
            frac = frac + 1;
8384
6.16k
            NEXT;
8385
6.16k
        }
8386
20.2k
        max = frac + MAX_FRAC;
8387
41.9k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8388
21.6k
      v = (CUR - '0');
8389
21.6k
      fraction = fraction * 10 + v;
8390
21.6k
      frac = frac + 1;
8391
21.6k
            NEXT;
8392
21.6k
        }
8393
20.2k
        fraction /= pow(10.0, frac);
8394
20.2k
        ret = ret + fraction;
8395
21.6k
        while ((CUR >= '0') && (CUR <= '9'))
8396
1.37k
            NEXT;
8397
20.2k
    }
8398
223k
    if ((CUR == 'e') || (CUR == 'E')) {
8399
18.5k
        NEXT;
8400
18.5k
        if (CUR == '-') {
8401
5.08k
            is_exponent_negative = 1;
8402
5.08k
            NEXT;
8403
13.4k
        } else if (CUR == '+') {
8404
1.64k
      NEXT;
8405
1.64k
  }
8406
89.1k
        while ((CUR >= '0') && (CUR <= '9')) {
8407
70.5k
            if (exponent < 1000000)
8408
58.0k
                exponent = exponent * 10 + (CUR - '0');
8409
70.5k
            NEXT;
8410
70.5k
        }
8411
18.5k
        if (is_exponent_negative)
8412
5.08k
            exponent = -exponent;
8413
18.5k
        ret *= pow(10.0, (double) exponent);
8414
18.5k
    }
8415
223k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8416
223k
    if (num == NULL) {
8417
45
  ctxt->error = XPATH_MEMORY_ERROR;
8418
223k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8419
223k
                              NULL) == -1) {
8420
16
        xmlXPathReleaseObject(ctxt->context, num);
8421
16
    }
8422
223k
}
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
14.3k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8435
14.3k
    const xmlChar *q;
8436
14.3k
    xmlChar *ret = NULL;
8437
14.3k
    int quote;
8438
8439
14.3k
    if (CUR == '"') {
8440
2.54k
        quote = '"';
8441
11.8k
    } else if (CUR == '\'') {
8442
11.7k
        quote = '\'';
8443
11.7k
    } else {
8444
66
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8445
0
    }
8446
8447
14.2k
    NEXT;
8448
14.2k
    q = CUR_PTR;
8449
9.36M
    while (CUR != quote) {
8450
9.35M
        int ch;
8451
9.35M
        int len = 4;
8452
8453
9.35M
        if (CUR == 0)
8454
9.35M
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8455
9.35M
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8456
9.35M
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8457
9.35M
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8458
9.35M
        CUR_PTR += len;
8459
9.35M
    }
8460
13.7k
    ret = xmlStrndup(q, CUR_PTR - q);
8461
13.7k
    if (ret == NULL)
8462
6
        xmlXPathPErrMemory(ctxt);
8463
13.7k
    NEXT;
8464
13.7k
    return(ret);
8465
14.2k
}
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
13.7k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8479
13.7k
    xmlChar *ret = NULL;
8480
13.7k
    xmlXPathObjectPtr lit;
8481
8482
13.7k
    ret = xmlXPathParseLiteral(ctxt);
8483
13.7k
    if (ret == NULL)
8484
491
        return;
8485
13.2k
    lit = xmlXPathCacheNewString(ctxt, ret);
8486
13.2k
    if (lit == NULL) {
8487
13
        ctxt->error = XPATH_MEMORY_ERROR;
8488
13.2k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8489
13.2k
                              NULL) == -1) {
8490
43
        xmlXPathReleaseObject(ctxt->context, lit);
8491
43
    }
8492
13.2k
    xmlFree(ret);
8493
13.2k
}
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
10.9k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8512
10.9k
    xmlChar *name;
8513
10.9k
    xmlChar *prefix;
8514
8515
10.9k
    SKIP_BLANKS;
8516
10.9k
    if (CUR != '$') {
8517
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8518
0
    }
8519
10.9k
    NEXT;
8520
10.9k
    name = xmlXPathParseQName(ctxt, &prefix);
8521
10.9k
    if (name == NULL) {
8522
5.18k
        xmlFree(prefix);
8523
5.18k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8524
0
    }
8525
5.75k
    ctxt->comp->last = -1;
8526
5.75k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8527
219
        xmlFree(prefix);
8528
219
        xmlFree(name);
8529
219
    }
8530
5.75k
    SKIP_BLANKS;
8531
5.75k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8532
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8533
0
    }
8534
5.75k
}
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
31.9k
xmlXPathIsNodeType(const xmlChar *name) {
8549
31.9k
    if (name == NULL)
8550
0
  return(0);
8551
8552
31.9k
    if (xmlStrEqual(name, BAD_CAST "node"))
8553
820
  return(1);
8554
31.0k
    if (xmlStrEqual(name, BAD_CAST "text"))
8555
1.10k
  return(1);
8556
29.9k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8557
617
  return(1);
8558
29.3k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8559
899
  return(1);
8560
28.4k
    return(0);
8561
29.3k
}
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
28.4k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8574
28.4k
    xmlChar *name;
8575
28.4k
    xmlChar *prefix;
8576
28.4k
    int nbargs = 0;
8577
28.4k
    int sort = 1;
8578
8579
28.4k
    name = xmlXPathParseQName(ctxt, &prefix);
8580
28.4k
    if (name == NULL) {
8581
57
  xmlFree(prefix);
8582
57
  XP_ERROR(XPATH_EXPR_ERROR);
8583
0
    }
8584
28.4k
    SKIP_BLANKS;
8585
8586
28.4k
    if (CUR != '(') {
8587
45
  xmlFree(name);
8588
45
  xmlFree(prefix);
8589
45
  XP_ERROR(XPATH_EXPR_ERROR);
8590
0
    }
8591
28.3k
    NEXT;
8592
28.3k
    SKIP_BLANKS;
8593
8594
    /*
8595
    * Optimization for count(): we don't need the node-set to be sorted.
8596
    */
8597
28.3k
    if ((prefix == NULL) && (name[0] == 'c') &&
8598
3.33k
  xmlStrEqual(name, BAD_CAST "count"))
8599
382
    {
8600
382
  sort = 0;
8601
382
    }
8602
28.3k
    ctxt->comp->last = -1;
8603
28.3k
    if (CUR != ')') {
8604
1.32M
  while (CUR != 0) {
8605
1.32M
      int op1 = ctxt->comp->last;
8606
1.32M
      ctxt->comp->last = -1;
8607
1.32M
      xmlXPathCompileExpr(ctxt, sort);
8608
1.32M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8609
1.99k
    xmlFree(name);
8610
1.99k
    xmlFree(prefix);
8611
1.99k
    return;
8612
1.99k
      }
8613
1.31M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8614
1.31M
      nbargs++;
8615
1.31M
      if (CUR == ')') break;
8616
1.30M
      if (CUR != ',') {
8617
279
    xmlFree(name);
8618
279
    xmlFree(prefix);
8619
279
    XP_ERROR(XPATH_EXPR_ERROR);
8620
0
      }
8621
1.30M
      NEXT;
8622
1.30M
      SKIP_BLANKS;
8623
1.30M
  }
8624
21.1k
    }
8625
26.0k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8626
7
        xmlFree(prefix);
8627
7
        xmlFree(name);
8628
7
    }
8629
26.0k
    NEXT;
8630
26.0k
    SKIP_BLANKS;
8631
26.0k
}
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
320k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8646
320k
    SKIP_BLANKS;
8647
320k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8648
309k
    else if (CUR == '(') {
8649
43.0k
  NEXT;
8650
43.0k
  SKIP_BLANKS;
8651
43.0k
  xmlXPathCompileExpr(ctxt, 1);
8652
43.0k
  CHECK_ERROR;
8653
40.4k
  if (CUR != ')') {
8654
150
      XP_ERROR(XPATH_EXPR_ERROR);
8655
0
  }
8656
40.3k
  NEXT;
8657
40.3k
  SKIP_BLANKS;
8658
266k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8659
224k
  xmlXPathCompNumber(ctxt);
8660
224k
    } else if ((CUR == '\'') || (CUR == '"')) {
8661
13.7k
  xmlXPathCompLiteral(ctxt);
8662
28.4k
    } else {
8663
28.4k
  xmlXPathCompFunctionCall(ctxt);
8664
28.4k
    }
8665
317k
    SKIP_BLANKS;
8666
317k
}
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
320k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8684
320k
    xmlXPathCompPrimaryExpr(ctxt);
8685
320k
    CHECK_ERROR;
8686
308k
    SKIP_BLANKS;
8687
8688
346k
    while (CUR == '[') {
8689
38.4k
  xmlXPathCompPredicate(ctxt, 1);
8690
38.4k
  SKIP_BLANKS;
8691
38.4k
    }
8692
8693
8694
308k
}
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
14.7M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8706
14.7M
    const xmlChar *end;
8707
14.7M
    xmlChar *ret;
8708
8709
14.7M
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8710
14.7M
    if (end == NULL) {
8711
7
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8712
0
    }
8713
14.7M
    if (end == ctxt->cur)
8714
13.1M
        return(NULL);
8715
8716
1.67M
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8717
1.67M
    if (ret == NULL)
8718
76
        xmlXPathPErrMemory(ctxt);
8719
1.67M
    return(ret);
8720
14.7M
}
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
19.8M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8735
19.8M
    int lc = 1;           /* Should we branch to LocationPath ?         */
8736
19.8M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8737
8738
19.8M
    SKIP_BLANKS;
8739
19.8M
    if ((CUR == '$') || (CUR == '(') ||
8740
19.7M
  (IS_ASCII_DIGIT(CUR)) ||
8741
19.5M
        (CUR == '\'') || (CUR == '"') ||
8742
19.5M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8743
291k
  lc = 0;
8744
19.5M
    } else if (CUR == '*') {
8745
  /* relative or absolute location path */
8746
4.56M
  lc = 1;
8747
14.9M
    } else if (CUR == '/') {
8748
  /* relative or absolute location path */
8749
126k
  lc = 1;
8750
14.8M
    } else if (CUR == '@') {
8751
  /* relative abbreviated attribute location path */
8752
4.22k
  lc = 1;
8753
14.8M
    } else if (CUR == '.') {
8754
  /* relative abbreviated attribute location path */
8755
60.6k
  lc = 1;
8756
14.7M
    } 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
14.7M
  SKIP_BLANKS;
8769
14.7M
  name = xmlXPathScanName(ctxt);
8770
14.7M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8771
6.91k
      lc = 1;
8772
6.91k
      xmlFree(name);
8773
14.7M
  } else if (name != NULL) {
8774
1.66M
      int len =xmlStrlen(name);
8775
8776
8777
2.15M
      while (NXT(len) != 0) {
8778
2.14M
    if (NXT(len) == '/') {
8779
        /* element name */
8780
50.7k
        lc = 1;
8781
50.7k
        break;
8782
2.09M
    } else if (IS_BLANK_CH(NXT(len))) {
8783
        /* ignore blanks */
8784
485k
        ;
8785
1.61M
    } else if (NXT(len) == ':') {
8786
994
        lc = 1;
8787
994
        break;
8788
1.61M
    } else if ((NXT(len) == '(')) {
8789
        /* Node Type or Function */
8790
31.9k
        if (xmlXPathIsNodeType(name)) {
8791
3.44k
      lc = 1;
8792
28.4k
        } else {
8793
28.4k
      lc = 0;
8794
28.4k
        }
8795
31.9k
                    break;
8796
1.57M
    } else if ((NXT(len) == '[')) {
8797
        /* element name */
8798
4.25k
        lc = 1;
8799
4.25k
        break;
8800
1.57M
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8801
1.46M
         (NXT(len) == '=')) {
8802
148k
        lc = 1;
8803
148k
        break;
8804
1.42M
    } else {
8805
1.42M
        lc = 1;
8806
1.42M
        break;
8807
1.42M
    }
8808
485k
    len++;
8809
485k
      }
8810
1.66M
      if (NXT(len) == 0) {
8811
    /* element name */
8812
3.46k
    lc = 1;
8813
3.46k
      }
8814
1.66M
      xmlFree(name);
8815
13.1M
  } else {
8816
      /* make sure all cases are covered explicitly */
8817
13.1M
      XP_ERROR(XPATH_EXPR_ERROR);
8818
0
  }
8819
14.7M
    }
8820
8821
6.71M
    if (lc) {
8822
6.39M
  if (CUR == '/') {
8823
126k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8824
6.27M
  } else {
8825
6.27M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8826
6.27M
  }
8827
6.39M
  xmlXPathCompLocationPath(ctxt);
8828
6.39M
    } else {
8829
320k
  xmlXPathCompFilterExpr(ctxt);
8830
320k
  CHECK_ERROR;
8831
306k
  if ((CUR == '/') && (NXT(1) == '/')) {
8832
3.12k
      SKIP(2);
8833
3.12k
      SKIP_BLANKS;
8834
8835
3.12k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8836
3.12k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8837
8838
3.12k
      xmlXPathCompRelativeLocationPath(ctxt);
8839
303k
  } else if (CUR == '/') {
8840
4.50k
      xmlXPathCompRelativeLocationPath(ctxt);
8841
4.50k
  }
8842
306k
    }
8843
6.70M
    SKIP_BLANKS;
8844
6.70M
}
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
6.60M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8857
6.60M
    xmlXPathCompPathExpr(ctxt);
8858
6.60M
    CHECK_ERROR;
8859
6.58M
    SKIP_BLANKS;
8860
19.8M
    while (CUR == '|') {
8861
13.2M
  int op1 = ctxt->comp->last;
8862
13.2M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8863
8864
13.2M
  NEXT;
8865
13.2M
  SKIP_BLANKS;
8866
13.2M
  xmlXPathCompPathExpr(ctxt);
8867
8868
13.2M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8869
8870
13.2M
  SKIP_BLANKS;
8871
13.2M
    }
8872
6.58M
}
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
6.60M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8885
6.60M
    int minus = 0;
8886
6.60M
    int found = 0;
8887
8888
6.60M
    SKIP_BLANKS;
8889
7.36M
    while (CUR == '-') {
8890
761k
        minus = 1 - minus;
8891
761k
  found = 1;
8892
761k
  NEXT;
8893
761k
  SKIP_BLANKS;
8894
761k
    }
8895
8896
6.60M
    xmlXPathCompUnionExpr(ctxt);
8897
6.60M
    CHECK_ERROR;
8898
6.58M
    if (found) {
8899
257k
  if (minus)
8900
169k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8901
87.6k
  else
8902
87.6k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8903
257k
    }
8904
6.58M
}
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
2.02M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8920
2.02M
    xmlXPathCompUnaryExpr(ctxt);
8921
2.02M
    CHECK_ERROR;
8922
2.00M
    SKIP_BLANKS;
8923
6.58M
    while ((CUR == '*') ||
8924
2.00M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8925
4.58M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8926
4.58M
  int op = -1;
8927
4.58M
  int op1 = ctxt->comp->last;
8928
8929
4.58M
        if (CUR == '*') {
8930
4.58M
      op = 0;
8931
4.58M
      NEXT;
8932
4.58M
  } else if (CUR == 'd') {
8933
1.72k
      op = 1;
8934
1.72k
      SKIP(3);
8935
1.72k
  } else if (CUR == 'm') {
8936
1.51k
      op = 2;
8937
1.51k
      SKIP(3);
8938
1.51k
  }
8939
4.58M
  SKIP_BLANKS;
8940
4.58M
        xmlXPathCompUnaryExpr(ctxt);
8941
4.58M
  CHECK_ERROR;
8942
4.58M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8943
4.58M
  SKIP_BLANKS;
8944
4.58M
    }
8945
2.00M
}
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
1.77M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8959
8960
1.77M
    xmlXPathCompMultiplicativeExpr(ctxt);
8961
1.77M
    CHECK_ERROR;
8962
1.75M
    SKIP_BLANKS;
8963
2.00M
    while ((CUR == '+') || (CUR == '-')) {
8964
248k
  int plus;
8965
248k
  int op1 = ctxt->comp->last;
8966
8967
248k
        if (CUR == '+') plus = 1;
8968
228k
  else plus = 0;
8969
248k
  NEXT;
8970
248k
  SKIP_BLANKS;
8971
248k
        xmlXPathCompMultiplicativeExpr(ctxt);
8972
248k
  CHECK_ERROR;
8973
247k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8974
247k
  SKIP_BLANKS;
8975
247k
    }
8976
1.75M
}
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
1.59M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8997
1.59M
    xmlXPathCompAdditiveExpr(ctxt);
8998
1.59M
    CHECK_ERROR;
8999
1.57M
    SKIP_BLANKS;
9000
1.75M
    while ((CUR == '<') || (CUR == '>')) {
9001
179k
  int inf, strict;
9002
179k
  int op1 = ctxt->comp->last;
9003
9004
179k
        if (CUR == '<') inf = 1;
9005
157k
  else inf = 0;
9006
179k
  if (NXT(1) == '=') strict = 0;
9007
119k
  else strict = 1;
9008
179k
  NEXT;
9009
179k
  if (!strict) NEXT;
9010
179k
  SKIP_BLANKS;
9011
179k
        xmlXPathCompAdditiveExpr(ctxt);
9012
179k
  CHECK_ERROR;
9013
177k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9014
177k
  SKIP_BLANKS;
9015
177k
    }
9016
1.57M
}
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
1.49M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9034
1.49M
    xmlXPathCompRelationalExpr(ctxt);
9035
1.49M
    CHECK_ERROR;
9036
1.47M
    SKIP_BLANKS;
9037
1.57M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9038
97.7k
  int eq;
9039
97.7k
  int op1 = ctxt->comp->last;
9040
9041
97.7k
        if (CUR == '=') eq = 1;
9042
6.18k
  else eq = 0;
9043
97.7k
  NEXT;
9044
97.7k
  if (!eq) NEXT;
9045
97.7k
  SKIP_BLANKS;
9046
97.7k
        xmlXPathCompRelationalExpr(ctxt);
9047
97.7k
  CHECK_ERROR;
9048
95.3k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9049
95.3k
  SKIP_BLANKS;
9050
95.3k
    }
9051
1.47M
}
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
1.49M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9063
1.49M
    xmlXPathCompEqualityExpr(ctxt);
9064
1.49M
    CHECK_ERROR;
9065
1.47M
    SKIP_BLANKS;
9066
1.47M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9067
3.03k
  int op1 = ctxt->comp->last;
9068
3.03k
        SKIP(3);
9069
3.03k
  SKIP_BLANKS;
9070
3.03k
        xmlXPathCompEqualityExpr(ctxt);
9071
3.03k
  CHECK_ERROR;
9072
2.74k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9073
2.74k
  SKIP_BLANKS;
9074
2.74k
    }
9075
1.47M
}
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
1.48M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9089
1.48M
    xmlXPathContextPtr xpctxt = ctxt->context;
9090
9091
1.48M
    if (xpctxt != NULL) {
9092
1.48M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9093
1.48M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9094
        /*
9095
         * Parsing a single '(' pushes about 10 functions on the call stack
9096
         * before recursing!
9097
         */
9098
1.48M
        xpctxt->depth += 10;
9099
1.48M
    }
9100
9101
1.48M
    xmlXPathCompAndExpr(ctxt);
9102
1.48M
    CHECK_ERROR;
9103
1.46M
    SKIP_BLANKS;
9104
1.47M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9105
7.77k
  int op1 = ctxt->comp->last;
9106
7.77k
        SKIP(2);
9107
7.77k
  SKIP_BLANKS;
9108
7.77k
        xmlXPathCompAndExpr(ctxt);
9109
7.77k
  CHECK_ERROR;
9110
7.16k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9111
7.16k
  SKIP_BLANKS;
9112
7.16k
    }
9113
1.46M
    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
1.40M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9121
1.40M
    }
9122
9123
1.46M
    if (xpctxt != NULL)
9124
1.46M
        xpctxt->depth -= 10;
9125
1.46M
}
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
77.5k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9138
77.5k
    int op1 = ctxt->comp->last;
9139
9140
77.5k
    SKIP_BLANKS;
9141
77.5k
    if (CUR != '[') {
9142
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9143
0
    }
9144
77.5k
    NEXT;
9145
77.5k
    SKIP_BLANKS;
9146
9147
77.5k
    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
77.5k
    if (! filter)
9158
39.1k
  xmlXPathCompileExpr(ctxt, 0);
9159
38.4k
    else
9160
38.4k
  xmlXPathCompileExpr(ctxt, 1);
9161
77.5k
    CHECK_ERROR;
9162
9163
66.2k
    if (CUR != ']') {
9164
591
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9165
0
    }
9166
9167
65.6k
    if (filter)
9168
35.0k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9169
30.6k
    else
9170
30.6k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9171
9172
65.6k
    NEXT;
9173
65.6k
    SKIP_BLANKS;
9174
65.6k
}
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
6.37M
         xmlChar *name) {
9202
6.37M
    int blanks;
9203
9204
6.37M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9205
0
  return(NULL);
9206
0
    }
9207
6.37M
    *type = (xmlXPathTypeVal) 0;
9208
6.37M
    *test = (xmlXPathTestVal) 0;
9209
6.37M
    *prefix = NULL;
9210
6.37M
    SKIP_BLANKS;
9211
9212
6.37M
    if ((name == NULL) && (CUR == '*')) {
9213
  /*
9214
   * All elements
9215
   */
9216
4.60M
  NEXT;
9217
4.60M
  *test = NODE_TEST_ALL;
9218
4.60M
  return(NULL);
9219
4.60M
    }
9220
9221
1.77M
    if (name == NULL)
9222
20.5k
  name = xmlXPathParseNCName(ctxt);
9223
1.77M
    if (name == NULL) {
9224
1.23k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9225
0
    }
9226
9227
1.77M
    blanks = IS_BLANK_CH(CUR);
9228
1.77M
    SKIP_BLANKS;
9229
1.77M
    if (CUR == '(') {
9230
12.2k
  NEXT;
9231
  /*
9232
   * NodeType or PI search
9233
   */
9234
12.2k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9235
1.37k
      *type = NODE_TYPE_COMMENT;
9236
10.8k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9237
6.52k
      *type = NODE_TYPE_NODE;
9238
4.33k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9239
1.44k
      *type = NODE_TYPE_PI;
9240
2.88k
  else if (xmlStrEqual(name, BAD_CAST "text"))
9241
2.73k
      *type = NODE_TYPE_TEXT;
9242
153
  else {
9243
153
      if (name != NULL)
9244
153
    xmlFree(name);
9245
153
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9246
0
  }
9247
9248
12.0k
  *test = NODE_TEST_TYPE;
9249
9250
12.0k
  SKIP_BLANKS;
9251
12.0k
  if (*type == NODE_TYPE_PI) {
9252
      /*
9253
       * Specific case: search a PI by name.
9254
       */
9255
1.44k
      if (name != NULL)
9256
1.44k
    xmlFree(name);
9257
1.44k
      name = NULL;
9258
1.44k
      if (CUR != ')') {
9259
638
    name = xmlXPathParseLiteral(ctxt);
9260
638
    *test = NODE_TEST_PI;
9261
638
    SKIP_BLANKS;
9262
638
      }
9263
1.44k
  }
9264
12.0k
  if (CUR != ')') {
9265
326
      if (name != NULL)
9266
210
    xmlFree(name);
9267
326
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9268
0
  }
9269
11.7k
  NEXT;
9270
11.7k
  return(name);
9271
12.0k
    }
9272
1.75M
    *test = NODE_TEST_NAME;
9273
1.75M
    if ((!blanks) && (CUR == ':')) {
9274
12.9k
  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
12.9k
  *prefix = name;
9284
9285
12.9k
  if (CUR == '*') {
9286
      /*
9287
       * All elements
9288
       */
9289
1.21k
      NEXT;
9290
1.21k
      *test = NODE_TEST_ALL;
9291
1.21k
      return(NULL);
9292
1.21k
  }
9293
9294
11.7k
  name = xmlXPathParseNCName(ctxt);
9295
11.7k
  if (name == NULL) {
9296
930
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9297
0
  }
9298
11.7k
    }
9299
1.75M
    return(name);
9300
1.75M
}
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
1.77M
xmlXPathIsAxisName(const xmlChar *name) {
9322
1.77M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9323
1.77M
    switch (name[0]) {
9324
38.2k
  case 'a':
9325
38.2k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9326
2.35k
    ret = AXIS_ANCESTOR;
9327
38.2k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9328
1.81k
    ret = AXIS_ANCESTOR_OR_SELF;
9329
38.2k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9330
528
    ret = AXIS_ATTRIBUTE;
9331
38.2k
      break;
9332
15.1k
  case 'c':
9333
15.1k
      if (xmlStrEqual(name, BAD_CAST "child"))
9334
729
    ret = AXIS_CHILD;
9335
15.1k
      break;
9336
10.7k
  case 'd':
9337
10.7k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9338
3.47k
    ret = AXIS_DESCENDANT;
9339
10.7k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9340
1.87k
    ret = AXIS_DESCENDANT_OR_SELF;
9341
10.7k
      break;
9342
28.0k
  case 'f':
9343
28.0k
      if (xmlStrEqual(name, BAD_CAST "following"))
9344
9.99k
    ret = AXIS_FOLLOWING;
9345
28.0k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9346
634
    ret = AXIS_FOLLOWING_SIBLING;
9347
28.0k
      break;
9348
93.3k
  case 'n':
9349
93.3k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9350
2.70k
    ret = AXIS_NAMESPACE;
9351
93.3k
      break;
9352
96.2k
  case 'p':
9353
96.2k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9354
792
    ret = AXIS_PARENT;
9355
96.2k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9356
1.68k
    ret = AXIS_PRECEDING;
9357
96.2k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9358
1.07k
    ret = AXIS_PRECEDING_SIBLING;
9359
96.2k
      break;
9360
9.04k
  case 's':
9361
9.04k
      if (xmlStrEqual(name, BAD_CAST "self"))
9362
2.84k
    ret = AXIS_SELF;
9363
9.04k
      break;
9364
1.77M
    }
9365
1.77M
    return(ret);
9366
1.77M
}
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
6.49M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9391
6.49M
    SKIP_BLANKS;
9392
6.49M
    if ((CUR == '.') && (NXT(1) == '.')) {
9393
11.3k
  SKIP(2);
9394
11.3k
  SKIP_BLANKS;
9395
11.3k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9396
11.3k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9397
6.48M
    } else if (CUR == '.') {
9398
98.7k
  NEXT;
9399
98.7k
  SKIP_BLANKS;
9400
6.38M
    } else {
9401
6.38M
  xmlChar *name = NULL;
9402
6.38M
  xmlChar *prefix = NULL;
9403
6.38M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9404
6.38M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9405
6.38M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9406
6.38M
  int op1;
9407
9408
6.38M
  if (CUR == '*') {
9409
4.59M
      axis = AXIS_CHILD;
9410
4.59M
  } else {
9411
1.78M
      if (name == NULL)
9412
1.78M
    name = xmlXPathParseNCName(ctxt);
9413
1.78M
      if (name != NULL) {
9414
1.77M
    axis = xmlXPathIsAxisName(name);
9415
1.77M
    if (axis != 0) {
9416
30.4k
        SKIP_BLANKS;
9417
30.4k
        if ((CUR == ':') && (NXT(1) == ':')) {
9418
14.3k
      SKIP(2);
9419
14.3k
      xmlFree(name);
9420
14.3k
      name = NULL;
9421
16.1k
        } else {
9422
      /* an element name can conflict with an axis one :-\ */
9423
16.1k
      axis = AXIS_CHILD;
9424
16.1k
        }
9425
1.74M
    } else {
9426
1.74M
        axis = AXIS_CHILD;
9427
1.74M
    }
9428
1.77M
      } else if (CUR == '@') {
9429
11.5k
    NEXT;
9430
11.5k
    axis = AXIS_ATTRIBUTE;
9431
11.5k
      } else {
9432
3.18k
    axis = AXIS_CHILD;
9433
3.18k
      }
9434
1.78M
  }
9435
9436
6.38M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9437
10.0k
            xmlFree(name);
9438
10.0k
            return;
9439
10.0k
        }
9440
9441
6.37M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9442
6.37M
  if (test == 0)
9443
1.38k
      return;
9444
9445
6.37M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9446
12.9k
      (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
6.37M
  op1 = ctxt->comp->last;
9454
6.37M
  ctxt->comp->last = -1;
9455
9456
6.37M
  SKIP_BLANKS;
9457
6.41M
  while (CUR == '[') {
9458
39.1k
      xmlXPathCompPredicate(ctxt, 0);
9459
39.1k
  }
9460
9461
6.37M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9462
6.37M
                           test, type, (void *)prefix, (void *)name) == -1) {
9463
151
            xmlFree(prefix);
9464
151
            xmlFree(name);
9465
151
        }
9466
6.37M
    }
9467
6.49M
}
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
6.38M
(xmlXPathParserContextPtr ctxt) {
9482
6.38M
    SKIP_BLANKS;
9483
6.38M
    if ((CUR == '/') && (NXT(1) == '/')) {
9484
5.99k
  SKIP(2);
9485
5.99k
  SKIP_BLANKS;
9486
5.99k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9487
5.99k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9488
6.37M
    } else if (CUR == '/') {
9489
13.6k
      NEXT;
9490
13.6k
  SKIP_BLANKS;
9491
13.6k
    }
9492
6.38M
    xmlXPathCompStep(ctxt);
9493
6.38M
    CHECK_ERROR;
9494
6.36M
    SKIP_BLANKS;
9495
6.47M
    while (CUR == '/') {
9496
109k
  if ((CUR == '/') && (NXT(1) == '/')) {
9497
17.2k
      SKIP(2);
9498
17.2k
      SKIP_BLANKS;
9499
17.2k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9500
17.2k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9501
17.2k
      xmlXPathCompStep(ctxt);
9502
92.4k
  } else if (CUR == '/') {
9503
92.4k
      NEXT;
9504
92.4k
      SKIP_BLANKS;
9505
92.4k
      xmlXPathCompStep(ctxt);
9506
92.4k
  }
9507
109k
  SKIP_BLANKS;
9508
109k
    }
9509
6.36M
}
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
6.39M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9525
6.39M
    SKIP_BLANKS;
9526
6.39M
    if (CUR != '/') {
9527
6.27M
        xmlXPathCompRelativeLocationPath(ctxt);
9528
6.27M
    } else {
9529
252k
  while (CUR == '/') {
9530
129k
      if ((CUR == '/') && (NXT(1) == '/')) {
9531
53.0k
    SKIP(2);
9532
53.0k
    SKIP_BLANKS;
9533
53.0k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9534
53.0k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9535
53.0k
    xmlXPathCompRelativeLocationPath(ctxt);
9536
76.7k
      } else if (CUR == '/') {
9537
76.7k
    NEXT;
9538
76.7k
    SKIP_BLANKS;
9539
76.7k
    if ((CUR != 0) &&
9540
75.7k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9541
48.6k
                     (CUR == '_') || (CUR == '.') ||
9542
39.1k
         (CUR == '@') || (CUR == '*')))
9543
50.8k
        xmlXPathCompRelativeLocationPath(ctxt);
9544
76.7k
      }
9545
129k
      CHECK_ERROR;
9546
129k
  }
9547
126k
    }
9548
6.39M
}
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
924k
{
9578
924k
    xmlXPathContextPtr xpctxt;
9579
924k
    xmlNodePtr oldnode;
9580
924k
    xmlDocPtr olddoc;
9581
924k
    xmlXPathStepOpPtr filterOp;
9582
924k
    int oldcs, oldpp;
9583
924k
    int i, j, pos;
9584
9585
924k
    if ((set == NULL) || (set->nodeNr == 0))
9586
135k
        return;
9587
9588
    /*
9589
    * Check if the node set contains a sufficient number of nodes for
9590
    * the requested range.
9591
    */
9592
789k
    if (set->nodeNr < minPos) {
9593
6.75k
        xmlXPathNodeSetClear(set, hasNsNodes);
9594
6.75k
        return;
9595
6.75k
    }
9596
9597
782k
    xpctxt = ctxt->context;
9598
782k
    oldnode = xpctxt->node;
9599
782k
    olddoc = xpctxt->doc;
9600
782k
    oldcs = xpctxt->contextSize;
9601
782k
    oldpp = xpctxt->proximityPosition;
9602
782k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9603
9604
782k
    xpctxt->contextSize = set->nodeNr;
9605
9606
5.55M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9607
5.18M
        xmlNodePtr node = set->nodeTab[i];
9608
5.18M
        int res;
9609
9610
5.18M
        xpctxt->node = node;
9611
5.18M
        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
5.18M
        if ((node->type != XML_NAMESPACE_DECL) &&
9620
3.06M
            (node->doc != NULL))
9621
3.06M
            xpctxt->doc = node->doc;
9622
9623
5.18M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9624
9625
5.18M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9626
5.01k
            break;
9627
5.18M
        if (res < 0) {
9628
            /* Shouldn't happen */
9629
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9630
0
            break;
9631
0
        }
9632
9633
5.18M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9634
3.65M
            if (i != j) {
9635
28.7k
                set->nodeTab[j] = node;
9636
28.7k
                set->nodeTab[i] = NULL;
9637
28.7k
            }
9638
9639
3.65M
            j += 1;
9640
3.65M
        } else {
9641
            /* Remove the entry from the initial node set. */
9642
1.52M
            set->nodeTab[i] = NULL;
9643
1.52M
            if (node->type == XML_NAMESPACE_DECL)
9644
382k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9645
1.52M
        }
9646
9647
5.18M
        if (res != 0) {
9648
3.69M
            if (pos == maxPos) {
9649
407k
                i += 1;
9650
407k
                break;
9651
407k
            }
9652
9653
3.29M
            pos += 1;
9654
3.29M
        }
9655
5.18M
    }
9656
9657
    /* Free remaining nodes. */
9658
782k
    if (hasNsNodes) {
9659
734k
        for (; i < set->nodeNr; i++) {
9660
471k
            xmlNodePtr node = set->nodeTab[i];
9661
471k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9662
435k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9663
471k
        }
9664
263k
    }
9665
9666
782k
    set->nodeNr = j;
9667
9668
    /* If too many elements were removed, shrink table to preserve memory. */
9669
782k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9670
76.5k
        (set->nodeNr < set->nodeMax / 2)) {
9671
52.5k
        xmlNodePtr *tmp;
9672
52.5k
        int nodeMax = set->nodeNr;
9673
9674
52.5k
        if (nodeMax < XML_NODESET_DEFAULT)
9675
49.5k
            nodeMax = XML_NODESET_DEFAULT;
9676
52.5k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9677
52.5k
                nodeMax * sizeof(xmlNodePtr));
9678
52.5k
        if (tmp == NULL) {
9679
3
            xmlXPathPErrMemory(ctxt);
9680
52.5k
        } else {
9681
52.5k
            set->nodeTab = tmp;
9682
52.5k
            set->nodeMax = nodeMax;
9683
52.5k
        }
9684
52.5k
    }
9685
9686
782k
    xpctxt->node = oldnode;
9687
782k
    xpctxt->doc = olddoc;
9688
782k
    xpctxt->contextSize = oldcs;
9689
782k
    xpctxt->proximityPosition = oldpp;
9690
782k
}
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
573k
{
9711
573k
    if (op->ch1 != -1) {
9712
6.81k
  xmlXPathCompExprPtr comp = ctxt->comp;
9713
  /*
9714
  * Process inner predicates first.
9715
  */
9716
6.81k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9717
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9718
0
  }
9719
6.81k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9720
6.80k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9721
6.80k
        ctxt->context->depth += 1;
9722
6.80k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9723
6.80k
                                    1, set->nodeNr, hasNsNodes);
9724
6.80k
        ctxt->context->depth -= 1;
9725
6.80k
  CHECK_ERROR;
9726
6.80k
    }
9727
9728
571k
    if (op->ch2 != -1)
9729
571k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9730
571k
}
9731
9732
static int
9733
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9734
          xmlXPathStepOpPtr op,
9735
          int *maxPos)
9736
274k
{
9737
9738
274k
    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
274k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9754
0
  return(0);
9755
9756
274k
    if (op->ch2 != -1) {
9757
274k
  exprOp = &ctxt->comp->steps[op->ch2];
9758
274k
    } else
9759
0
  return(0);
9760
9761
274k
    if ((exprOp != NULL) &&
9762
274k
  (exprOp->op == XPATH_OP_VALUE) &&
9763
153k
  (exprOp->value4 != NULL) &&
9764
153k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9765
103k
    {
9766
103k
        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
103k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9780
99.0k
      *maxPos = (int) floatval;
9781
99.0k
            if (floatval == (double) *maxPos)
9782
95.2k
                return(1);
9783
99.0k
        }
9784
103k
    }
9785
179k
    return(0);
9786
274k
}
9787
9788
static int
9789
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9790
                           xmlXPathStepOpPtr op,
9791
         xmlNodePtr * first, xmlNodePtr * last,
9792
         int toBool)
9793
3.17M
{
9794
9795
3.17M
#define XP_TEST_HIT \
9796
60.8M
    if (hasAxisRange != 0) { \
9797
371k
  if (++pos == maxPos) { \
9798
42.4k
      if (addNode(seq, cur) < 0) \
9799
42.4k
          xmlXPathPErrMemory(ctxt); \
9800
42.4k
      goto axis_range_end; } \
9801
60.4M
    } else { \
9802
60.4M
  if (addNode(seq, cur) < 0) \
9803
60.4M
      xmlXPathPErrMemory(ctxt); \
9804
60.4M
  if (breakOnFirstHit) goto first_hit; }
9805
9806
3.17M
#define XP_TEST_HIT_NS \
9807
3.17M
    if (hasAxisRange != 0) { \
9808
8.10k
  if (++pos == maxPos) { \
9809
3.84k
      hasNsNodes = 1; \
9810
3.84k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9811
3.84k
          xmlXPathPErrMemory(ctxt); \
9812
3.84k
  goto axis_range_end; } \
9813
3.16M
    } else { \
9814
3.16M
  hasNsNodes = 1; \
9815
3.16M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9816
3.16M
      xmlXPathPErrMemory(ctxt); \
9817
3.16M
  if (breakOnFirstHit) goto first_hit; }
9818
9819
3.17M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9820
3.17M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9821
3.17M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9822
3.17M
    const xmlChar *prefix = op->value4;
9823
3.17M
    const xmlChar *name = op->value5;
9824
3.17M
    const xmlChar *URI = NULL;
9825
9826
3.17M
    int total = 0, hasNsNodes = 0;
9827
    /* The popped object holding the context nodes */
9828
3.17M
    xmlXPathObjectPtr obj;
9829
    /* The set of context nodes for the node tests */
9830
3.17M
    xmlNodeSetPtr contextSeq;
9831
3.17M
    int contextIdx;
9832
3.17M
    xmlNodePtr contextNode;
9833
    /* The final resulting node set wrt to all context nodes */
9834
3.17M
    xmlNodeSetPtr outSeq;
9835
    /*
9836
    * The temporary resulting node set wrt 1 context node.
9837
    * Used to feed predicate evaluation.
9838
    */
9839
3.17M
    xmlNodeSetPtr seq;
9840
3.17M
    xmlNodePtr cur;
9841
    /* First predicate operator */
9842
3.17M
    xmlXPathStepOpPtr predOp;
9843
3.17M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9844
3.17M
    int hasPredicateRange, hasAxisRange, pos;
9845
3.17M
    int breakOnFirstHit;
9846
9847
3.17M
    xmlXPathTraversalFunction next = NULL;
9848
3.17M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9849
3.17M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9850
3.17M
    xmlNodePtr oldContextNode;
9851
3.17M
    xmlXPathContextPtr xpctxt = ctxt->context;
9852
9853
9854
3.17M
    CHECK_TYPE0(XPATH_NODESET);
9855
3.17M
    obj = xmlXPathValuePop(ctxt);
9856
    /*
9857
    * Setup namespaces.
9858
    */
9859
3.17M
    if (prefix != NULL) {
9860
14.8k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9861
14.8k
        if (URI == NULL) {
9862
381
      xmlXPathReleaseObject(xpctxt, obj);
9863
381
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9864
381
                           "Undefined namespace prefix: %s\n", prefix);
9865
381
            return 0;
9866
381
  }
9867
14.8k
    }
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
3.17M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9882
3.17M
    switch (axis) {
9883
27.7k
        case AXIS_ANCESTOR:
9884
27.7k
            first = NULL;
9885
27.7k
            next = xmlXPathNextAncestor;
9886
27.7k
            break;
9887
8.35k
        case AXIS_ANCESTOR_OR_SELF:
9888
8.35k
            first = NULL;
9889
8.35k
            next = xmlXPathNextAncestorOrSelf;
9890
8.35k
            break;
9891
60.5k
        case AXIS_ATTRIBUTE:
9892
60.5k
            first = NULL;
9893
60.5k
      last = NULL;
9894
60.5k
            next = xmlXPathNextAttribute;
9895
60.5k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9896
60.5k
            break;
9897
2.37M
        case AXIS_CHILD:
9898
2.37M
      last = NULL;
9899
2.37M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9900
2.32M
    (type == NODE_TYPE_NODE))
9901
2.32M
      {
9902
    /*
9903
    * Optimization if an element node type is 'element'.
9904
    */
9905
2.32M
    next = xmlXPathNextChildElement;
9906
2.32M
      } else
9907
54.6k
    next = xmlXPathNextChild;
9908
2.37M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9909
2.37M
            break;
9910
89.0k
        case AXIS_DESCENDANT:
9911
89.0k
      last = NULL;
9912
89.0k
            next = xmlXPathNextDescendant;
9913
89.0k
            break;
9914
489k
        case AXIS_DESCENDANT_OR_SELF:
9915
489k
      last = NULL;
9916
489k
            next = xmlXPathNextDescendantOrSelf;
9917
489k
            break;
9918
3.09k
        case AXIS_FOLLOWING:
9919
3.09k
      last = NULL;
9920
3.09k
            next = xmlXPathNextFollowing;
9921
3.09k
            break;
9922
2.52k
        case AXIS_FOLLOWING_SIBLING:
9923
2.52k
      last = NULL;
9924
2.52k
            next = xmlXPathNextFollowingSibling;
9925
2.52k
            break;
9926
31.2k
        case AXIS_NAMESPACE:
9927
31.2k
            first = NULL;
9928
31.2k
      last = NULL;
9929
31.2k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9930
31.2k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9931
31.2k
            break;
9932
57.3k
        case AXIS_PARENT:
9933
57.3k
            first = NULL;
9934
57.3k
            next = xmlXPathNextParent;
9935
57.3k
            break;
9936
23.3k
        case AXIS_PRECEDING:
9937
23.3k
            first = NULL;
9938
23.3k
            next = xmlXPathNextPrecedingInternal;
9939
23.3k
            break;
9940
2.86k
        case AXIS_PRECEDING_SIBLING:
9941
2.86k
            first = NULL;
9942
2.86k
            next = xmlXPathNextPrecedingSibling;
9943
2.86k
            break;
9944
3.41k
        case AXIS_SELF:
9945
3.41k
            first = NULL;
9946
3.41k
      last = NULL;
9947
3.41k
            next = xmlXPathNextSelf;
9948
3.41k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9949
3.41k
            break;
9950
3.17M
    }
9951
9952
3.17M
    if (next == NULL) {
9953
0
  xmlXPathReleaseObject(xpctxt, obj);
9954
0
        return(0);
9955
0
    }
9956
3.17M
    contextSeq = obj->nodesetval;
9957
3.17M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9958
114k
        xmlXPathValuePush(ctxt, obj);
9959
114k
        return(0);
9960
114k
    }
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
3.06M
    maxPos = 0;
9980
3.06M
    predOp = NULL;
9981
3.06M
    hasPredicateRange = 0;
9982
3.06M
    hasAxisRange = 0;
9983
3.06M
    if (op->ch2 != -1) {
9984
  /*
9985
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9986
  */
9987
274k
  predOp = &ctxt->comp->steps[op->ch2];
9988
274k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9989
95.2k
      if (predOp->ch1 != -1) {
9990
    /*
9991
    * Use the next inner predicate operator.
9992
    */
9993
36.9k
    predOp = &ctxt->comp->steps[predOp->ch1];
9994
36.9k
    hasPredicateRange = 1;
9995
58.3k
      } else {
9996
    /*
9997
    * There's no other predicate than the [n] predicate.
9998
    */
9999
58.3k
    predOp = NULL;
10000
58.3k
    hasAxisRange = 1;
10001
58.3k
      }
10002
95.2k
  }
10003
274k
    }
10004
3.06M
    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
3.06M
    oldContextNode = xpctxt->node;
10019
3.06M
    addNode = xmlXPathNodeSetAddUnique;
10020
3.06M
    outSeq = NULL;
10021
3.06M
    seq = NULL;
10022
3.06M
    contextNode = NULL;
10023
3.06M
    contextIdx = 0;
10024
10025
10026
12.4M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10027
9.50M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
10028
9.50M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
10029
10030
9.50M
  if (seq == NULL) {
10031
3.17M
      seq = xmlXPathNodeSetCreate(NULL);
10032
3.17M
      if (seq == NULL) {
10033
298
                xmlXPathPErrMemory(ctxt);
10034
298
    total = 0;
10035
298
    goto error;
10036
298
      }
10037
3.17M
  }
10038
  /*
10039
  * Traverse the axis and test the nodes.
10040
  */
10041
9.50M
  pos = 0;
10042
9.50M
  cur = NULL;
10043
9.50M
  hasNsNodes = 0;
10044
81.2M
        do {
10045
81.2M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10046
246
                goto error;
10047
10048
81.2M
            cur = next(ctxt, cur);
10049
81.2M
            if (cur == NULL)
10050
9.35M
                break;
10051
10052
      /*
10053
      * QUESTION TODO: What does the "first" and "last" stuff do?
10054
      */
10055
71.9M
            if ((first != NULL) && (*first != NULL)) {
10056
570k
    if (*first == cur)
10057
12.9k
        break;
10058
557k
    if (((total % 256) == 0) &&
10059
10.0k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10060
10.0k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10061
#else
10062
        (xmlXPathCmpNodes(*first, cur) >= 0))
10063
#endif
10064
4.87k
    {
10065
4.87k
        break;
10066
4.87k
    }
10067
557k
      }
10068
71.8M
      if ((last != NULL) && (*last != NULL)) {
10069
17.4k
    if (*last == cur)
10070
1.93k
        break;
10071
15.5k
    if (((total % 256) == 0) &&
10072
14.4k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10073
14.4k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10074
#else
10075
        (xmlXPathCmpNodes(cur, *last) >= 0))
10076
#endif
10077
13.3k
    {
10078
13.3k
        break;
10079
13.3k
    }
10080
15.5k
      }
10081
10082
71.8M
            total++;
10083
10084
71.8M
      switch (test) {
10085
0
                case NODE_TEST_NONE:
10086
0
        total = 0;
10087
0
        goto error;
10088
53.9M
                case NODE_TEST_TYPE:
10089
53.9M
        if (type == NODE_TYPE_NODE) {
10090
53.3M
      switch (cur->type) {
10091
431k
          case XML_DOCUMENT_NODE:
10092
432k
          case XML_HTML_DOCUMENT_NODE:
10093
33.0M
          case XML_ELEMENT_NODE:
10094
33.0M
          case XML_ATTRIBUTE_NODE:
10095
33.2M
          case XML_PI_NODE:
10096
33.3M
          case XML_COMMENT_NODE:
10097
33.5M
          case XML_CDATA_SECTION_NODE:
10098
53.2M
          case XML_TEXT_NODE:
10099
53.2M
        XP_TEST_HIT
10100
53.2M
        break;
10101
53.2M
          case XML_NAMESPACE_DECL: {
10102
51.4k
        if (axis == AXIS_NAMESPACE) {
10103
17.7k
            XP_TEST_HIT_NS
10104
33.6k
        } else {
10105
33.6k
                              hasNsNodes = 1;
10106
33.6k
            XP_TEST_HIT
10107
33.6k
        }
10108
48.3k
        break;
10109
51.4k
                            }
10110
60.8k
          default:
10111
60.8k
        break;
10112
53.3M
      }
10113
53.3M
        } else if (cur->type == (xmlElementType) type) {
10114
239k
      if (cur->type == XML_NAMESPACE_DECL)
10115
0
          XP_TEST_HIT_NS
10116
239k
      else
10117
239k
          XP_TEST_HIT
10118
321k
        } else if ((type == NODE_TYPE_TEXT) &&
10119
319k
       (cur->type == XML_CDATA_SECTION_NODE))
10120
45.5k
        {
10121
45.5k
      XP_TEST_HIT
10122
45.5k
        }
10123
53.9M
        break;
10124
53.9M
                case NODE_TEST_PI:
10125
644k
                    if ((cur->type == XML_PI_NODE) &&
10126
43.8k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10127
43.4k
        {
10128
43.4k
      XP_TEST_HIT
10129
43.4k
                    }
10130
643k
                    break;
10131
13.2M
                case NODE_TEST_ALL:
10132
13.2M
                    if (axis == AXIS_ATTRIBUTE) {
10133
46.6k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10134
46.6k
      {
10135
46.6k
                            if (prefix == NULL)
10136
43.7k
          {
10137
43.7k
        XP_TEST_HIT
10138
43.7k
                            } else if ((cur->ns != NULL) &&
10139
2.21k
        (xmlStrEqual(URI, cur->ns->href)))
10140
1.97k
          {
10141
1.97k
        XP_TEST_HIT
10142
1.97k
                            }
10143
46.6k
                        }
10144
13.2M
                    } else if (axis == AXIS_NAMESPACE) {
10145
3.14M
                        if (cur->type == XML_NAMESPACE_DECL)
10146
3.14M
      {
10147
3.14M
          XP_TEST_HIT_NS
10148
3.14M
                        }
10149
10.0M
                    } else {
10150
10.0M
                        if (cur->type == XML_ELEMENT_NODE) {
10151
6.79M
                            if (prefix == NULL)
10152
6.76M
          {
10153
6.76M
        XP_TEST_HIT
10154
10155
6.76M
                            } else if ((cur->ns != NULL) &&
10156
4.57k
        (xmlStrEqual(URI, cur->ns->href)))
10157
2.73k
          {
10158
2.73k
        XP_TEST_HIT
10159
2.73k
                            }
10160
6.79M
                        }
10161
10.0M
                    }
10162
13.1M
                    break;
10163
13.1M
                case NODE_TEST_NS:{
10164
                        /* TODO */
10165
0
                        break;
10166
13.2M
                    }
10167
4.03M
                case NODE_TEST_NAME:
10168
4.03M
                    if (axis == AXIS_ATTRIBUTE) {
10169
11.0k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10170
0
          break;
10171
4.01M
        } else if (axis == AXIS_NAMESPACE) {
10172
12.3k
                        if (cur->type != XML_NAMESPACE_DECL)
10173
0
          break;
10174
4.00M
        } else {
10175
4.00M
            if (cur->type != XML_ELEMENT_NODE)
10176
608k
          break;
10177
4.00M
        }
10178
3.42M
                    switch (cur->type) {
10179
3.39M
                        case XML_ELEMENT_NODE:
10180
3.39M
                            if (xmlStrEqual(name, cur->name)) {
10181
413k
                                if (prefix == NULL) {
10182
400k
                                    if (cur->ns == NULL)
10183
398k
            {
10184
398k
          XP_TEST_HIT
10185
398k
                                    }
10186
400k
                                } else {
10187
12.0k
                                    if ((cur->ns != NULL) &&
10188
7.89k
                                        (xmlStrEqual(URI, cur->ns->href)))
10189
2.27k
            {
10190
2.27k
          XP_TEST_HIT
10191
2.27k
                                    }
10192
12.0k
                                }
10193
413k
                            }
10194
3.38M
                            break;
10195
3.38M
                        case XML_ATTRIBUTE_NODE:{
10196
11.0k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10197
10198
11.0k
                                if (xmlStrEqual(name, attr->name)) {
10199
7.87k
                                    if (prefix == NULL) {
10200
5.20k
                                        if ((attr->ns == NULL) ||
10201
515
                                            (attr->ns->prefix == NULL))
10202
4.69k
          {
10203
4.69k
              XP_TEST_HIT
10204
4.69k
                                        }
10205
5.20k
                                    } else {
10206
2.66k
                                        if ((attr->ns != NULL) &&
10207
1.95k
                                            (xmlStrEqual(URI,
10208
1.95k
                attr->ns->href)))
10209
1.51k
          {
10210
1.51k
              XP_TEST_HIT
10211
1.51k
                                        }
10212
2.66k
                                    }
10213
7.87k
                                }
10214
8.72k
                                break;
10215
11.0k
                            }
10216
12.3k
                        case XML_NAMESPACE_DECL:
10217
12.3k
                            if (cur->type == XML_NAMESPACE_DECL) {
10218
12.3k
                                xmlNsPtr ns = (xmlNsPtr) cur;
10219
10220
12.3k
                                if ((ns->prefix != NULL) && (name != NULL)
10221
10.4k
                                    && (xmlStrEqual(ns->prefix, name)))
10222
4.83k
        {
10223
4.83k
            XP_TEST_HIT_NS
10224
4.83k
                                }
10225
12.3k
                            }
10226
10.9k
                            break;
10227
10.9k
                        default:
10228
0
                            break;
10229
3.42M
                    }
10230
3.40M
                    break;
10231
71.8M
      } /* switch(test) */
10232
71.8M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10233
10234
9.38M
  goto apply_predicates;
10235
10236
9.38M
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
46.2k
  if (outSeq == NULL) {
10244
29.3k
      outSeq = seq;
10245
29.3k
      seq = NULL;
10246
29.3k
  } else {
10247
16.8k
      outSeq = mergeAndClear(outSeq, seq);
10248
16.8k
            if (outSeq == NULL)
10249
14
                xmlXPathPErrMemory(ctxt);
10250
16.8k
        }
10251
  /*
10252
  * Break if only a true/false result was requested.
10253
  */
10254
46.2k
  if (toBool)
10255
20.1k
      break;
10256
26.1k
  continue;
10257
10258
66.7k
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
66.7k
  if (outSeq == NULL) {
10264
66.7k
      outSeq = seq;
10265
66.7k
      seq = NULL;
10266
66.7k
  } else {
10267
0
      outSeq = mergeAndClear(outSeq, seq);
10268
0
            if (outSeq == NULL)
10269
0
                xmlXPathPErrMemory(ctxt);
10270
0
        }
10271
66.7k
  break;
10272
10273
9.38M
apply_predicates: /* --------------------------------------------------- */
10274
9.38M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10275
470
      goto error;
10276
10277
        /*
10278
  * Apply predicates.
10279
  */
10280
9.38M
        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
566k
      if (hasPredicateRange != 0)
10310
18.5k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10311
18.5k
              hasNsNodes);
10312
547k
      else
10313
547k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10314
547k
              hasNsNodes);
10315
10316
566k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10317
4.31k
    total = 0;
10318
4.31k
    goto error;
10319
4.31k
      }
10320
566k
        }
10321
10322
9.38M
        if (seq->nodeNr > 0) {
10323
      /*
10324
      * Add to result set.
10325
      */
10326
3.72M
      if (outSeq == NULL) {
10327
937k
    outSeq = seq;
10328
937k
    seq = NULL;
10329
2.79M
      } else {
10330
2.79M
    outSeq = mergeAndClear(outSeq, seq);
10331
2.79M
                if (outSeq == NULL)
10332
273
                    xmlXPathPErrMemory(ctxt);
10333
2.79M
      }
10334
10335
3.72M
            if (toBool)
10336
13.3k
                break;
10337
3.72M
  }
10338
9.38M
    }
10339
10340
3.06M
error:
10341
3.06M
    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
3.06M
    xmlXPathReleaseObject(xpctxt, obj);
10353
10354
    /*
10355
    * Ensure we return at least an empty set.
10356
    */
10357
3.06M
    if (outSeq == NULL) {
10358
2.02M
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10359
2.02M
      outSeq = seq;
10360
2.02M
        } else {
10361
638
      outSeq = xmlXPathNodeSetCreate(NULL);
10362
638
            if (outSeq == NULL)
10363
3
                xmlXPathPErrMemory(ctxt);
10364
638
        }
10365
2.02M
    }
10366
3.06M
    if ((seq != NULL) && (seq != outSeq)) {
10367
109k
   xmlXPathFreeNodeSet(seq);
10368
109k
    }
10369
    /*
10370
    * Hand over the result. Better to push the set also in
10371
    * case of errors.
10372
    */
10373
3.06M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10374
    /*
10375
    * Reset the context node.
10376
    */
10377
3.06M
    xpctxt->node = oldContextNode;
10378
    /*
10379
    * When traversing the namespace axis in "toBool" mode, it's
10380
    * possible that tmpNsList wasn't freed.
10381
    */
10382
3.06M
    if (xpctxt->tmpNsList != NULL) {
10383
934
        xmlFree(xpctxt->tmpNsList);
10384
934
        xpctxt->tmpNsList = NULL;
10385
934
    }
10386
10387
3.06M
    return(total);
10388
3.06M
}
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
369k
{
10407
369k
    int total = 0, cur;
10408
369k
    xmlXPathCompExprPtr comp;
10409
369k
    xmlXPathObjectPtr arg1, arg2;
10410
10411
369k
    CHECK_ERROR0;
10412
369k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10413
5
        return(0);
10414
369k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10415
369k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10416
369k
    ctxt->context->depth += 1;
10417
369k
    comp = ctxt->comp;
10418
369k
    switch (op->op) {
10419
0
        case XPATH_OP_END:
10420
0
            break;
10421
82.8k
        case XPATH_OP_UNION:
10422
82.8k
            total =
10423
82.8k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10424
82.8k
                                        first);
10425
82.8k
      CHECK_ERROR0;
10426
74.4k
            if ((ctxt->value != NULL)
10427
74.4k
                && (ctxt->value->type == XPATH_NODESET)
10428
74.3k
                && (ctxt->value->nodesetval != NULL)
10429
74.3k
                && (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
45.5k
    if (ctxt->value->nodesetval->nodeNr > 1)
10441
33.2k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10442
45.5k
                *first = ctxt->value->nodesetval->nodeTab[0];
10443
45.5k
            }
10444
74.4k
            cur =
10445
74.4k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10446
74.4k
                                        first);
10447
74.4k
      CHECK_ERROR0;
10448
10449
74.3k
            arg2 = xmlXPathValuePop(ctxt);
10450
74.3k
            arg1 = xmlXPathValuePop(ctxt);
10451
74.3k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10452
74.2k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10453
81
          xmlXPathReleaseObject(ctxt->context, arg1);
10454
81
          xmlXPathReleaseObject(ctxt->context, arg2);
10455
81
                XP_ERROR0(XPATH_INVALID_TYPE);
10456
0
            }
10457
74.2k
            if ((ctxt->context->opLimit != 0) &&
10458
69.3k
                (((arg1->nodesetval != NULL) &&
10459
69.3k
                  (xmlXPathCheckOpLimit(ctxt,
10460
69.3k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10461
69.3k
                 ((arg2->nodesetval != NULL) &&
10462
69.3k
                  (xmlXPathCheckOpLimit(ctxt,
10463
69.3k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10464
6
          xmlXPathReleaseObject(ctxt->context, arg1);
10465
6
          xmlXPathReleaseObject(ctxt->context, arg2);
10466
6
                break;
10467
6
            }
10468
10469
74.2k
            if ((arg2->nodesetval != NULL) &&
10470
74.2k
                (arg2->nodesetval->nodeNr != 0)) {
10471
59.2k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10472
59.2k
                                                        arg2->nodesetval);
10473
59.2k
                if (arg1->nodesetval == NULL)
10474
8
                    xmlXPathPErrMemory(ctxt);
10475
59.2k
            }
10476
74.2k
            xmlXPathValuePush(ctxt, arg1);
10477
74.2k
      xmlXPathReleaseObject(ctxt->context, arg2);
10478
74.2k
            total += cur;
10479
74.2k
            break;
10480
11.5k
        case XPATH_OP_ROOT:
10481
11.5k
            xmlXPathRoot(ctxt);
10482
11.5k
            break;
10483
35.7k
        case XPATH_OP_NODE:
10484
35.7k
            if (op->ch1 != -1)
10485
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10486
35.7k
      CHECK_ERROR0;
10487
35.7k
            if (op->ch2 != -1)
10488
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10489
35.7k
      CHECK_ERROR0;
10490
35.7k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10491
35.7k
    ctxt->context->node));
10492
35.7k
            break;
10493
60.8k
        case XPATH_OP_COLLECT:{
10494
60.8k
                if (op->ch1 == -1)
10495
0
                    break;
10496
10497
60.8k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10498
60.8k
    CHECK_ERROR0;
10499
10500
60.6k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10501
60.6k
                break;
10502
60.8k
            }
10503
185
        case XPATH_OP_VALUE:
10504
185
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10505
185
            break;
10506
37.9k
        case XPATH_OP_SORT:
10507
37.9k
            if (op->ch1 != -1)
10508
37.9k
                total +=
10509
37.9k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10510
37.9k
                                            first);
10511
37.9k
      CHECK_ERROR0;
10512
37.3k
            if ((ctxt->value != NULL)
10513
37.3k
                && (ctxt->value->type == XPATH_NODESET)
10514
35.5k
                && (ctxt->value->nodesetval != NULL)
10515
35.5k
    && (ctxt->value->nodesetval->nodeNr > 1))
10516
19.2k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10517
37.3k
            break;
10518
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10519
138k
  case XPATH_OP_FILTER:
10520
138k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10521
138k
            break;
10522
0
#endif
10523
1.80k
        default:
10524
1.80k
            total += xmlXPathCompOpEval(ctxt, op);
10525
1.80k
            break;
10526
369k
    }
10527
10528
359k
    ctxt->context->depth -= 1;
10529
359k
    return(total);
10530
369k
}
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
247k
{
10545
247k
    int total = 0, cur;
10546
247k
    xmlXPathCompExprPtr comp;
10547
247k
    xmlXPathObjectPtr arg1, arg2;
10548
10549
247k
    CHECK_ERROR0;
10550
247k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10551
4
        return(0);
10552
247k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10553
247k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10554
247k
    ctxt->context->depth += 1;
10555
247k
    comp = ctxt->comp;
10556
247k
    switch (op->op) {
10557
0
        case XPATH_OP_END:
10558
0
            break;
10559
92.9k
        case XPATH_OP_UNION:
10560
92.9k
            total =
10561
92.9k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10562
92.9k
      CHECK_ERROR0;
10563
80.3k
            if ((ctxt->value != NULL)
10564
80.3k
                && (ctxt->value->type == XPATH_NODESET)
10565
80.3k
                && (ctxt->value->nodesetval != NULL)
10566
80.3k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10567
                /*
10568
                 * limit tree traversing to first node in the result
10569
                 */
10570
63.3k
    if (ctxt->value->nodesetval->nodeNr > 1)
10571
39.6k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10572
63.3k
                *last =
10573
63.3k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10574
63.3k
                                                     nodesetval->nodeNr -
10575
63.3k
                                                     1];
10576
63.3k
            }
10577
80.3k
            cur =
10578
80.3k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10579
80.3k
      CHECK_ERROR0;
10580
80.1k
            if ((ctxt->value != NULL)
10581
80.1k
                && (ctxt->value->type == XPATH_NODESET)
10582
80.0k
                && (ctxt->value->nodesetval != NULL)
10583
80.0k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10584
52.0k
            }
10585
10586
80.1k
            arg2 = xmlXPathValuePop(ctxt);
10587
80.1k
            arg1 = xmlXPathValuePop(ctxt);
10588
80.1k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10589
80.0k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10590
117
          xmlXPathReleaseObject(ctxt->context, arg1);
10591
117
          xmlXPathReleaseObject(ctxt->context, arg2);
10592
117
                XP_ERROR0(XPATH_INVALID_TYPE);
10593
0
            }
10594
80.0k
            if ((ctxt->context->opLimit != 0) &&
10595
75.3k
                (((arg1->nodesetval != NULL) &&
10596
75.3k
                  (xmlXPathCheckOpLimit(ctxt,
10597
75.3k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10598
75.3k
                 ((arg2->nodesetval != NULL) &&
10599
75.3k
                  (xmlXPathCheckOpLimit(ctxt,
10600
75.3k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10601
5
          xmlXPathReleaseObject(ctxt->context, arg1);
10602
5
          xmlXPathReleaseObject(ctxt->context, arg2);
10603
5
                break;
10604
5
            }
10605
10606
79.9k
            if ((arg2->nodesetval != NULL) &&
10607
79.9k
                (arg2->nodesetval->nodeNr != 0)) {
10608
52.0k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10609
52.0k
                                                        arg2->nodesetval);
10610
52.0k
                if (arg1->nodesetval == NULL)
10611
8
                    xmlXPathPErrMemory(ctxt);
10612
52.0k
            }
10613
79.9k
            xmlXPathValuePush(ctxt, arg1);
10614
79.9k
      xmlXPathReleaseObject(ctxt->context, arg2);
10615
79.9k
            total += cur;
10616
79.9k
            break;
10617
14.3k
        case XPATH_OP_ROOT:
10618
14.3k
            xmlXPathRoot(ctxt);
10619
14.3k
            break;
10620
26.9k
        case XPATH_OP_NODE:
10621
26.9k
            if (op->ch1 != -1)
10622
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10623
26.9k
      CHECK_ERROR0;
10624
26.9k
            if (op->ch2 != -1)
10625
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10626
26.9k
      CHECK_ERROR0;
10627
26.9k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10628
26.9k
    ctxt->context->node));
10629
26.9k
            break;
10630
73.1k
        case XPATH_OP_COLLECT:{
10631
73.1k
                if (op->ch1 == -1)
10632
0
                    break;
10633
10634
73.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10635
73.1k
    CHECK_ERROR0;
10636
10637
73.0k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10638
73.0k
                break;
10639
73.1k
            }
10640
132
        case XPATH_OP_VALUE:
10641
132
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10642
132
            break;
10643
37.5k
        case XPATH_OP_SORT:
10644
37.5k
            if (op->ch1 != -1)
10645
37.5k
                total +=
10646
37.5k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10647
37.5k
                                           last);
10648
37.5k
      CHECK_ERROR0;
10649
36.8k
            if ((ctxt->value != NULL)
10650
36.8k
                && (ctxt->value->type == XPATH_NODESET)
10651
34.6k
                && (ctxt->value->nodesetval != NULL)
10652
34.6k
    && (ctxt->value->nodesetval->nodeNr > 1))
10653
16.6k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10654
36.8k
            break;
10655
2.37k
        default:
10656
2.37k
            total += xmlXPathCompOpEval(ctxt, op);
10657
2.37k
            break;
10658
247k
    }
10659
10660
233k
    ctxt->context->depth -= 1;
10661
233k
    return (total);
10662
247k
}
10663
10664
#ifdef XP_OPTIMIZED_FILTER_FIRST
10665
static int
10666
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10667
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10668
138k
{
10669
138k
    int total = 0;
10670
138k
    xmlXPathCompExprPtr comp;
10671
138k
    xmlXPathObjectPtr obj;
10672
138k
    xmlNodeSetPtr set;
10673
10674
138k
    CHECK_ERROR0;
10675
138k
    comp = ctxt->comp;
10676
    /*
10677
    * Optimization for ()[last()] selection i.e. the last elem
10678
    */
10679
138k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10680
138k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10681
118k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10682
10.6k
  int f = comp->steps[op->ch2].ch1;
10683
10684
10.6k
  if ((f != -1) &&
10685
10.6k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10686
8.90k
      (comp->steps[f].value5 == NULL) &&
10687
7.93k
      (comp->steps[f].value == 0) &&
10688
6.99k
      (comp->steps[f].value4 != NULL) &&
10689
6.99k
      (xmlStrEqual
10690
6.99k
      (comp->steps[f].value4, BAD_CAST "last"))) {
10691
6.03k
      xmlNodePtr last = NULL;
10692
10693
6.03k
      total +=
10694
6.03k
    xmlXPathCompOpEvalLast(ctxt,
10695
6.03k
        &comp->steps[op->ch1],
10696
6.03k
        &last);
10697
6.03k
      CHECK_ERROR0;
10698
      /*
10699
      * The nodeset should be in document order,
10700
      * Keep only the last value
10701
      */
10702
5.95k
      if ((ctxt->value != NULL) &&
10703
5.95k
    (ctxt->value->type == XPATH_NODESET) &&
10704
5.09k
    (ctxt->value->nodesetval != NULL) &&
10705
5.09k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10706
4.02k
    (ctxt->value->nodesetval->nodeNr > 1)) {
10707
1.86k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10708
1.86k
    *first = *(ctxt->value->nodesetval->nodeTab);
10709
1.86k
      }
10710
5.95k
      return (total);
10711
6.03k
  }
10712
10.6k
    }
10713
10714
132k
    if (op->ch1 != -1)
10715
132k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10716
132k
    CHECK_ERROR0;
10717
129k
    if (op->ch2 == -1)
10718
0
  return (total);
10719
129k
    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
129k
    CHECK_TYPE0(XPATH_NODESET);
10728
129k
    obj = xmlXPathValuePop(ctxt);
10729
129k
    set = obj->nodesetval;
10730
129k
    if (set != NULL) {
10731
129k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10732
129k
        if (set->nodeNr > 0)
10733
106k
            *first = set->nodeTab[0];
10734
129k
    }
10735
129k
    xmlXPathValuePush(ctxt, obj);
10736
10737
129k
    return (total);
10738
129k
}
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
14.3M
{
10751
14.3M
    int total = 0;
10752
14.3M
    int equal, ret;
10753
14.3M
    xmlXPathCompExprPtr comp;
10754
14.3M
    xmlXPathObjectPtr arg1, arg2;
10755
10756
14.3M
    CHECK_ERROR0;
10757
14.3M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10758
275
        return(0);
10759
14.3M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10760
14.3M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10761
14.3M
    ctxt->context->depth += 1;
10762
14.3M
    comp = ctxt->comp;
10763
14.3M
    switch (op->op) {
10764
0
        case XPATH_OP_END:
10765
0
            break;
10766
6.43k
        case XPATH_OP_AND:
10767
6.43k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10768
6.43k
      CHECK_ERROR0;
10769
5.22k
            xmlXPathBooleanFunction(ctxt, 1);
10770
5.22k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10771
2.68k
                break;
10772
2.53k
            arg2 = xmlXPathValuePop(ctxt);
10773
2.53k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10774
2.53k
      if (ctxt->error) {
10775
111
    xmlXPathFreeObject(arg2);
10776
111
    break;
10777
111
      }
10778
2.42k
            xmlXPathBooleanFunction(ctxt, 1);
10779
2.42k
            if (ctxt->value != NULL)
10780
2.41k
                ctxt->value->boolval &= arg2->boolval;
10781
2.42k
      xmlXPathReleaseObject(ctxt->context, arg2);
10782
2.42k
            break;
10783
26.8k
        case XPATH_OP_OR:
10784
26.8k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10785
26.8k
      CHECK_ERROR0;
10786
25.3k
            xmlXPathBooleanFunction(ctxt, 1);
10787
25.3k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10788
12.7k
                break;
10789
12.5k
            arg2 = xmlXPathValuePop(ctxt);
10790
12.5k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10791
12.5k
      if (ctxt->error) {
10792
306
    xmlXPathFreeObject(arg2);
10793
306
    break;
10794
306
      }
10795
12.2k
            xmlXPathBooleanFunction(ctxt, 1);
10796
12.2k
            if (ctxt->value != NULL)
10797
12.2k
                ctxt->value->boolval |= arg2->boolval;
10798
12.2k
      xmlXPathReleaseObject(ctxt->context, arg2);
10799
12.2k
            break;
10800
704k
        case XPATH_OP_EQUAL:
10801
704k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10802
704k
      CHECK_ERROR0;
10803
684k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10804
684k
      CHECK_ERROR0;
10805
681k
      if (op->value)
10806
595k
    equal = xmlXPathEqualValues(ctxt);
10807
86.8k
      else
10808
86.8k
    equal = xmlXPathNotEqualValues(ctxt);
10809
681k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10810
681k
            break;
10811
369k
        case XPATH_OP_CMP:
10812
369k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10813
369k
      CHECK_ERROR0;
10814
367k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10815
367k
      CHECK_ERROR0;
10816
365k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10817
365k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10818
365k
            break;
10819
574k
        case XPATH_OP_PLUS:
10820
574k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10821
574k
      CHECK_ERROR0;
10822
566k
            if (op->ch2 != -1) {
10823
272k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10824
272k
      }
10825
566k
      CHECK_ERROR0;
10826
563k
            if (op->value == 0)
10827
172k
                xmlXPathSubValues(ctxt);
10828
390k
            else if (op->value == 1)
10829
95.8k
                xmlXPathAddValues(ctxt);
10830
294k
            else if (op->value == 2)
10831
234k
                xmlXPathValueFlipSign(ctxt);
10832
60.2k
            else if (op->value == 3) {
10833
60.2k
                CAST_TO_NUMBER;
10834
60.2k
                CHECK_TYPE0(XPATH_NUMBER);
10835
60.1k
            }
10836
563k
            break;
10837
732k
        case XPATH_OP_MULT:
10838
732k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10839
732k
      CHECK_ERROR0;
10840
708k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10841
708k
      CHECK_ERROR0;
10842
706k
            if (op->value == 0)
10843
694k
                xmlXPathMultValues(ctxt);
10844
12.7k
            else if (op->value == 1)
10845
8.76k
                xmlXPathDivValues(ctxt);
10846
3.96k
            else if (op->value == 2)
10847
3.96k
                xmlXPathModValues(ctxt);
10848
706k
            break;
10849
413k
        case XPATH_OP_UNION:
10850
413k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10851
413k
      CHECK_ERROR0;
10852
410k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10853
410k
      CHECK_ERROR0;
10854
10855
407k
            arg2 = xmlXPathValuePop(ctxt);
10856
407k
            arg1 = xmlXPathValuePop(ctxt);
10857
407k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10858
407k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10859
348
          xmlXPathReleaseObject(ctxt->context, arg1);
10860
348
          xmlXPathReleaseObject(ctxt->context, arg2);
10861
348
                XP_ERROR0(XPATH_INVALID_TYPE);
10862
0
            }
10863
407k
            if ((ctxt->context->opLimit != 0) &&
10864
384k
                (((arg1->nodesetval != NULL) &&
10865
384k
                  (xmlXPathCheckOpLimit(ctxt,
10866
384k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10867
384k
                 ((arg2->nodesetval != NULL) &&
10868
384k
                  (xmlXPathCheckOpLimit(ctxt,
10869
384k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10870
47
          xmlXPathReleaseObject(ctxt->context, arg1);
10871
47
          xmlXPathReleaseObject(ctxt->context, arg2);
10872
47
                break;
10873
47
            }
10874
10875
407k
      if (((arg2->nodesetval != NULL) &&
10876
407k
     (arg2->nodesetval->nodeNr != 0)))
10877
253k
      {
10878
253k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10879
253k
              arg2->nodesetval);
10880
253k
                if (arg1->nodesetval == NULL)
10881
109
                    xmlXPathPErrMemory(ctxt);
10882
253k
      }
10883
10884
407k
            xmlXPathValuePush(ctxt, arg1);
10885
407k
      xmlXPathReleaseObject(ctxt->context, arg2);
10886
407k
            break;
10887
2.86M
        case XPATH_OP_ROOT:
10888
2.86M
            xmlXPathRoot(ctxt);
10889
2.86M
            break;
10890
2.70M
        case XPATH_OP_NODE:
10891
2.70M
            if (op->ch1 != -1)
10892
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10893
2.70M
      CHECK_ERROR0;
10894
2.70M
            if (op->ch2 != -1)
10895
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10896
2.70M
      CHECK_ERROR0;
10897
2.70M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10898
2.70M
                                                    ctxt->context->node));
10899
2.70M
            break;
10900
2.76M
        case XPATH_OP_COLLECT:{
10901
2.76M
                if (op->ch1 == -1)
10902
0
                    break;
10903
10904
2.76M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10905
2.76M
    CHECK_ERROR0;
10906
10907
2.75M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10908
2.75M
                break;
10909
2.76M
            }
10910
838k
        case XPATH_OP_VALUE:
10911
838k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10912
838k
            break;
10913
336
        case XPATH_OP_VARIABLE:{
10914
336
    xmlXPathObjectPtr val;
10915
10916
336
                if (op->ch1 != -1)
10917
0
                    total +=
10918
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10919
336
                if (op->value5 == NULL) {
10920
247
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10921
247
        if (val == NULL) {
10922
247
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10923
247
                                       "Undefined variable: %s\n", op->value4);
10924
247
                        return 0;
10925
247
                    }
10926
0
                    xmlXPathValuePush(ctxt, val);
10927
89
    } else {
10928
89
                    const xmlChar *URI;
10929
10930
89
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10931
89
                    if (URI == NULL) {
10932
42
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10933
42
                                       "Undefined namespace prefix: %s\n",
10934
42
                                       op->value5);
10935
42
                        return 0;
10936
42
                    }
10937
47
        val = xmlXPathVariableLookupNS(ctxt->context,
10938
47
                                                       op->value4, URI);
10939
47
        if (val == NULL) {
10940
47
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10941
47
                                       "Undefined variable: %s:%s\n",
10942
47
                                       op->value5, op->value4);
10943
47
                        return 0;
10944
47
                    }
10945
0
                    xmlXPathValuePush(ctxt, val);
10946
0
                }
10947
0
                break;
10948
336
            }
10949
756k
        case XPATH_OP_FUNCTION:{
10950
756k
                xmlXPathFunction func;
10951
756k
                const xmlChar *oldFunc, *oldFuncURI;
10952
756k
    int i;
10953
756k
                int frame;
10954
10955
756k
                frame = ctxt->valueNr;
10956
756k
                if (op->ch1 != -1) {
10957
230k
                    total +=
10958
230k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10959
230k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10960
3.03k
                        break;
10961
230k
                }
10962
753k
    if (ctxt->valueNr < frame + op->value)
10963
753k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10964
1.12M
    for (i = 0; i < op->value; i++) {
10965
374k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10966
374k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10967
374k
                }
10968
753k
                if (op->cache != NULL)
10969
737k
                    func = op->cache;
10970
16.3k
                else {
10971
16.3k
                    const xmlChar *URI = NULL;
10972
10973
16.3k
                    if (op->value5 == NULL) {
10974
16.1k
                        func = xmlXPathFunctionLookup(ctxt->context,
10975
16.1k
                                                      op->value4);
10976
16.1k
                        if (func == NULL) {
10977
1.60k
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10978
1.60k
                                           "Unregistered function: %s\n",
10979
1.60k
                                           op->value4);
10980
1.60k
                            return 0;
10981
1.60k
                        }
10982
16.1k
                    } else {
10983
183
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10984
183
                        if (URI == NULL) {
10985
125
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10986
125
                                           "Undefined namespace prefix: %s\n",
10987
125
                                           op->value5);
10988
125
                            return 0;
10989
125
                        }
10990
58
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10991
58
                                                        op->value4, URI);
10992
58
                        if (func == NULL) {
10993
58
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10994
58
                                           "Unregistered function: %s:%s\n",
10995
58
                                           op->value5, op->value4);
10996
58
                            return 0;
10997
58
                        }
10998
58
                    }
10999
14.5k
                    op->cache = func;
11000
14.5k
                    op->cacheURI = (void *) URI;
11001
14.5k
                }
11002
751k
                oldFunc = ctxt->context->function;
11003
751k
                oldFuncURI = ctxt->context->functionURI;
11004
751k
                ctxt->context->function = op->value4;
11005
751k
                ctxt->context->functionURI = op->cacheURI;
11006
751k
                func(ctxt, op->value);
11007
751k
                ctxt->context->function = oldFunc;
11008
751k
                ctxt->context->functionURI = oldFuncURI;
11009
751k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11010
750k
                    (ctxt->valueNr != frame + 1))
11011
751k
                    XP_ERROR0(XPATH_STACK_ERROR);
11012
751k
                break;
11013
751k
            }
11014
458k
        case XPATH_OP_ARG:
11015
458k
            if (op->ch1 != -1) {
11016
228k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11017
228k
          CHECK_ERROR0;
11018
228k
            }
11019
427k
            if (op->ch2 != -1) {
11020
427k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11021
427k
          CHECK_ERROR0;
11022
427k
      }
11023
425k
            break;
11024
425k
        case XPATH_OP_PREDICATE:
11025
431k
        case XPATH_OP_FILTER:{
11026
431k
                xmlXPathObjectPtr obj;
11027
431k
                xmlNodeSetPtr set;
11028
11029
                /*
11030
                 * Optimization for ()[1] selection i.e. the first elem
11031
                 */
11032
431k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11033
431k
#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
431k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11044
278k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11045
#else
11046
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
#endif
11048
405k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11049
188k
                    xmlXPathObjectPtr val;
11050
11051
188k
                    val = comp->steps[op->ch2].value4;
11052
188k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11053
187k
                        (val->floatval == 1.0)) {
11054
173k
                        xmlNodePtr first = NULL;
11055
11056
173k
                        total +=
11057
173k
                            xmlXPathCompOpEvalFirst(ctxt,
11058
173k
                                                    &comp->steps[op->ch1],
11059
173k
                                                    &first);
11060
173k
      CHECK_ERROR0;
11061
                        /*
11062
                         * The nodeset should be in document order,
11063
                         * Keep only the first value
11064
                         */
11065
170k
                        if ((ctxt->value != NULL) &&
11066
170k
                            (ctxt->value->type == XPATH_NODESET) &&
11067
168k
                            (ctxt->value->nodesetval != NULL) &&
11068
168k
                            (ctxt->value->nodesetval->nodeNr > 1))
11069
19.1k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11070
19.1k
                                                        1, 1);
11071
170k
                        break;
11072
173k
                    }
11073
188k
                }
11074
                /*
11075
                 * Optimization for ()[last()] selection i.e. the last elem
11076
                 */
11077
257k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11078
257k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11079
117k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11080
111k
                    int f = comp->steps[op->ch2].ch1;
11081
11082
111k
                    if ((f != -1) &&
11083
111k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11084
46.6k
                        (comp->steps[f].value5 == NULL) &&
11085
45.6k
                        (comp->steps[f].value == 0) &&
11086
33.8k
                        (comp->steps[f].value4 != NULL) &&
11087
33.8k
                        (xmlStrEqual
11088
33.8k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11089
30.5k
                        xmlNodePtr last = NULL;
11090
11091
30.5k
                        total +=
11092
30.5k
                            xmlXPathCompOpEvalLast(ctxt,
11093
30.5k
                                                   &comp->steps[op->ch1],
11094
30.5k
                                                   &last);
11095
30.5k
      CHECK_ERROR0;
11096
                        /*
11097
                         * The nodeset should be in document order,
11098
                         * Keep only the last value
11099
                         */
11100
30.1k
                        if ((ctxt->value != NULL) &&
11101
30.1k
                            (ctxt->value->type == XPATH_NODESET) &&
11102
28.7k
                            (ctxt->value->nodesetval != NULL) &&
11103
28.7k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11104
19.8k
                            (ctxt->value->nodesetval->nodeNr > 1))
11105
14.7k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11106
30.1k
                        break;
11107
30.5k
                    }
11108
111k
                }
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
227k
                if (op->ch1 != -1)
11121
227k
                    total +=
11122
227k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11123
227k
    CHECK_ERROR0;
11124
224k
                if (op->ch2 == -1)
11125
0
                    break;
11126
224k
                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
224k
                CHECK_TYPE0(XPATH_NODESET);
11136
223k
                obj = xmlXPathValuePop(ctxt);
11137
223k
                set = obj->nodesetval;
11138
223k
                if (set != NULL)
11139
223k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11140
223k
                                          1, set->nodeNr, 1);
11141
223k
                xmlXPathValuePush(ctxt, obj);
11142
223k
                break;
11143
224k
            }
11144
676k
        case XPATH_OP_SORT:
11145
676k
            if (op->ch1 != -1)
11146
676k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11147
676k
      CHECK_ERROR0;
11148
661k
            if ((ctxt->value != NULL) &&
11149
661k
                (ctxt->value->type == XPATH_NODESET) &&
11150
527k
                (ctxt->value->nodesetval != NULL) &&
11151
527k
    (ctxt->value->nodesetval->nodeNr > 1))
11152
140k
      {
11153
140k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11154
140k
      }
11155
661k
            break;
11156
0
        default:
11157
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11158
0
            break;
11159
14.3M
    }
11160
11161
14.1M
    ctxt->context->depth -= 1;
11162
14.1M
    return (total);
11163
14.3M
}
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
5.18M
{
11178
5.18M
    xmlXPathObjectPtr resObj = NULL;
11179
11180
7.76M
start:
11181
7.76M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11182
13
        return(0);
11183
    /* comp = ctxt->comp; */
11184
7.76M
    switch (op->op) {
11185
0
        case XPATH_OP_END:
11186
0
            return (0);
11187
1.00M
  case XPATH_OP_VALUE:
11188
1.00M
      resObj = (xmlXPathObjectPtr) op->value4;
11189
1.00M
      if (isPredicate)
11190
1.00M
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11191
0
      return(xmlXPathCastToBoolean(resObj));
11192
2.58M
  case XPATH_OP_SORT:
11193
      /*
11194
      * We don't need sorting for boolean results. Skip this one.
11195
      */
11196
2.58M
            if (op->ch1 != -1) {
11197
2.58M
    op = &ctxt->comp->steps[op->ch1];
11198
2.58M
    goto start;
11199
2.58M
      }
11200
0
      return(0);
11201
287k
  case XPATH_OP_COLLECT:
11202
287k
      if (op->ch1 == -1)
11203
0
    return(0);
11204
11205
287k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11206
287k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11207
280
    return(-1);
11208
11209
287k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11210
287k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11211
872
    return(-1);
11212
11213
286k
      resObj = xmlXPathValuePop(ctxt);
11214
286k
      if (resObj == NULL)
11215
0
    return(-1);
11216
286k
      break;
11217
3.89M
  default:
11218
      /*
11219
      * Fallback to call xmlXPathCompOpEval().
11220
      */
11221
3.89M
      xmlXPathCompOpEval(ctxt, op);
11222
3.89M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11223
3.84k
    return(-1);
11224
11225
3.88M
      resObj = xmlXPathValuePop(ctxt);
11226
3.88M
      if (resObj == NULL)
11227
0
    return(-1);
11228
3.88M
      break;
11229
7.76M
    }
11230
11231
4.17M
    if (resObj) {
11232
4.17M
  int res;
11233
11234
4.17M
  if (resObj->type == XPATH_BOOLEAN) {
11235
576k
      res = resObj->boolval;
11236
3.59M
  } 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
3.59M
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11246
3.59M
  } else {
11247
0
      res = xmlXPathCastToBoolean(resObj);
11248
0
  }
11249
4.17M
  xmlXPathReleaseObject(ctxt->context, resObj);
11250
4.17M
  return(res);
11251
4.17M
    }
11252
11253
0
    return(0);
11254
4.17M
}
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
38.0k
{
11497
38.0k
    xmlXPathCompExprPtr comp;
11498
38.0k
    int oldDepth;
11499
11500
38.0k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11501
0
  return(-1);
11502
11503
38.0k
    if (ctxt->valueTab == NULL) {
11504
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11505
0
        int valueMax = 1;
11506
#else
11507
        int valueMax = 10;
11508
#endif
11509
11510
  /* Allocate the value stack */
11511
0
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11512
0
  if (ctxt->valueTab == NULL) {
11513
0
      xmlXPathPErrMemory(ctxt);
11514
0
      return(-1);
11515
0
  }
11516
0
  ctxt->valueNr = 0;
11517
0
  ctxt->valueMax = valueMax;
11518
0
  ctxt->value = NULL;
11519
0
    }
11520
#ifdef XPATH_STREAMING
11521
    if (ctxt->comp->stream) {
11522
  int res;
11523
11524
  if (toBool) {
11525
      /*
11526
      * Evaluation to boolean result.
11527
      */
11528
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
11529
      if (res != -1)
11530
    return(res);
11531
  } else {
11532
      xmlXPathObjectPtr resObj = NULL;
11533
11534
      /*
11535
      * Evaluation to a sequence.
11536
      */
11537
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
11538
11539
      if ((res != -1) && (resObj != NULL)) {
11540
    xmlXPathValuePush(ctxt, resObj);
11541
    return(0);
11542
      }
11543
      if (resObj != NULL)
11544
    xmlXPathReleaseObject(ctxt->context, resObj);
11545
  }
11546
  /*
11547
  * QUESTION TODO: This falls back to normal XPath evaluation
11548
  * if res == -1. Is this intended?
11549
  */
11550
    }
11551
#endif
11552
38.0k
    comp = ctxt->comp;
11553
38.0k
    if (comp->last < 0) {
11554
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11555
0
  return(-1);
11556
0
    }
11557
38.0k
    oldDepth = ctxt->context->depth;
11558
38.0k
    if (toBool)
11559
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11560
0
      &comp->steps[comp->last], 0));
11561
38.0k
    else
11562
38.0k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11563
38.0k
    ctxt->context->depth = oldDepth;
11564
11565
38.0k
    return(0);
11566
38.0k
}
11567
11568
/************************************************************************
11569
 *                  *
11570
 *      Public interfaces       *
11571
 *                  *
11572
 ************************************************************************/
11573
11574
/**
11575
 * Evaluate a predicate result for the current node.
11576
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11577
 * the result to a boolean. If the result is a number, the result will
11578
 * be converted to true if the number is equal to the position of the
11579
 * context node in the context node list (as returned by the position
11580
 * function) and will be converted to false otherwise; if the result
11581
 * is not a number, then the result will be converted as if by a call
11582
 * to the boolean function.
11583
 *
11584
 * @param ctxt  the XPath context
11585
 * @param res  the Predicate Expression evaluation result
11586
 * @returns 1 if predicate is true, 0 otherwise
11587
 */
11588
int
11589
0
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11590
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
11591
0
    switch (res->type) {
11592
0
        case XPATH_BOOLEAN:
11593
0
      return(res->boolval);
11594
0
        case XPATH_NUMBER:
11595
0
      return(res->floatval == ctxt->proximityPosition);
11596
0
        case XPATH_NODESET:
11597
0
        case XPATH_XSLT_TREE:
11598
0
      if (res->nodesetval == NULL)
11599
0
    return(0);
11600
0
      return(res->nodesetval->nodeNr != 0);
11601
0
        case XPATH_STRING:
11602
0
      return((res->stringval != NULL) &&
11603
0
             (xmlStrlen(res->stringval) != 0));
11604
0
        default:
11605
0
      break;
11606
0
    }
11607
0
    return(0);
11608
0
}
11609
11610
/**
11611
 * Evaluate a predicate result for the current node.
11612
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11613
 * the result to a boolean. If the result is a number, the result will
11614
 * be converted to true if the number is equal to the position of the
11615
 * context node in the context node list (as returned by the position
11616
 * function) and will be converted to false otherwise; if the result
11617
 * is not a number, then the result will be converted as if by a call
11618
 * to the boolean function.
11619
 *
11620
 * @param ctxt  the XPath Parser context
11621
 * @param res  the Predicate Expression evaluation result
11622
 * @returns 1 if predicate is true, 0 otherwise
11623
 */
11624
int
11625
xmlXPathEvaluatePredicateResult(xmlXPathParserContext *ctxt,
11626
4.60M
                                xmlXPathObject *res) {
11627
4.60M
    if ((ctxt == NULL) || (res == NULL)) return(0);
11628
4.60M
    switch (res->type) {
11629
0
        case XPATH_BOOLEAN:
11630
0
      return(res->boolval);
11631
1.04M
        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
1.04M
      return(res->floatval == ctxt->context->proximityPosition);
11637
0
#endif
11638
2.83M
        case XPATH_NODESET:
11639
2.83M
        case XPATH_XSLT_TREE:
11640
2.83M
      if (res->nodesetval == NULL)
11641
0
    return(0);
11642
2.83M
      return(res->nodesetval->nodeNr != 0);
11643
727k
        case XPATH_STRING:
11644
727k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11645
0
        default:
11646
0
      break;
11647
4.60M
    }
11648
0
    return(0);
11649
4.60M
}
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
5.20M
{
11741
5.20M
    xmlXPathCompExprPtr comp = pctxt->comp;
11742
5.20M
    xmlXPathContextPtr ctxt;
11743
11744
    /*
11745
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11746
    * internal representation.
11747
    */
11748
11749
5.20M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11750
1.49M
        (op->ch1 != -1) &&
11751
1.49M
        (op->ch2 == -1 /* no predicate */))
11752
1.46M
    {
11753
1.46M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11754
11755
1.46M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11756
77.2k
            ((xmlXPathAxisVal) prevop->value ==
11757
77.2k
                AXIS_DESCENDANT_OR_SELF) &&
11758
31.0k
            (prevop->ch2 == -1) &&
11759
30.2k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11760
29.9k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11761
29.5k
        {
11762
            /*
11763
            * This is a "descendant-or-self::node()" without predicates.
11764
            * Try to eliminate it.
11765
            */
11766
11767
29.5k
            switch ((xmlXPathAxisVal) op->value) {
11768
14.2k
                case AXIS_CHILD:
11769
14.3k
                case AXIS_DESCENDANT:
11770
                    /*
11771
                    * Convert "descendant-or-self::node()/child::" or
11772
                    * "descendant-or-self::node()/descendant::" to
11773
                    * "descendant::"
11774
                    */
11775
14.3k
                    op->ch1   = prevop->ch1;
11776
14.3k
                    op->value = AXIS_DESCENDANT;
11777
14.3k
                    break;
11778
10
                case AXIS_SELF:
11779
4.12k
                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
4.12k
                    op->ch1   = prevop->ch1;
11786
4.12k
                    op->value = AXIS_DESCENDANT_OR_SELF;
11787
4.12k
                    break;
11788
11.1k
                default:
11789
11.1k
                    break;
11790
29.5k
            }
11791
29.5k
  }
11792
1.46M
    }
11793
11794
    /* OP_VALUE has invalid ch1. */
11795
5.20M
    if (op->op == XPATH_OP_VALUE)
11796
163k
        return;
11797
11798
    /* Recurse */
11799
5.04M
    ctxt = pctxt->context;
11800
5.04M
    if (ctxt != NULL) {
11801
5.04M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11802
5.05k
            return;
11803
5.03M
        ctxt->depth += 1;
11804
5.03M
    }
11805
5.03M
    if (op->ch1 != -1)
11806
3.51M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11807
5.03M
    if (op->ch2 != -1)
11808
1.65M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11809
5.03M
    if (ctxt != NULL)
11810
5.03M
        ctxt->depth -= 1;
11811
5.03M
}
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
5.98k
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11823
5.98k
    xmlXPathParserContextPtr pctxt;
11824
5.98k
    xmlXPathContextPtr tmpctxt = NULL;
11825
5.98k
    xmlXPathCompExprPtr comp;
11826
5.98k
    int oldDepth = 0;
11827
11828
5.98k
    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
5.98k
    xmlInitParser();
11838
11839
    /*
11840
     * We need an xmlXPathContext for the depth check.
11841
     */
11842
5.98k
    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
5.98k
    pctxt = xmlXPathNewParserContext(str, ctxt);
11850
5.98k
    if (pctxt == NULL) {
11851
12
        if (tmpctxt != NULL)
11852
0
            xmlXPathFreeContext(tmpctxt);
11853
12
        return NULL;
11854
12
    }
11855
11856
5.97k
    oldDepth = ctxt->depth;
11857
5.97k
    xmlXPathCompileExpr(pctxt, 1);
11858
5.97k
    ctxt->depth = oldDepth;
11859
11860
5.97k
    if( pctxt->error != XPATH_EXPRESSION_OK )
11861
1.58k
    {
11862
1.58k
        xmlXPathFreeParserContext(pctxt);
11863
1.58k
        if (tmpctxt != NULL)
11864
0
            xmlXPathFreeContext(tmpctxt);
11865
1.58k
        return(NULL);
11866
1.58k
    }
11867
11868
4.38k
    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
179
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11876
179
  comp = NULL;
11877
4.20k
    } else {
11878
4.20k
  comp = pctxt->comp;
11879
4.20k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11880
4.17k
            if (ctxt != NULL)
11881
4.17k
                oldDepth = ctxt->depth;
11882
4.17k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11883
4.17k
            if (ctxt != NULL)
11884
4.17k
                ctxt->depth = oldDepth;
11885
4.17k
  }
11886
4.20k
  pctxt->comp = NULL;
11887
4.20k
    }
11888
4.38k
    xmlXPathFreeParserContext(pctxt);
11889
4.38k
    if (tmpctxt != NULL)
11890
0
        xmlXPathFreeContext(tmpctxt);
11891
11892
4.38k
    if (comp != NULL) {
11893
4.20k
  comp->expr = xmlStrdup(str);
11894
4.20k
    }
11895
4.38k
    return(comp);
11896
5.97k
}
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
4.20k
{
11927
4.20k
    xmlXPathParserContextPtr pctxt;
11928
4.20k
    xmlXPathObjectPtr resObj = NULL;
11929
4.20k
    int res;
11930
11931
4.20k
    if (comp == NULL)
11932
0
  return(-1);
11933
4.20k
    xmlInitParser();
11934
11935
4.20k
    xmlResetError(&ctxt->lastError);
11936
11937
4.20k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11938
4.20k
    if (pctxt == NULL)
11939
3
        return(-1);
11940
4.20k
    res = xmlXPathRunEval(pctxt, toBool);
11941
11942
4.20k
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11943
3.54k
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11944
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11945
3.54k
        else if (!toBool)
11946
3.54k
            resObj = xmlXPathValuePop(pctxt);
11947
3.54k
    }
11948
11949
4.20k
    if (resObjPtr)
11950
4.20k
        *resObjPtr = resObj;
11951
0
    else
11952
0
        xmlXPathReleaseObject(ctxt, resObj);
11953
11954
4.20k
    pctxt->comp = NULL;
11955
4.20k
    xmlXPathFreeParserContext(pctxt);
11956
11957
4.20k
    return(res);
11958
4.20k
}
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
4.20k
{
11971
4.20k
    xmlXPathObjectPtr res = NULL;
11972
11973
4.20k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11974
4.20k
    return(res);
11975
4.20k
}
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
40.8k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
12003
#ifdef XPATH_STREAMING
12004
    xmlXPathCompExprPtr comp;
12005
#endif
12006
40.8k
    int oldDepth = 0;
12007
12008
40.8k
    if ((ctxt == NULL) || (ctxt->context == NULL))
12009
0
        return;
12010
40.8k
    if (ctxt->context->lastError.code != 0)
12011
604
        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
40.2k
    {
12027
40.2k
        if (ctxt->context != NULL)
12028
40.2k
            oldDepth = ctxt->context->depth;
12029
40.2k
  xmlXPathCompileExpr(ctxt, 1);
12030
40.2k
        if (ctxt->context != NULL)
12031
40.2k
            ctxt->context->depth = oldDepth;
12032
40.2k
        CHECK_ERROR;
12033
12034
        /* Check for trailing characters. */
12035
34.8k
        if (*ctxt->cur != 0)
12036
33.8k
            XP_ERROR(XPATH_EXPR_ERROR);
12037
12038
33.8k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12039
33.6k
            if (ctxt->context != NULL)
12040
33.6k
                oldDepth = ctxt->context->depth;
12041
33.6k
      xmlXPathOptimizeExpression(ctxt,
12042
33.6k
    &ctxt->comp->steps[ctxt->comp->last]);
12043
33.6k
            if (ctxt->context != NULL)
12044
33.6k
                ctxt->context->depth = oldDepth;
12045
33.6k
        }
12046
33.8k
    }
12047
12048
0
    xmlXPathRunEval(ctxt, 0);
12049
33.8k
}
12050
12051
/**
12052
 * Evaluate the XPath Location Path in the given context.
12053
 *
12054
 * @param str  the XPath expression
12055
 * @param ctx  the XPath context
12056
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12057
 *         the caller has to free the object.
12058
 */
12059
xmlXPathObject *
12060
0
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12061
0
    xmlXPathParserContextPtr ctxt;
12062
0
    xmlXPathObjectPtr res;
12063
12064
0
    if (ctx == NULL)
12065
0
        return(NULL);
12066
12067
0
    xmlInitParser();
12068
12069
0
    xmlResetError(&ctx->lastError);
12070
12071
0
    ctxt = xmlXPathNewParserContext(str, ctx);
12072
0
    if (ctxt == NULL)
12073
0
        return NULL;
12074
0
    xmlXPathEvalExpr(ctxt);
12075
12076
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12077
0
  res = NULL;
12078
0
    } else if (ctxt->valueNr != 1) {
12079
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12080
0
  res = NULL;
12081
0
    } else {
12082
0
  res = xmlXPathValuePop(ctxt);
12083
0
    }
12084
12085
0
    xmlXPathFreeParserContext(ctxt);
12086
0
    return(res);
12087
0
}
12088
12089
/**
12090
 * Sets 'node' as the context node. The node must be in the same
12091
 * document as that associated with the context.
12092
 *
12093
 * @param node  the node to to use as the context node
12094
 * @param ctx  the XPath context
12095
 * @returns -1 in case of error or 0 if successful
12096
 */
12097
int
12098
0
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12099
0
    if ((node == NULL) || (ctx == NULL))
12100
0
        return(-1);
12101
12102
0
    if (node->doc == ctx->doc) {
12103
0
        ctx->node = node;
12104
0
  return(0);
12105
0
    }
12106
0
    return(-1);
12107
0
}
12108
12109
/**
12110
 * Evaluate the XPath Location Path in the given context. The node 'node'
12111
 * is set as the context node. The context node is not restored.
12112
 *
12113
 * @param node  the node to to use as the context node
12114
 * @param str  the XPath expression
12115
 * @param ctx  the XPath context
12116
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12117
 *         the caller has to free the object.
12118
 */
12119
xmlXPathObject *
12120
0
xmlXPathNodeEval(xmlNode *node, const xmlChar *str, xmlXPathContext *ctx) {
12121
0
    if (str == NULL)
12122
0
        return(NULL);
12123
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
12124
0
        return(NULL);
12125
0
    return(xmlXPathEval(str, ctx));
12126
0
}
12127
12128
/**
12129
 * Alias for #xmlXPathEval.
12130
 *
12131
 * @param str  the XPath expression
12132
 * @param ctxt  the XPath context
12133
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12134
 *         the caller has to free the object.
12135
 */
12136
xmlXPathObject *
12137
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12138
0
    return(xmlXPathEval(str, ctxt));
12139
0
}
12140
12141
/**
12142
 * Registers all default XPath functions in this context
12143
 *
12144
 * @deprecated No-op since 2.14.0.
12145
 *
12146
 * @param ctxt  the XPath context
12147
 */
12148
void
12149
xmlXPathRegisterAllFunctions(xmlXPathContext *ctxt ATTRIBUTE_UNUSED)
12150
0
{
12151
0
}
12152
12153
#endif /* LIBXML_XPATH_ENABLED */