Coverage Report

Created: 2026-07-30 06:07

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
62.1k
#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
261
#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
1.41M
#define XPATH_MAX_NODESET_LENGTH 10000000
106
107
/*
108
 * Maximum amount of nested functions calls when parsing or evaluating
109
 * expressions
110
 */
111
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
112
4.96M
#define XPATH_MAX_RECURSION_DEPTH 500
113
#elif defined(_WIN32)
114
/* Windows typically limits stack size to 1MB. */
115
#define XPATH_MAX_RECURSION_DEPTH 1000
116
#else
117
#define XPATH_MAX_RECURSION_DEPTH 5000
118
#endif
119
120
/*
121
 * TODO:
122
 * There are a few spots where some tests are done which depend upon ascii
123
 * data.  These should be enhanced for full UTF8 support (see particularly
124
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
125
 */
126
127
#if defined(LIBXML_XPATH_ENABLED)
128
129
static void
130
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
131
132
static const struct {
133
    const char *name;
134
    xmlXPathFunction func;
135
} xmlXPathStandardFunctions[] = {
136
    { "boolean", xmlXPathBooleanFunction },
137
    { "ceiling", xmlXPathCeilingFunction },
138
    { "count", xmlXPathCountFunction },
139
    { "concat", xmlXPathConcatFunction },
140
    { "contains", xmlXPathContainsFunction },
141
    { "id", xmlXPathIdFunction },
142
    { "false", xmlXPathFalseFunction },
143
    { "floor", xmlXPathFloorFunction },
144
    { "last", xmlXPathLastFunction },
145
    { "lang", xmlXPathLangFunction },
146
    { "local-name", xmlXPathLocalNameFunction },
147
    { "not", xmlXPathNotFunction },
148
    { "name", xmlXPathNameFunction },
149
    { "namespace-uri", xmlXPathNamespaceURIFunction },
150
    { "normalize-space", xmlXPathNormalizeFunction },
151
    { "number", xmlXPathNumberFunction },
152
    { "position", xmlXPathPositionFunction },
153
    { "round", xmlXPathRoundFunction },
154
    { "string", xmlXPathStringFunction },
155
    { "string-length", xmlXPathStringLengthFunction },
156
    { "starts-with", xmlXPathStartsWithFunction },
157
    { "substring", xmlXPathSubstringFunction },
158
    { "substring-before", xmlXPathSubstringBeforeFunction },
159
    { "substring-after", xmlXPathSubstringAfterFunction },
160
    { "sum", xmlXPathSumFunction },
161
    { "true", xmlXPathTrueFunction },
162
    { "translate", xmlXPathTranslateFunction }
163
};
164
165
#define NUM_STANDARD_FUNCTIONS \
166
56
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
8.66k
#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
6.00k
xmlXPathSFComputeHash(const xmlChar *name) {
187
6.00k
    unsigned hashValue = 5381;
188
6.00k
    const xmlChar *ptr;
189
190
39.0k
    for (ptr = name; *ptr; ptr++)
191
33.0k
        hashValue = hashValue * 33 + *ptr;
192
193
6.00k
    return(hashValue);
194
6.00k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
2
xmlInitXPathInternal(void) {
202
2
    size_t i;
203
204
2
#if defined(NAN) && defined(INFINITY)
205
2
    xmlXPathNAN = NAN;
206
2
    xmlXPathPINF = INFINITY;
207
2
    xmlXPathNINF = -INFINITY;
208
#else
209
    /* MSVC doesn't allow division by zero in constant expressions. */
210
    double zero = 0.0;
211
    xmlXPathNAN = 0.0 / zero;
212
    xmlXPathPINF = 1.0 / zero;
213
    xmlXPathNINF = -xmlXPathPINF;
214
#endif
215
216
    /*
217
     * Initialize hash table for standard functions
218
     */
219
220
130
    for (i = 0; i < SF_HASH_SIZE; i++)
221
128
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
56
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
54
        const char *name = xmlXPathStandardFunctions[i].name;
225
54
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
68
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
14
            bucketIndex += 1;
229
14
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
14
        }
232
233
54
        xmlXPathSFHash[bucketIndex] = i;
234
54
    }
235
2
}
236
237
/************************************************************************
238
 *                  *
239
 *      Floating point stuff        *
240
 *                  *
241
 ************************************************************************/
242
243
/**
244
 * Checks whether a double is a NaN.
245
 *
246
 * @param val  a double value
247
 * @returns 1 if the value is a NaN, 0 otherwise
248
 */
249
int
250
575k
xmlXPathIsNaN(double val) {
251
575k
#ifdef isnan
252
575k
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
575k
}
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
430k
xmlXPathIsInf(double val) {
266
430k
#ifdef isinf
267
430k
    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
430k
}
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
4.29M
#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
3.58M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
3.58M
    int depth1, depth2;
311
3.58M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
3.58M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
3.58M
    xmlNodePtr cur, root;
314
3.58M
    XML_INTPTR_T l1, l2;
315
316
3.58M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
3.58M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
3.58M
    switch (node1->type) {
326
2.53M
  case XML_ELEMENT_NODE:
327
2.53M
      if (node2->type == XML_ELEMENT_NODE) {
328
1.84M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
0
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
0
        (node1->doc == node2->doc))
331
0
    {
332
0
        l1 = -XML_NODE_SORT_VALUE(node1);
333
0
        l2 = -XML_NODE_SORT_VALUE(node2);
334
0
        if (l1 < l2)
335
0
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
1.84M
        goto turtle_comparison;
340
1.84M
      }
341
690k
      break;
342
690k
  case XML_ATTRIBUTE_NODE:
343
14.4k
      precedence1 = 1; /* element is owner */
344
14.4k
      miscNode1 = node1;
345
14.4k
      node1 = node1->parent;
346
14.4k
      misc = 1;
347
14.4k
      break;
348
790k
  case XML_TEXT_NODE:
349
853k
  case XML_CDATA_SECTION_NODE:
350
858k
  case XML_COMMENT_NODE:
351
955k
  case XML_PI_NODE: {
352
955k
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
955k
      if (node1->prev != NULL) {
357
5.97M
    do {
358
5.97M
        node1 = node1->prev;
359
5.97M
        if (node1->type == XML_ELEMENT_NODE) {
360
470k
      precedence1 = 3; /* element in prev-sibl axis */
361
470k
      break;
362
470k
        }
363
5.50M
        if (node1->prev == NULL) {
364
5.59k
      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
5.59k
      node1 = node1->parent;
370
5.59k
      break;
371
5.59k
        }
372
5.50M
    } while (1);
373
479k
      } else {
374
479k
    precedence1 = 2; /* element is parent */
375
479k
    node1 = node1->parent;
376
479k
      }
377
955k
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
955k
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
955k
    node1 = miscNode1;
383
955k
    precedence1 = 0;
384
955k
      } else
385
0
    misc = 1;
386
955k
  }
387
955k
      break;
388
56.0k
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
56.0k
      return(1);
393
22.9k
  default:
394
22.9k
      break;
395
3.58M
    }
396
1.68M
    switch (node2->type) {
397
528k
  case XML_ELEMENT_NODE:
398
528k
      break;
399
13.3k
  case XML_ATTRIBUTE_NODE:
400
13.3k
      precedence2 = 1; /* element is owner */
401
13.3k
      miscNode2 = node2;
402
13.3k
      node2 = node2->parent;
403
13.3k
      misc = 1;
404
13.3k
      break;
405
883k
  case XML_TEXT_NODE:
406
946k
  case XML_CDATA_SECTION_NODE:
407
951k
  case XML_COMMENT_NODE:
408
1.04M
  case XML_PI_NODE: {
409
1.04M
      miscNode2 = node2;
410
1.04M
      if (node2->prev != NULL) {
411
5.99M
    do {
412
5.99M
        node2 = node2->prev;
413
5.99M
        if (node2->type == XML_ELEMENT_NODE) {
414
490k
      precedence2 = 3; /* element in prev-sibl axis */
415
490k
      break;
416
490k
        }
417
5.50M
        if (node2->prev == NULL) {
418
5.42k
      precedence2 = 2; /* element is parent */
419
5.42k
      node2 = node2->parent;
420
5.42k
      break;
421
5.42k
        }
422
5.50M
    } while (1);
423
552k
      } else {
424
552k
    precedence2 = 2; /* element is parent */
425
552k
    node2 = node2->parent;
426
552k
      }
427
1.04M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
1.04M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
1.04M
      {
430
1.04M
    node2 = miscNode2;
431
1.04M
    precedence2 = 0;
432
1.04M
      } else
433
0
    misc = 1;
434
1.04M
  }
435
1.04M
      break;
436
394
  case XML_NAMESPACE_DECL:
437
394
      return(1);
438
92.6k
  default:
439
92.6k
      break;
440
1.68M
    }
441
1.68M
    if (misc) {
442
19.5k
  if (node1 == node2) {
443
2.57k
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
1.21k
    cur = miscNode2->prev;
449
1.47k
    while (cur != NULL) {
450
663
        if (cur == miscNode1)
451
401
      return(1);
452
262
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
262
        cur = cur->prev;
455
262
    }
456
815
    return (-1);
457
1.35k
      } 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
1.35k
    if (precedence1 < precedence2)
464
486
        return(1);
465
868
    else
466
868
        return(-1);
467
1.35k
      }
468
2.57k
  }
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
16.9k
  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
16.9k
  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
16.9k
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
1.68M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
702k
  (node2->type == XML_ELEMENT_NODE) &&
501
13.4k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
0
  (node1->doc == node2->doc)) {
504
505
0
  l1 = -XML_NODE_SORT_VALUE(node1);
506
0
  l2 = -XML_NODE_SORT_VALUE(node2);
507
0
  if (l1 < l2)
508
0
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
3.52M
turtle_comparison:
514
515
3.52M
    if (node1 == node2->prev)
516
1.14M
  return(1);
517
2.38M
    if (node1 == node2->next)
518
53.0k
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
48.0M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
46.4M
  if (cur->parent == node1)
524
706k
      return(1);
525
45.6M
  depth2++;
526
45.6M
    }
527
1.62M
    root = cur;
528
42.7M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
41.5M
  if (cur->parent == node2)
530
373k
      return(-1);
531
41.1M
  depth1++;
532
41.1M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
1.24M
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
5.06M
    while (depth1 > depth2) {
543
3.81M
  depth1--;
544
3.81M
  node1 = node1->parent;
545
3.81M
    }
546
7.93M
    while (depth2 > depth1) {
547
6.68M
  depth2--;
548
6.68M
  node2 = node2->parent;
549
6.68M
    }
550
2.73M
    while (node1->parent != node2->parent) {
551
1.49M
  node1 = node1->parent;
552
1.49M
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
1.49M
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
1.49M
    }
557
    /*
558
     * Find who's first.
559
     */
560
1.24M
    if (node1 == node2->prev)
561
393k
  return(1);
562
853k
    if (node1 == node2->next)
563
402k
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
451k
    if ((node1->type == XML_ELEMENT_NODE) &&
568
443k
  (node2->type == XML_ELEMENT_NODE) &&
569
436k
  (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
2.38M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
2.17M
  if (cur == node2)
583
240k
      return(1);
584
210k
    return(-1); /* assume there is no sibling list corruption */
585
451k
}
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
500k
#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
3.58M
    {
607
3.58M
        int res = xmlXPathCmpNodesExt(x, y);
608
3.58M
        return res == -2 ? res : -res;
609
3.58M
    }
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
3.58M
#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
667
    { 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
8.39k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
8.39k
       sizeof(xmlXPathErrorMessages[0])) - 1)
670
/**
671
 * Handle a memory allocation failure.
672
 *
673
 * @param ctxt  an XPath context
674
 */
675
void
676
xmlXPathErrMemory(xmlXPathContext *ctxt)
677
3.50k
{
678
3.50k
    if (ctxt == NULL)
679
0
        return;
680
3.50k
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
3.50k
                        &ctxt->lastError);
682
3.50k
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
3.31k
{
692
3.31k
    if (ctxt == NULL)
693
0
        return;
694
3.31k
    ctxt->error = XPATH_MEMORY_ERROR;
695
3.31k
    xmlXPathErrMemory(ctxt->context);
696
3.31k
}
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
8.39k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
8.39k
    va_list ap;
709
8.39k
    xmlStructuredErrorFunc schannel = NULL;
710
8.39k
    xmlGenericErrorFunc channel = NULL;
711
8.39k
    void *data = NULL;
712
8.39k
    xmlNodePtr node = NULL;
713
8.39k
    int res;
714
715
8.39k
    if (ctxt == NULL)
716
0
        return;
717
8.39k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
8.39k
    if (ctxt->error != 0)
721
3.25k
        return;
722
723
5.14k
    ctxt->error = code;
724
725
5.14k
    if (ctxt->context != NULL) {
726
5.14k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
5.14k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
5.14k
        xmlResetError(err);
734
735
5.14k
        err->domain = XML_FROM_XPATH;
736
5.14k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
5.14k
        err->level = XML_ERR_ERROR;
738
5.14k
        if (ctxt->base != NULL) {
739
5.14k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
5.14k
            if (err->str1 == NULL) {
741
26
                xmlXPathPErrMemory(ctxt);
742
26
                return;
743
26
            }
744
5.14k
        }
745
5.12k
        err->int1 = ctxt->cur - ctxt->base;
746
5.12k
        err->node = ctxt->context->debugNode;
747
748
5.12k
        schannel = ctxt->context->error;
749
5.12k
        data = ctxt->context->userData;
750
5.12k
        node = ctxt->context->debugNode;
751
5.12k
    }
752
753
5.12k
    if (schannel == NULL) {
754
0
        channel = xmlGenericError;
755
0
        data = xmlGenericErrorContext;
756
0
    }
757
758
5.12k
    va_start(ap, fmt);
759
5.12k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
5.12k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
5.12k
                         XML_ERR_ERROR, NULL, 0,
762
5.12k
                         (const char *) ctxt->base, NULL, NULL,
763
5.12k
                         ctxt->cur - ctxt->base, 0,
764
5.12k
                         fmt, ap);
765
5.12k
    va_end(ap);
766
5.12k
    if (res < 0)
767
49
        xmlXPathPErrMemory(ctxt);
768
5.12k
}
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
7.54k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
7.54k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
7.54k
}
780
781
/**
782
 * Formats an error message.
783
 *
784
 * @param ctxt  the XPath Parser context
785
 * @param file  the file name
786
 * @param line  the line number
787
 * @param no  the error number
788
 */
789
void
790
xmlXPatherror(xmlXPathParserContext *ctxt, const char *file ATTRIBUTE_UNUSED,
791
0
              int line ATTRIBUTE_UNUSED, int no) {
792
0
    xmlXPathErr(ctxt, no);
793
0
}
794
795
/**
796
 * Adds opCount to the running total of operations and returns -1 if the
797
 * operation limit is exceeded. Returns 0 otherwise.
798
 *
799
 * @param ctxt  the XPath Parser context
800
 * @param opCount  the number of operations to be added
801
 */
802
static int
803
14.2M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
14.2M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
14.2M
    if ((opCount > xpctxt->opLimit) ||
807
14.2M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
111
        xpctxt->opCount = xpctxt->opLimit;
809
111
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
111
        return(-1);
811
111
    }
812
813
14.2M
    xpctxt->opCount += opCount;
814
14.2M
    return(0);
815
14.2M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
13.8M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
819
820
/************************************************************************
821
 *                  *
822
 *      Parser Types          *
823
 *                  *
824
 ************************************************************************/
825
826
/*
827
 * Types are private:
828
 */
829
830
typedef enum {
831
    XPATH_OP_END=0,
832
    XPATH_OP_AND,
833
    XPATH_OP_OR,
834
    XPATH_OP_EQUAL,
835
    XPATH_OP_CMP,
836
    XPATH_OP_PLUS,
837
    XPATH_OP_MULT,
838
    XPATH_OP_UNION,
839
    XPATH_OP_ROOT,
840
    XPATH_OP_NODE,
841
    XPATH_OP_COLLECT,
842
    XPATH_OP_VALUE, /* 11 */
843
    XPATH_OP_VARIABLE,
844
    XPATH_OP_FUNCTION,
845
    XPATH_OP_ARG,
846
    XPATH_OP_PREDICATE,
847
    XPATH_OP_FILTER, /* 16 */
848
    XPATH_OP_SORT /* 17 */
849
} xmlXPathOp;
850
851
typedef enum {
852
    AXIS_ANCESTOR = 1,
853
    AXIS_ANCESTOR_OR_SELF,
854
    AXIS_ATTRIBUTE,
855
    AXIS_CHILD,
856
    AXIS_DESCENDANT,
857
    AXIS_DESCENDANT_OR_SELF,
858
    AXIS_FOLLOWING,
859
    AXIS_FOLLOWING_SIBLING,
860
    AXIS_NAMESPACE,
861
    AXIS_PARENT,
862
    AXIS_PRECEDING,
863
    AXIS_PRECEDING_SIBLING,
864
    AXIS_SELF
865
} xmlXPathAxisVal;
866
867
typedef enum {
868
    NODE_TEST_NONE = 0,
869
    NODE_TEST_TYPE = 1,
870
    NODE_TEST_PI = 2,
871
    NODE_TEST_ALL = 3,
872
    NODE_TEST_NS = 4,
873
    NODE_TEST_NAME = 5
874
} xmlXPathTestVal;
875
876
typedef enum {
877
    NODE_TYPE_NODE = 0,
878
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
879
    NODE_TYPE_TEXT = XML_TEXT_NODE,
880
    NODE_TYPE_PI = XML_PI_NODE
881
} xmlXPathTypeVal;
882
883
typedef struct _xmlXPathStepOp xmlXPathStepOp;
884
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
885
struct _xmlXPathStepOp {
886
    xmlXPathOp op;    /* The identifier of the operation */
887
    int ch1;      /* First child */
888
    int ch2;      /* Second child */
889
    int value;
890
    int value2;
891
    int value3;
892
    void *value4;
893
    void *value5;
894
    xmlXPathFunction cache;
895
    void *cacheURI;
896
};
897
898
struct _xmlXPathCompExpr {
899
    int nbStep;     /* Number of steps in this expression */
900
    int maxStep;    /* Maximum number of steps allocated */
901
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
902
    int last;     /* index of last step in expression */
903
    xmlChar *expr;    /* the expression being computed */
904
    xmlDictPtr dict;    /* the dictionary to use if any */
905
#ifdef XPATH_STREAMING
906
    xmlPatternPtr stream;
907
#endif
908
};
909
910
/************************************************************************
911
 *                  *
912
 *      Forward declarations        *
913
 *                  *
914
 ************************************************************************/
915
916
static void
917
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
918
static int
919
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
920
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
921
static int
922
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
923
          xmlXPathStepOpPtr op,
924
          int isPredicate);
925
static void
926
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
927
928
/************************************************************************
929
 *                  *
930
 *      Parser Type functions       *
931
 *                  *
932
 ************************************************************************/
933
934
/**
935
 * Create a new Xpath component
936
 *
937
 * @returns the newly allocated xmlXPathCompExpr or NULL in case of error
938
 */
939
static xmlXPathCompExprPtr
940
11.6k
xmlXPathNewCompExpr(void) {
941
11.6k
    xmlXPathCompExprPtr cur;
942
943
11.6k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
11.6k
    if (cur == NULL)
945
32
  return(NULL);
946
11.5k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
11.5k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
11.5k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
11.5k
    cur->nbStep = 0;
953
11.5k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
11.5k
                                     sizeof(xmlXPathStepOp));
955
11.5k
    if (cur->steps == NULL) {
956
30
  xmlFree(cur);
957
30
  return(NULL);
958
30
    }
959
11.5k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
11.5k
    cur->last = -1;
961
11.5k
    return(cur);
962
11.5k
}
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
11.5k
{
972
11.5k
    xmlXPathStepOpPtr op;
973
11.5k
    int i;
974
975
11.5k
    if (comp == NULL)
976
0
        return;
977
11.5k
    if (comp->dict == NULL) {
978
1.03M
  for (i = 0; i < comp->nbStep; i++) {
979
1.02M
      op = &comp->steps[i];
980
1.02M
      if (op->value4 != NULL) {
981
87.9k
    if (op->op == XPATH_OP_VALUE)
982
75.1k
        xmlXPathFreeObject(op->value4);
983
12.8k
    else
984
12.8k
        xmlFree(op->value4);
985
87.9k
      }
986
1.02M
      if (op->value5 != NULL)
987
75.8k
    xmlFree(op->value5);
988
1.02M
  }
989
11.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
11.5k
    if (comp->steps != NULL) {
1000
11.5k
        xmlFree(comp->steps);
1001
11.5k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
11.5k
    if (comp->expr != NULL) {
1008
0
        xmlFree(comp->expr);
1009
0
    }
1010
1011
11.5k
    xmlFree(comp);
1012
11.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
1.02M
   int value2, int value3, void *value4, void *value5) {
1032
1.02M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
1.02M
    if (comp->nbStep >= comp->maxStep) {
1034
62.1k
  xmlXPathStepOp *real;
1035
62.1k
        int newSize;
1036
1037
62.1k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
62.1k
                                  10, XPATH_MAX_STEPS);
1039
62.1k
        if (newSize < 0) {
1040
0
      xmlXPathPErrMemory(ctxt);
1041
0
      return(-1);
1042
0
        }
1043
62.1k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
62.1k
  if (real == NULL) {
1045
146
      xmlXPathPErrMemory(ctxt);
1046
146
      return(-1);
1047
146
  }
1048
62.0k
  comp->steps = real;
1049
62.0k
  comp->maxStep = newSize;
1050
62.0k
    }
1051
1.02M
    comp->last = comp->nbStep;
1052
1.02M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
1.02M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
1.02M
    comp->steps[comp->nbStep].op = op;
1055
1.02M
    comp->steps[comp->nbStep].value = value;
1056
1.02M
    comp->steps[comp->nbStep].value2 = value2;
1057
1.02M
    comp->steps[comp->nbStep].value3 = value3;
1058
1.02M
    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
1.02M
    } else {
1074
1.02M
  comp->steps[comp->nbStep].value4 = value4;
1075
1.02M
  comp->steps[comp->nbStep].value5 = value5;
1076
1.02M
    }
1077
1.02M
    comp->steps[comp->nbStep].cache = NULL;
1078
1.02M
    return(comp->nbStep++);
1079
1.02M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
248k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
248k
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
114k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
114k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
272k
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
272k
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
61.9k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
61.9k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
328k
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
328k
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
328k
      (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
0
{
1516
0
    xmlXPathContextCachePtr ret;
1517
1518
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
0
    if (ret == NULL)
1520
0
  return(NULL);
1521
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
0
    ret->maxNodeset = 100;
1523
0
    ret->maxMisc = 100;
1524
0
    return(ret);
1525
0
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
0
{
1530
0
    while (list != NULL) {
1531
0
        xmlXPathObjectPtr next;
1532
1533
0
        next = (void *) list->stringval;
1534
1535
0
  if (list->nodesetval != NULL) {
1536
0
      if (list->nodesetval->nodeTab != NULL)
1537
0
    xmlFree(list->nodesetval->nodeTab);
1538
0
      xmlFree(list->nodesetval);
1539
0
  }
1540
0
  xmlFree(list);
1541
1542
0
        list = next;
1543
0
    }
1544
0
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
0
{
1549
0
    if (cache == NULL)
1550
0
  return;
1551
0
    if (cache->nodesetObjs)
1552
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
0
    if (cache->miscObjs)
1554
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
0
    xmlFree(cache);
1556
0
}
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
0
{
1582
0
    if (ctxt == NULL)
1583
0
  return(-1);
1584
0
    if (active) {
1585
0
  xmlXPathContextCachePtr cache;
1586
1587
0
  if (ctxt->cache == NULL) {
1588
0
      ctxt->cache = xmlXPathNewCache();
1589
0
      if (ctxt->cache == NULL) {
1590
0
                xmlXPathErrMemory(ctxt);
1591
0
    return(-1);
1592
0
            }
1593
0
  }
1594
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
0
  if (options == 0) {
1596
0
      if (value < 0)
1597
0
    value = 100;
1598
0
      cache->maxNodeset = value;
1599
0
      cache->maxMisc = value;
1600
0
  }
1601
0
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
0
    return(0);
1606
0
}
1607
1608
/**
1609
 * This is the cached version of #xmlXPathWrapNodeSet.
1610
 * Wrap the Nodeset `val` in a new xmlXPathObject
1611
 *
1612
 * In case of error the node set is destroyed and NULL is returned.
1613
 *
1614
 * @param pctxt  the XPath context
1615
 * @param val  the NodePtr value
1616
 * @returns the created or reused object.
1617
 */
1618
static xmlXPathObjectPtr
1619
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1620
1.09M
{
1621
1.09M
    xmlXPathObjectPtr ret;
1622
1.09M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
1.09M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
0
  xmlXPathContextCachePtr cache =
1626
0
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
0
  if (cache->miscObjs != NULL) {
1629
0
      ret = cache->miscObjs;
1630
0
            cache->miscObjs = (void *) ret->stringval;
1631
0
            cache->numMisc -= 1;
1632
0
            ret->stringval = NULL;
1633
0
      ret->type = XPATH_NODESET;
1634
0
      ret->nodesetval = val;
1635
0
      return(ret);
1636
0
  }
1637
0
    }
1638
1639
1.09M
    ret = xmlXPathWrapNodeSet(val);
1640
1.09M
    if (ret == NULL)
1641
172
        xmlXPathPErrMemory(pctxt);
1642
1.09M
    return(ret);
1643
1.09M
}
1644
1645
/**
1646
 * This is the cached version of #xmlXPathWrapString.
1647
 * Wraps the `val` string into an XPath object.
1648
 *
1649
 * @param pctxt  the XPath context
1650
 * @param val  the xmlChar * value
1651
 * @returns the created or reused object.
1652
 */
1653
static xmlXPathObjectPtr
1654
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1655
57.7k
{
1656
57.7k
    xmlXPathObjectPtr ret;
1657
57.7k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
57.7k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
0
  if (cache->miscObjs != NULL) {
1663
0
      ret = cache->miscObjs;
1664
0
            cache->miscObjs = (void *) ret->stringval;
1665
0
            cache->numMisc -= 1;
1666
0
      ret->type = XPATH_STRING;
1667
0
      ret->stringval = val;
1668
0
      return(ret);
1669
0
  }
1670
0
    }
1671
1672
57.7k
    ret = xmlXPathWrapString(val);
1673
57.7k
    if (ret == NULL)
1674
47
        xmlXPathPErrMemory(pctxt);
1675
57.7k
    return(ret);
1676
57.7k
}
1677
1678
/**
1679
 * This is the cached version of #xmlXPathNewNodeSet.
1680
 * Acquire an xmlXPathObject of type NodeSet and initialize
1681
 * it with the single Node `val`
1682
 *
1683
 * @param pctxt  the XPath context
1684
 * @param val  the NodePtr value
1685
 * @returns the created or reused object.
1686
 */
1687
static xmlXPathObjectPtr
1688
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1689
1.25M
{
1690
1.25M
    xmlXPathObjectPtr ret;
1691
1.25M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
1.25M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
0
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
0
      ret = cache->nodesetObjs;
1701
0
            cache->nodesetObjs = (void *) ret->stringval;
1702
0
            cache->numNodeset -= 1;
1703
0
            ret->stringval = NULL;
1704
0
      ret->type = XPATH_NODESET;
1705
0
      ret->boolval = 0;
1706
0
      if (val) {
1707
0
    if ((ret->nodesetval->nodeMax == 0) ||
1708
0
        (val->type == XML_NAMESPACE_DECL))
1709
0
    {
1710
0
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
0
                        xmlXPathPErrMemory(pctxt);
1712
0
    } else {
1713
0
        ret->nodesetval->nodeTab[0] = val;
1714
0
        ret->nodesetval->nodeNr = 1;
1715
0
    }
1716
0
      }
1717
0
      return(ret);
1718
0
  } else if (cache->miscObjs != NULL) {
1719
0
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
0
      set = xmlXPathNodeSetCreate(val);
1725
0
      if (set == NULL) {
1726
0
                xmlXPathPErrMemory(pctxt);
1727
0
    return(NULL);
1728
0
      }
1729
1730
0
      ret = cache->miscObjs;
1731
0
            cache->miscObjs = (void *) ret->stringval;
1732
0
            cache->numMisc -= 1;
1733
0
            ret->stringval = NULL;
1734
0
      ret->type = XPATH_NODESET;
1735
0
      ret->boolval = 0;
1736
0
      ret->nodesetval = set;
1737
0
      return(ret);
1738
0
  }
1739
0
    }
1740
1.25M
    ret = xmlXPathNewNodeSet(val);
1741
1.25M
    if (ret == NULL)
1742
455
        xmlXPathPErrMemory(pctxt);
1743
1.25M
    return(ret);
1744
1.25M
}
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
145k
{
1757
145k
    xmlXPathObjectPtr ret;
1758
145k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
145k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
0
  if (cache->miscObjs != NULL) {
1764
0
            xmlChar *copy;
1765
1766
0
            if (val == NULL)
1767
0
                val = BAD_CAST "";
1768
0
            copy = xmlStrdup(val);
1769
0
            if (copy == NULL) {
1770
0
                xmlXPathPErrMemory(pctxt);
1771
0
                return(NULL);
1772
0
            }
1773
1774
0
      ret = cache->miscObjs;
1775
0
            cache->miscObjs = (void *) ret->stringval;
1776
0
            cache->numMisc -= 1;
1777
0
      ret->type = XPATH_STRING;
1778
0
            ret->stringval = copy;
1779
0
      return(ret);
1780
0
  }
1781
0
    }
1782
1783
145k
    ret = xmlXPathNewString(val);
1784
145k
    if (ret == NULL)
1785
33
        xmlXPathPErrMemory(pctxt);
1786
145k
    return(ret);
1787
145k
}
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
6.89k
{
1800
6.89k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
6.89k
}
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
611k
{
1814
611k
    xmlXPathObjectPtr ret;
1815
611k
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
611k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
0
  if (cache->miscObjs != NULL) {
1821
0
      ret = cache->miscObjs;
1822
0
            cache->miscObjs = (void *) ret->stringval;
1823
0
            cache->numMisc -= 1;
1824
0
            ret->stringval = NULL;
1825
0
      ret->type = XPATH_BOOLEAN;
1826
0
      ret->boolval = (val != 0);
1827
0
      return(ret);
1828
0
  }
1829
0
    }
1830
1831
611k
    ret = xmlXPathNewBoolean(val);
1832
611k
    if (ret == NULL)
1833
97
        xmlXPathPErrMemory(pctxt);
1834
611k
    return(ret);
1835
611k
}
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
487k
{
1848
487k
    xmlXPathObjectPtr ret;
1849
487k
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
487k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
0
  if (cache->miscObjs != NULL) {
1855
0
      ret = cache->miscObjs;
1856
0
            cache->miscObjs = (void *) ret->stringval;
1857
0
            cache->numMisc -= 1;
1858
0
            ret->stringval = NULL;
1859
0
      ret->type = XPATH_NUMBER;
1860
0
      ret->floatval = val;
1861
0
      return(ret);
1862
0
  }
1863
0
    }
1864
1865
487k
    ret = xmlXPathNewFloat(val);
1866
487k
    if (ret == NULL)
1867
143
        xmlXPathPErrMemory(pctxt);
1868
487k
    return(ret);
1869
487k
}
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
409k
{
1882
409k
    xmlXPathObjectPtr ret;
1883
409k
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
409k
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
409k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
0
  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
0
      case XPATH_STRING:
1901
0
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
0
      case XPATH_NUMBER:
1905
0
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
0
  }
1909
0
    }
1910
409k
    ret = xmlXPathObjectCopy(val);
1911
409k
    if (ret == NULL)
1912
101
        xmlXPathPErrMemory(pctxt);
1913
409k
    return(ret);
1914
409k
}
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
720k
                             xmlXPathObjectPtr val) {
1932
720k
    double ret = 0.0;
1933
1934
720k
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
720k
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
471k
    case XPATH_NODESET:
1941
471k
    case XPATH_XSLT_TREE: {
1942
471k
        xmlChar *str;
1943
1944
471k
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
471k
        if (str == NULL) {
1946
65
            xmlXPathPErrMemory(ctxt);
1947
65
            ret = xmlXPathNAN;
1948
471k
        } else {
1949
471k
      ret = xmlXPathCastStringToNumber(str);
1950
471k
            xmlFree(str);
1951
471k
        }
1952
471k
  break;
1953
471k
    }
1954
149k
    case XPATH_STRING:
1955
149k
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
149k
  break;
1957
62.1k
    case XPATH_NUMBER:
1958
62.1k
  ret = val->floatval;
1959
62.1k
  break;
1960
36.6k
    case XPATH_BOOLEAN:
1961
36.6k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
36.6k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
720k
    }
1968
720k
    return(ret);
1969
720k
}
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
4.28M
{
1980
4.28M
    xmlXPathObjectPtr ret;
1981
1982
4.28M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
16.3k
        return (NULL);
1984
1985
4.26M
    ctxt->valueNr--;
1986
4.26M
    if (ctxt->valueNr > 0)
1987
3.45M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
815k
    else
1989
815k
        ctxt->value = NULL;
1990
4.26M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
4.26M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
4.26M
    return (ret);
1993
4.28M
}
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
4.27M
{
2008
4.27M
    if (ctxt == NULL) return(-1);
2009
4.27M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
1.02k
        xmlXPathPErrMemory(ctxt);
2014
1.02k
        return(-1);
2015
1.02k
    }
2016
4.27M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
261
        xmlXPathObjectPtr *tmp;
2018
261
        int newSize;
2019
2020
261
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
261
                                  10, XPATH_MAX_STACK_DEPTH);
2022
261
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
261
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
261
        if (tmp == NULL) {
2029
2
            xmlXPathPErrMemory(ctxt);
2030
2
            xmlXPathFreeObject(value);
2031
2
            return (-1);
2032
2
        }
2033
259
  ctxt->valueTab = tmp;
2034
259
        ctxt->valueMax = newSize;
2035
259
    }
2036
4.27M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
4.27M
    ctxt->value = value;
2038
4.27M
    return (ctxt->valueNr++);
2039
4.27M
}
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
9.91M
#define CUR (*ctxt->cur)
2194
39.7k
#define SKIP(val) ctxt->cur += (val)
2195
1.34M
#define NXT(val) ctxt->cur[(val)]
2196
38.4k
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
4.83M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
4.72M
#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
13.4k
#define UPPER_DOUBLE 1E9
2213
1.95k
#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
12.1k
#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
18.3k
{
2230
18.3k
    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
18.3k
    default:
2240
18.3k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
18.3k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
18.3k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
7.05k
                   (number == (int) number)) {
2248
4.92k
      char work[30];
2249
4.92k
      char *ptr, *cur;
2250
4.92k
      int value = (int) number;
2251
2252
4.92k
            ptr = &buffer[0];
2253
4.92k
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
4.92k
      } else {
2256
4.92k
    snprintf(work, 29, "%d", value);
2257
4.92k
    cur = &work[0];
2258
23.1k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
18.2k
        *ptr++ = *cur++;
2260
18.2k
    }
2261
4.92k
      }
2262
4.92k
      if (ptr - buffer < buffersize) {
2263
4.92k
    *ptr = 0;
2264
4.92k
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
13.4k
  } 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
13.4k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
13.4k
      int integer_place, fraction_place;
2280
13.4k
      char *ptr;
2281
13.4k
      char *after_fraction;
2282
13.4k
      double absolute_value;
2283
13.4k
      int size;
2284
2285
13.4k
      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
13.4k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
1.95k
      (absolute_value < LOWER_DOUBLE)) &&
2294
12.1k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
12.1k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
12.1k
    fraction_place = DBL_DIG - 1;
2298
12.1k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
12.1k
       integer_place, fraction_place, number);
2300
65.0k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
12.1k
      }
2303
1.30k
      else {
2304
    /* Use regular notation */
2305
1.30k
    if (absolute_value > 0.0) {
2306
1.30k
        integer_place = (int)log10(absolute_value);
2307
1.30k
        if (integer_place > 0)
2308
544
            fraction_place = DBL_DIG - integer_place - 1;
2309
765
        else
2310
765
            fraction_place = DBL_DIG - integer_place;
2311
1.30k
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
1.30k
    size = snprintf(work, sizeof(work), "%0.*f",
2315
1.30k
        fraction_place, number);
2316
1.30k
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
19.7k
      while (work[0] == ' ') {
2320
133k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
6.33k
    size--;
2322
6.33k
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
13.4k
      after_fraction = work + size;
2326
13.4k
      ptr = after_fraction;
2327
44.6k
      while (*(--ptr) == '0')
2328
31.2k
    ;
2329
13.4k
      if (*ptr != '.')
2330
13.1k
          ptr++;
2331
66.3k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
13.4k
      size = strlen(work) + 1;
2335
13.4k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
13.4k
      memmove(buffer, work, size);
2340
13.4k
  }
2341
18.3k
  break;
2342
18.3k
    }
2343
18.3k
}
2344
2345
2346
/************************************************************************
2347
 *                  *
2348
 *      Routines to handle NodeSets     *
2349
 *                  *
2350
 ************************************************************************/
2351
2352
/**
2353
 * Call this routine to speed up XPath computation on static documents.
2354
 * This stamps all the element nodes with the document order
2355
 * Like for line information, the order is kept in the element->content
2356
 * field, the value stored is actually - the node number (starting at -1)
2357
 * to be able to differentiate from line numbers.
2358
 *
2359
 * @param doc  an input document
2360
 * @returns the number of elements found in the document or -1 in case
2361
 *    of error.
2362
 */
2363
long
2364
0
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
0
    XML_INTPTR_T count = 0;
2366
0
    xmlNodePtr cur;
2367
2368
0
    if (doc == NULL)
2369
0
  return(-1);
2370
0
    cur = doc->children;
2371
0
    while (cur != NULL) {
2372
0
  if (cur->type == XML_ELEMENT_NODE) {
2373
0
            count += 1;
2374
0
            cur->content = XML_INT_TO_PTR(-count);
2375
0
      if (cur->children != NULL) {
2376
0
    cur = cur->children;
2377
0
    continue;
2378
0
      }
2379
0
  }
2380
0
  if (cur->next != NULL) {
2381
0
      cur = cur->next;
2382
0
      continue;
2383
0
  }
2384
0
  do {
2385
0
      cur = cur->parent;
2386
0
      if (cur == NULL)
2387
0
    break;
2388
0
      if (cur == (xmlNodePtr) doc) {
2389
0
    cur = NULL;
2390
0
    break;
2391
0
      }
2392
0
      if (cur->next != NULL) {
2393
0
    cur = cur->next;
2394
0
    break;
2395
0
      }
2396
0
  } while (cur != NULL);
2397
0
    }
2398
0
    return(count);
2399
0
}
2400
2401
/**
2402
 * Compare two nodes w.r.t document order
2403
 *
2404
 * @param node1  the first node
2405
 * @param node2  the second node
2406
 * @returns -2 in case of error 1 if first point < second point, 0 if
2407
 *         it's the same node, -1 otherwise
2408
 */
2409
int
2410
0
xmlXPathCmpNodes(xmlNode *node1, xmlNode *node2) {
2411
0
    int depth1, depth2;
2412
0
    int attr1 = 0, attr2 = 0;
2413
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2414
0
    xmlNodePtr cur, root;
2415
2416
0
    if ((node1 == NULL) || (node2 == NULL))
2417
0
  return(-2);
2418
    /*
2419
     * a couple of optimizations which will avoid computations in most cases
2420
     */
2421
0
    if (node1 == node2)   /* trivial case */
2422
0
  return(0);
2423
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2424
0
  attr1 = 1;
2425
0
  attrNode1 = node1;
2426
0
  node1 = node1->parent;
2427
0
    }
2428
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2429
0
  attr2 = 1;
2430
0
  attrNode2 = node2;
2431
0
  node2 = node2->parent;
2432
0
    }
2433
0
    if (node1 == node2) {
2434
0
  if (attr1 == attr2) {
2435
      /* not required, but we keep attributes in order */
2436
0
      if (attr1 != 0) {
2437
0
          cur = attrNode2->prev;
2438
0
    while (cur != NULL) {
2439
0
        if (cur == attrNode1)
2440
0
            return (1);
2441
0
        cur = cur->prev;
2442
0
    }
2443
0
    return (-1);
2444
0
      }
2445
0
      return(0);
2446
0
  }
2447
0
  if (attr2 == 1)
2448
0
      return(1);
2449
0
  return(-1);
2450
0
    }
2451
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2452
0
        (node2->type == XML_NAMESPACE_DECL))
2453
0
  return(1);
2454
0
    if (node1 == node2->prev)
2455
0
  return(1);
2456
0
    if (node1 == node2->next)
2457
0
  return(-1);
2458
2459
    /*
2460
     * Speedup using document order if available.
2461
     */
2462
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2463
0
  (node2->type == XML_ELEMENT_NODE) &&
2464
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2465
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2466
0
  (node1->doc == node2->doc)) {
2467
0
  XML_INTPTR_T l1, l2;
2468
2469
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2470
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2471
0
  if (l1 < l2)
2472
0
      return(1);
2473
0
  if (l1 > l2)
2474
0
      return(-1);
2475
0
    }
2476
2477
    /*
2478
     * compute depth to root
2479
     */
2480
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2481
0
  if (cur->parent == node1)
2482
0
      return(1);
2483
0
  depth2++;
2484
0
    }
2485
0
    root = cur;
2486
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2487
0
  if (cur->parent == node2)
2488
0
      return(-1);
2489
0
  depth1++;
2490
0
    }
2491
    /*
2492
     * Distinct document (or distinct entities :-( ) case.
2493
     */
2494
0
    if (root != cur) {
2495
0
  return(-2);
2496
0
    }
2497
    /*
2498
     * get the nearest common ancestor.
2499
     */
2500
0
    while (depth1 > depth2) {
2501
0
  depth1--;
2502
0
  node1 = node1->parent;
2503
0
    }
2504
0
    while (depth2 > depth1) {
2505
0
  depth2--;
2506
0
  node2 = node2->parent;
2507
0
    }
2508
0
    while (node1->parent != node2->parent) {
2509
0
  node1 = node1->parent;
2510
0
  node2 = node2->parent;
2511
  /* should not happen but just in case ... */
2512
0
  if ((node1 == NULL) || (node2 == NULL))
2513
0
      return(-2);
2514
0
    }
2515
    /*
2516
     * Find who's first.
2517
     */
2518
0
    if (node1 == node2->prev)
2519
0
  return(1);
2520
0
    if (node1 == node2->next)
2521
0
  return(-1);
2522
    /*
2523
     * Speedup using document order if available.
2524
     */
2525
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2526
0
  (node2->type == XML_ELEMENT_NODE) &&
2527
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2528
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2529
0
  (node1->doc == node2->doc)) {
2530
0
  XML_INTPTR_T l1, l2;
2531
2532
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2533
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2534
0
  if (l1 < l2)
2535
0
      return(1);
2536
0
  if (l1 > l2)
2537
0
      return(-1);
2538
0
    }
2539
2540
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2541
0
  if (cur == node2)
2542
0
      return(1);
2543
0
    return(-1); /* assume there is no sibling list corruption */
2544
0
}
2545
2546
/**
2547
 * Sort the node set in document order
2548
 *
2549
 * @param set  the node set
2550
 */
2551
void
2552
30.3k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
30.3k
    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
30.3k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
30.3k
#endif /* WITH_TIM_SORT */
2591
30.3k
}
2592
2593
5.32M
#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
129k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
129k
    xmlNsPtr cur;
2606
2607
129k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
129k
    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
129k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
129k
    if (cur == NULL)
2617
25
  return(NULL);
2618
129k
    memset(cur, 0, sizeof(xmlNs));
2619
129k
    cur->type = XML_NAMESPACE_DECL;
2620
129k
    if (ns->href != NULL) {
2621
82.3k
  cur->href = xmlStrdup(ns->href);
2622
82.3k
        if (cur->href == NULL) {
2623
16
            xmlFree(cur);
2624
16
            return(NULL);
2625
16
        }
2626
82.3k
    }
2627
129k
    if (ns->prefix != NULL) {
2628
98.9k
  cur->prefix = xmlStrdup(ns->prefix);
2629
98.9k
        if (cur->prefix == NULL) {
2630
22
            xmlFree((xmlChar *) cur->href);
2631
22
            xmlFree(cur);
2632
22
            return(NULL);
2633
22
        }
2634
98.9k
    }
2635
129k
    cur->next = (xmlNsPtr) node;
2636
129k
    return((xmlNodePtr) cur);
2637
129k
}
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
129k
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
129k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
129k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
129k
  if (ns->href != NULL)
2653
82.3k
      xmlFree((xmlChar *)ns->href);
2654
129k
  if (ns->prefix != NULL)
2655
98.9k
      xmlFree((xmlChar *)ns->prefix);
2656
129k
  xmlFree(ns);
2657
129k
    }
2658
129k
}
2659
2660
/**
2661
 * Create a new xmlNodeSet of type double and of value `val`
2662
 *
2663
 * @param val  an initial xmlNode, or NULL
2664
 * @returns the newly created object.
2665
 */
2666
xmlNodeSet *
2667
2.36M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
2.36M
    xmlNodeSetPtr ret;
2669
2670
2.36M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
2.36M
    if (ret == NULL)
2672
324
  return(NULL);
2673
2.36M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
2.36M
    if (val != NULL) {
2675
1.25M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
1.25M
               sizeof(xmlNodePtr));
2677
1.25M
  if (ret->nodeTab == NULL) {
2678
145
      xmlFree(ret);
2679
145
      return(NULL);
2680
145
  }
2681
1.24M
  memset(ret->nodeTab, 0 ,
2682
1.24M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
1.24M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
1.24M
  if (val->type == XML_NAMESPACE_DECL) {
2685
13.4k
      xmlNsPtr ns = (xmlNsPtr) val;
2686
13.4k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
13.4k
            if (nsNode == NULL) {
2689
4
                xmlXPathFreeNodeSet(ret);
2690
4
                return(NULL);
2691
4
            }
2692
13.4k
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
13.4k
  } else
2694
1.23M
      ret->nodeTab[ret->nodeNr++] = val;
2695
1.24M
    }
2696
2.36M
    return(ret);
2697
2.36M
}
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
1.41M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
1.41M
    xmlNodePtr *temp;
2737
1.41M
    int newSize;
2738
2739
1.41M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
1.41M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
1.41M
    if (newSize < 0)
2742
0
        return(-1);
2743
1.41M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
1.41M
    if (temp == NULL)
2745
308
        return(-1);
2746
1.41M
    cur->nodeMax = newSize;
2747
1.41M
    cur->nodeTab = temp;
2748
2749
1.41M
    return(0);
2750
1.41M
}
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
79.6k
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
79.6k
    int i;
2763
79.6k
    xmlNodePtr nsNode;
2764
2765
79.6k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
79.6k
        (ns->type != XML_NAMESPACE_DECL) ||
2767
79.6k
  (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
149k
    for (i = 0;i < cur->nodeNr;i++) {
2775
70.2k
        if ((cur->nodeTab[i] != NULL) &&
2776
70.2k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
70.2k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
70.2k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
70.2k
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
79.6k
    if (cur->nodeNr >= cur->nodeMax) {
2786
7.14k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
4
            return(-1);
2788
7.14k
    }
2789
79.6k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
79.6k
    if(nsNode == NULL)
2791
28
        return(-1);
2792
79.6k
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
79.6k
    return(0);
2794
79.6k
}
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
2.29k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
2.29k
    int i;
2806
2807
2.29k
    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
2.29k
    for (i = 0;i < cur->nodeNr;i++)
2814
1.42k
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
876
    if (cur->nodeNr >= cur->nodeMax) {
2820
876
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
1
            return(-1);
2822
876
    }
2823
2824
875
    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
875
  cur->nodeTab[cur->nodeNr++] = val;
2833
875
    return(0);
2834
875
}
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
5.53M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
5.53M
    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
5.53M
    if (cur->nodeNr >= cur->nodeMax) {
2853
1.28M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
174
            return(-1);
2855
1.28M
    }
2856
2857
5.53M
    if (val->type == XML_NAMESPACE_DECL) {
2858
5.73k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
5.73k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
5.73k
        if (nsNode == NULL)
2862
6
            return(-1);
2863
5.72k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
5.72k
    } else
2865
5.52M
  cur->nodeTab[cur->nodeNr++] = val;
2866
5.53M
    return(0);
2867
5.53M
}
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
58.0k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
58.0k
    int i, j, initNr, skip;
2882
58.0k
    xmlNodePtr n1, n2;
2883
2884
58.0k
    if (val1 == NULL) {
2885
4
  val1 = xmlXPathNodeSetCreate(NULL);
2886
4
        if (val1 == NULL)
2887
0
            return (NULL);
2888
4
    }
2889
58.0k
    if (val2 == NULL)
2890
34
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
57.9k
    initNr = val1->nodeNr;
2894
2895
899k
    for (i = 0;i < val2->nodeNr;i++) {
2896
841k
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
841k
  skip = 0;
2901
27.2M
  for (j = 0; j < initNr; j++) {
2902
26.5M
      n1 = val1->nodeTab[j];
2903
26.5M
      if (n1 == n2) {
2904
103k
    skip = 1;
2905
103k
    break;
2906
26.4M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
260
           (n2->type == XML_NAMESPACE_DECL)) {
2908
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
0
      ((xmlNsPtr) n2)->prefix)))
2911
0
    {
2912
0
        skip = 1;
2913
0
        break;
2914
0
    }
2915
0
      }
2916
26.5M
  }
2917
841k
  if (skip)
2918
103k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
737k
        if (val1->nodeNr >= val1->nodeMax) {
2924
61.8k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
24
                goto error;
2926
61.8k
        }
2927
737k
  if (n2->type == XML_NAMESPACE_DECL) {
2928
30.7k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
30.7k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
30.7k
            if (nsNode == NULL)
2932
25
                goto error;
2933
30.6k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
30.6k
  } else
2935
707k
      val1->nodeTab[val1->nodeNr++] = n2;
2936
737k
    }
2937
2938
57.9k
    return(val1);
2939
2940
49
error:
2941
49
    xmlXPathFreeNodeSet(val1);
2942
49
    return(NULL);
2943
57.9k
}
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
148k
{
2959
148k
    {
2960
148k
  int i, j, initNbSet1;
2961
148k
  xmlNodePtr n1, n2;
2962
2963
148k
  initNbSet1 = set1->nodeNr;
2964
514k
  for (i = 0;i < set2->nodeNr;i++) {
2965
365k
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
97.0M
      for (j = 0; j < initNbSet1; j++) {
2970
97.0M
    n1 = set1->nodeTab[j];
2971
97.0M
    if (n1 == n2) {
2972
289k
        goto skip_node;
2973
96.7M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
163k
        (n2->type == XML_NAMESPACE_DECL))
2975
163k
    {
2976
163k
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
4.28k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
4.28k
      ((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
163k
    }
2987
97.0M
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
75.8k
            if (set1->nodeNr >= set1->nodeMax) {
2992
14.2k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
43
                    goto error;
2994
14.2k
            }
2995
75.7k
      set1->nodeTab[set1->nodeNr++] = n2;
2996
365k
skip_node:
2997
365k
            set2->nodeTab[i] = NULL;
2998
365k
  }
2999
148k
    }
3000
148k
    set2->nodeNr = 0;
3001
148k
    return(set1);
3002
3003
43
error:
3004
43
    xmlXPathFreeNodeSet(set1);
3005
43
    xmlXPathNodeSetClear(set2, 1);
3006
43
    return(NULL);
3007
148k
}
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
130k
{
3022
130k
    {
3023
130k
  int i;
3024
130k
  xmlNodePtr n2;
3025
3026
420k
  for (i = 0;i < set2->nodeNr;i++) {
3027
289k
      n2 = set2->nodeTab[i];
3028
289k
            if (set1->nodeNr >= set1->nodeMax) {
3029
45.7k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
62
                    goto error;
3031
45.7k
            }
3032
289k
      set1->nodeTab[set1->nodeNr++] = n2;
3033
289k
            set2->nodeTab[i] = NULL;
3034
289k
  }
3035
130k
    }
3036
130k
    set2->nodeNr = 0;
3037
130k
    return(set1);
3038
3039
62
error:
3040
62
    xmlXPathFreeNodeSet(set1);
3041
62
    xmlXPathNodeSetClear(set2, 1);
3042
62
    return(NULL);
3043
130k
}
3044
3045
/**
3046
 * Removes an xmlNode from an existing NodeSet
3047
 *
3048
 * @param cur  the initial node set
3049
 * @param val  an xmlNode
3050
 */
3051
void
3052
0
xmlXPathNodeSetDel(xmlNodeSet *cur, xmlNode *val) {
3053
0
    int i;
3054
3055
0
    if (cur == NULL) return;
3056
0
    if (val == NULL) return;
3057
3058
    /*
3059
     * find node in nodeTab
3060
     */
3061
0
    for (i = 0;i < cur->nodeNr;i++)
3062
0
        if (cur->nodeTab[i] == val) break;
3063
3064
0
    if (i >= cur->nodeNr) { /* not found */
3065
0
        return;
3066
0
    }
3067
0
    if ((cur->nodeTab[i] != NULL) &&
3068
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3069
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3070
0
    cur->nodeNr--;
3071
0
    for (;i < cur->nodeNr;i++)
3072
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3073
0
    cur->nodeTab[cur->nodeNr] = NULL;
3074
0
}
3075
3076
/**
3077
 * Removes an entry from an existing NodeSet list.
3078
 *
3079
 * @param cur  the initial node set
3080
 * @param val  the index to remove
3081
 */
3082
void
3083
0
xmlXPathNodeSetRemove(xmlNodeSet *cur, int val) {
3084
0
    if (cur == NULL) return;
3085
0
    if (val >= cur->nodeNr) return;
3086
0
    if ((cur->nodeTab[val] != NULL) &&
3087
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3088
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3089
0
    cur->nodeNr--;
3090
0
    for (;val < cur->nodeNr;val++)
3091
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3092
0
    cur->nodeTab[cur->nodeNr] = NULL;
3093
0
}
3094
3095
/**
3096
 * Free the NodeSet compound (not the actual nodes !).
3097
 *
3098
 * @param obj  the xmlNodeSet to free
3099
 */
3100
void
3101
2.36M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
2.36M
    if (obj == NULL) return;
3103
2.36M
    if (obj->nodeTab != NULL) {
3104
1.63M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
8.56M
  for (i = 0;i < obj->nodeNr;i++)
3108
6.92M
      if ((obj->nodeTab[i] != NULL) &&
3109
6.92M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
126k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
1.63M
  xmlFree(obj->nodeTab);
3112
1.63M
    }
3113
2.36M
    xmlFree(obj);
3114
2.36M
}
3115
3116
/**
3117
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3118
 * are feed) starting with the entry at `pos`, but does *not* free the list
3119
 * itself. Sets the length of the list to `pos`.
3120
 *
3121
 * @param set  the node set to be cleared
3122
 * @param pos  the start position to clear from
3123
 * @param hasNsNodes  the node set might contain namespace nodes
3124
 */
3125
static void
3126
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3127
2.84k
{
3128
2.84k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
2.84k
    else if ((hasNsNodes)) {
3131
711
  int i;
3132
711
  xmlNodePtr node;
3133
3134
3.92k
  for (i = pos; i < set->nodeNr; i++) {
3135
3.21k
      node = set->nodeTab[i];
3136
3.21k
      if ((node != NULL) &&
3137
2.54k
    (node->type == XML_NAMESPACE_DECL))
3138
53
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
3.21k
  }
3140
711
    }
3141
2.84k
    set->nodeNr = pos;
3142
2.84k
}
3143
3144
/**
3145
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3146
 * are feed), but does *not* free the list itself. Sets the length of the
3147
 * list to 0.
3148
 *
3149
 * @param set  the node set to clear
3150
 * @param hasNsNodes  the node set might contain namespace nodes
3151
 */
3152
static void
3153
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3154
2.23k
{
3155
2.23k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
2.23k
}
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
681
{
3168
681
    int i;
3169
681
    xmlNodePtr node;
3170
3171
681
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
5.87k
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
5.19k
        node = set->nodeTab[i];
3175
5.19k
        if ((node != NULL) &&
3176
5.19k
            (node->type == XML_NAMESPACE_DECL))
3177
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
5.19k
    }
3179
681
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
681
    set->nodeNr = 1;
3181
681
}
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
1.25M
xmlXPathNewNodeSet(xmlNode *val) {
3192
1.25M
    xmlXPathObjectPtr ret;
3193
3194
1.25M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
1.25M
    if (ret == NULL)
3196
149
  return(NULL);
3197
1.25M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
1.25M
    ret->type = XPATH_NODESET;
3199
1.25M
    ret->boolval = 0;
3200
1.25M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
1.25M
    if (ret->nodesetval == NULL) {
3202
324
        xmlFree(ret);
3203
324
        return(NULL);
3204
324
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
1.25M
    return(ret);
3207
1.25M
}
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
1.09M
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
1.09M
    xmlXPathObjectPtr ret;
3269
3270
1.09M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
1.09M
    if (ret == NULL) {
3272
172
        xmlXPathFreeNodeSet(val);
3273
172
  return(NULL);
3274
172
    }
3275
1.09M
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
1.09M
    ret->type = XPATH_NODESET;
3277
1.09M
    ret->nodesetval = val;
3278
1.09M
    return(ret);
3279
1.09M
}
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
5.95k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
5.95k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
5.95k
}
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
5.95k
       const xmlChar *ns_uri) {
3759
5.95k
    xmlXPathFunction ret;
3760
5.95k
    void *payload;
3761
3762
5.95k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
5.95k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
5.95k
    if (ns_uri == NULL) {
3768
5.95k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
8.46k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
7.92k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
7.92k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
7.92k
                       (char *) name) == 0)
3775
5.41k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
2.51k
            bucketIndex += 1;
3778
2.51k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
2.51k
        }
3781
5.95k
    }
3782
3783
542
    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
542
    if (ctxt->funcHash == NULL)
3793
542
  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
542
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
7.15k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
7.15k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
7.15k
    xmlHashFree(ctxt->funcHash, NULL);
3812
7.15k
    ctxt->funcHash = NULL;
3813
7.15k
}
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
44
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
44
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
44
    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
44
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
44
}
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
55
       const xmlChar *ns_uri) {
3917
55
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
55
    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
55
    if (ctxt->varHash == NULL)
3929
55
  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
7.15k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
7.15k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
7.15k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
7.15k
    ctxt->varHash = NULL;
3948
7.15k
}
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
416
         const xmlChar *ns_uri) {
3962
416
    xmlChar *copy;
3963
3964
416
    if (ctxt == NULL)
3965
0
  return(-1);
3966
416
    if (prefix == NULL)
3967
0
  return(-1);
3968
416
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
416
    if (ctxt->nsHash == NULL)
3972
37
  ctxt->nsHash = xmlHashCreate(10);
3973
416
    if (ctxt->nsHash == NULL) {
3974
3
        xmlXPathErrMemory(ctxt);
3975
3
  return(-1);
3976
3
    }
3977
413
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
413
    copy = xmlStrdup(ns_uri);
3982
413
    if (copy == NULL) {
3983
1
        xmlXPathErrMemory(ctxt);
3984
1
        return(-1);
3985
1
    }
3986
412
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
412
                           xmlHashDefaultDeallocator) < 0) {
3988
1
        xmlXPathErrMemory(ctxt);
3989
1
        xmlFree(copy);
3990
1
        return(-1);
3991
1
    }
3992
3993
411
    return(0);
3994
412
}
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
8.08k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
8.08k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
8.08k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
8.08k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
7.83k
  return(XML_XML_NAMESPACE);
4013
4014
253
    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
253
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
253
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
7.15k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
7.15k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
7.15k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
7.15k
    ctxt->nsHash = NULL;
4039
7.15k
}
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
487k
xmlXPathNewFloat(double val) {
4057
487k
    xmlXPathObjectPtr ret;
4058
4059
487k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
487k
    if (ret == NULL)
4061
143
  return(NULL);
4062
487k
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
487k
    ret->type = XPATH_NUMBER;
4064
487k
    ret->floatval = val;
4065
487k
    return(ret);
4066
487k
}
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
611k
xmlXPathNewBoolean(int val) {
4076
611k
    xmlXPathObjectPtr ret;
4077
4078
611k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
611k
    if (ret == NULL)
4080
97
  return(NULL);
4081
611k
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
611k
    ret->type = XPATH_BOOLEAN;
4083
611k
    ret->boolval = (val != 0);
4084
611k
    return(ret);
4085
611k
}
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
145k
xmlXPathNewString(const xmlChar *val) {
4095
145k
    xmlXPathObjectPtr ret;
4096
4097
145k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
145k
    if (ret == NULL)
4099
20
  return(NULL);
4100
145k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
145k
    ret->type = XPATH_STRING;
4102
145k
    if (val == NULL)
4103
1
        val = BAD_CAST "";
4104
145k
    ret->stringval = xmlStrdup(val);
4105
145k
    if (ret->stringval == NULL) {
4106
21
        xmlFree(ret);
4107
21
        return(NULL);
4108
21
    }
4109
145k
    return(ret);
4110
145k
}
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
57.7k
xmlXPathWrapString (xmlChar *val) {
4122
57.7k
    xmlXPathObjectPtr ret;
4123
4124
57.7k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
57.7k
    if (ret == NULL) {
4126
47
        xmlFree(val);
4127
47
  return(NULL);
4128
47
    }
4129
57.7k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
57.7k
    ret->type = XPATH_STRING;
4131
57.7k
    ret->stringval = val;
4132
57.7k
    return(ret);
4133
57.7k
}
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
409k
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
409k
    xmlXPathObjectPtr ret;
4185
4186
409k
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
409k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
409k
    if (ret == NULL)
4191
87
  return(NULL);
4192
409k
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
409k
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
387k
  case XPATH_NUMBER:
4196
387k
      break;
4197
22.0k
  case XPATH_STRING:
4198
22.0k
      ret->stringval = xmlStrdup(val->stringval);
4199
22.0k
            if (ret->stringval == NULL) {
4200
14
                xmlFree(ret);
4201
14
                return(NULL);
4202
14
            }
4203
22.0k
      break;
4204
22.0k
  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
409k
    }
4222
409k
    return(ret);
4223
409k
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
4.05M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
4.05M
    if (obj == NULL) return;
4233
4.05M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
2.34M
        if (obj->nodesetval != NULL)
4235
2.34M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
2.34M
    } else if (obj->type == XPATH_STRING) {
4237
225k
  if (obj->stringval != NULL)
4238
225k
      xmlFree(obj->stringval);
4239
225k
    }
4240
4.05M
    xmlFree(obj);
4241
4.05M
}
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
3.79M
{
4258
3.79M
    if (obj == NULL)
4259
20
  return;
4260
3.79M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
3.79M
   xmlXPathFreeObject(obj);
4262
3.79M
    } else {
4263
0
  xmlXPathContextCachePtr cache =
4264
0
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
0
  switch (obj->type) {
4267
0
      case XPATH_NODESET:
4268
0
      case XPATH_XSLT_TREE:
4269
0
    if (obj->nodesetval != NULL) {
4270
0
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
0
      (cache->numNodeset < cache->maxNodeset)) {
4272
0
                        obj->stringval = (void *) cache->nodesetObjs;
4273
0
                        cache->nodesetObjs = obj;
4274
0
                        cache->numNodeset += 1;
4275
0
      goto obj_cached;
4276
0
        } else {
4277
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
0
      obj->nodesetval = NULL;
4279
0
        }
4280
0
    }
4281
0
    break;
4282
0
      case XPATH_STRING:
4283
0
    if (obj->stringval != NULL)
4284
0
        xmlFree(obj->stringval);
4285
0
                obj->stringval = NULL;
4286
0
    break;
4287
0
      case XPATH_BOOLEAN:
4288
0
      case XPATH_NUMBER:
4289
0
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
0
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
0
        if (cache->numMisc >= cache->maxMisc)
4298
0
      goto free_obj;
4299
0
        obj->stringval = (void *) cache->miscObjs;
4300
0
        cache->miscObjs = obj;
4301
0
        cache->numMisc += 1;
4302
4303
0
obj_cached:
4304
0
        obj->boolval = 0;
4305
0
  if (obj->nodesetval != NULL) {
4306
0
      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
0
      if (tmpset->nodeNr > 0) {
4313
0
    int i;
4314
0
    xmlNodePtr node;
4315
4316
0
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
0
        node = tmpset->nodeTab[i];
4318
0
        if ((node != NULL) &&
4319
0
      (node->type == XML_NAMESPACE_DECL))
4320
0
        {
4321
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
0
        }
4323
0
    }
4324
0
      }
4325
0
      tmpset->nodeNr = 0;
4326
0
        }
4327
4328
0
  return;
4329
4330
0
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
0
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
0
  xmlFree(obj);
4337
0
    }
4338
3.79M
}
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
5.58k
xmlXPathCastBooleanToString (int val) {
4355
5.58k
    xmlChar *ret;
4356
5.58k
    if (val)
4357
1.63k
  ret = xmlStrdup((const xmlChar *) "true");
4358
3.95k
    else
4359
3.95k
  ret = xmlStrdup((const xmlChar *) "false");
4360
5.58k
    return(ret);
4361
5.58k
}
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
22.6k
xmlXPathCastNumberToString (double val) {
4371
22.6k
    xmlChar *ret;
4372
22.6k
    switch (xmlXPathIsInf(val)) {
4373
230
    case 1:
4374
230
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
230
  break;
4376
436
    case -1:
4377
436
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
436
  break;
4379
21.9k
    default:
4380
21.9k
  if (xmlXPathIsNaN(val)) {
4381
2.89k
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
19.0k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
700
      ret = xmlStrdup((const xmlChar *) "0");
4385
18.3k
  } else {
4386
      /* could be improved */
4387
18.3k
      char buf[100];
4388
18.3k
      xmlXPathFormatNumber(val, buf, 99);
4389
18.3k
      buf[99] = 0;
4390
18.3k
      ret = xmlStrdup((const xmlChar *) buf);
4391
18.3k
  }
4392
22.6k
    }
4393
22.6k
    return(ret);
4394
22.6k
}
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
389k
xmlXPathCastNodeToString (xmlNode *node) {
4404
389k
    return(xmlNodeGetContent(node));
4405
389k
}
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
494k
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
494k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
325k
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
168k
    if (ns->nodeNr > 1)
4419
22.7k
  xmlXPathNodeSetSort(ns);
4420
168k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
494k
}
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
51.0k
xmlXPathCastToString(xmlXPathObject *val) {
4432
51.0k
    xmlChar *ret = NULL;
4433
4434
51.0k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
51.0k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
22.3k
        case XPATH_NODESET:
4441
22.3k
        case XPATH_XSLT_TREE:
4442
22.3k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
22.3k
      break;
4444
501
  case XPATH_STRING:
4445
501
      return(xmlStrdup(val->stringval));
4446
5.58k
        case XPATH_BOOLEAN:
4447
5.58k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
5.58k
      break;
4449
22.6k
  case XPATH_NUMBER: {
4450
22.6k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
22.6k
      break;
4452
22.3k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
51.0k
    }
4458
50.5k
    return(ret);
4459
51.0k
}
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
36.6k
xmlXPathCastBooleanToNumber(int val) {
4508
36.6k
    if (val)
4509
3.76k
  return(1.0);
4510
32.9k
    return(0.0);
4511
36.6k
}
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
712k
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
712k
    return(xmlXPathStringEvalNumber(val));
4522
712k
}
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
91.5k
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
91.5k
    xmlChar *strval;
4534
91.5k
    double ret;
4535
4536
91.5k
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
91.5k
    strval = xmlXPathCastNodeToString(node);
4539
91.5k
    if (strval == NULL) {
4540
16
        xmlXPathPErrMemory(ctxt);
4541
16
  return(xmlXPathNAN);
4542
16
    }
4543
91.5k
    ret = xmlXPathCastStringToNumber(strval);
4544
91.5k
    xmlFree(strval);
4545
4546
91.5k
    return(ret);
4547
91.5k
}
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
67.9k
xmlXPathCastNumberToBoolean (double val) {
4618
67.9k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
56.8k
   return(0);
4620
11.1k
     return(1);
4621
67.9k
}
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
62
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
62
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
18
  return(0);
4633
44
    return(1);
4634
62
}
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
10.9k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
10.9k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
9.36k
  return(0);
4646
1.57k
    return(1);
4647
10.9k
}
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
14.0k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
14.0k
    int ret = 0;
4658
4659
14.0k
    if (val == NULL)
4660
0
  return(0);
4661
14.0k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
10.9k
    case XPATH_NODESET:
4666
10.9k
    case XPATH_XSLT_TREE:
4667
10.9k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
10.9k
  break;
4669
62
    case XPATH_STRING:
4670
62
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
62
  break;
4672
3.08k
    case XPATH_NUMBER:
4673
3.08k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
3.08k
  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
14.0k
    }
4683
14.0k
    return(ret);
4684
14.0k
}
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
7.18k
xmlXPathNewContext(xmlDoc *doc) {
4721
7.18k
    xmlXPathContextPtr ret;
4722
4723
7.18k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
7.18k
    if (ret == NULL)
4725
28
  return(NULL);
4726
7.15k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
7.15k
    ret->doc = doc;
4728
7.15k
    ret->node = NULL;
4729
4730
7.15k
    ret->varHash = NULL;
4731
4732
7.15k
    ret->nb_types = 0;
4733
7.15k
    ret->max_types = 0;
4734
7.15k
    ret->types = NULL;
4735
4736
7.15k
    ret->nb_axis = 0;
4737
7.15k
    ret->max_axis = 0;
4738
7.15k
    ret->axis = NULL;
4739
4740
7.15k
    ret->nsHash = NULL;
4741
7.15k
    ret->user = NULL;
4742
4743
7.15k
    ret->contextSize = -1;
4744
7.15k
    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
7.15k
    return(ret);
4754
7.18k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
7.15k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
7.15k
    if (ctxt == NULL) return;
4764
4765
7.15k
    if (ctxt->cache != NULL)
4766
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
7.15k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
7.15k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
7.15k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
7.15k
    xmlResetError(&ctxt->lastError);
4771
7.15k
    xmlFree(ctxt);
4772
7.15k
}
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
7.15k
                        xmlStructuredErrorFunc handler, void *data) {
4786
7.15k
    if (ctxt == NULL)
4787
0
        return;
4788
4789
7.15k
    ctxt->error = handler;
4790
7.15k
    ctxt->userData = data;
4791
7.15k
}
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
11.6k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
11.6k
    xmlXPathParserContextPtr ret;
4809
4810
11.6k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
11.6k
    if (ret == NULL) {
4812
34
        xmlXPathErrMemory(ctxt);
4813
34
  return(NULL);
4814
34
    }
4815
11.6k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
11.6k
    ret->cur = ret->base = str;
4817
11.6k
    ret->context = ctxt;
4818
4819
11.6k
    ret->comp = xmlXPathNewCompExpr();
4820
11.6k
    if (ret->comp == NULL) {
4821
62
        xmlXPathErrMemory(ctxt);
4822
62
  xmlFree(ret->valueTab);
4823
62
  xmlFree(ret);
4824
62
  return(NULL);
4825
62
    }
4826
11.5k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
11.5k
    return(ret);
4832
11.6k
}
4833
4834
/**
4835
 * Create a new xmlXPathParserContext when processing a compiled expression
4836
 *
4837
 * @param comp  the XPath compiled expression
4838
 * @param ctxt  the XPath context
4839
 * @returns the xmlXPathParserContext just allocated.
4840
 */
4841
static xmlXPathParserContextPtr
4842
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
0
    xmlXPathParserContextPtr ret;
4844
4845
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
0
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
0
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
0
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
0
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
0
    ret->valueNr = 0;
4865
0
    ret->value = NULL;
4866
4867
0
    ret->context = ctxt;
4868
0
    ret->comp = comp;
4869
4870
0
    return(ret);
4871
0
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
11.5k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
11.5k
    int i;
4881
4882
11.5k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
11.5k
    if (ctxt->valueTab != NULL) {
4886
20.0k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
8.49k
            if (ctxt->context)
4888
8.49k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
8.49k
        }
4892
11.5k
        xmlFree(ctxt->valueTab);
4893
11.5k
    }
4894
11.5k
    if (ctxt->comp != NULL) {
4895
#ifdef XPATH_STREAMING
4896
  if (ctxt->comp->stream != NULL) {
4897
      xmlFreePatternList(ctxt->comp->stream);
4898
      ctxt->comp->stream = NULL;
4899
  }
4900
#endif
4901
11.5k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
11.5k
    }
4903
11.5k
    xmlFree(ctxt);
4904
11.5k
}
4905
4906
/************************************************************************
4907
 *                  *
4908
 *    The implicit core function library      *
4909
 *                  *
4910
 ************************************************************************/
4911
4912
/**
4913
 * Function computing the beginning of the string value of the node,
4914
 * used to speed up comparisons
4915
 *
4916
 * @param node  a node pointer
4917
 * @returns an int usable as a hash
4918
 */
4919
static unsigned int
4920
81.6k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
81.6k
    int len = 2;
4922
81.6k
    const xmlChar * string = NULL;
4923
81.6k
    xmlNodePtr tmp = NULL;
4924
81.6k
    unsigned int ret = 0;
4925
4926
81.6k
    if (node == NULL)
4927
0
  return(0);
4928
4929
81.6k
    if (node->type == XML_DOCUMENT_NODE) {
4930
18.3k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
18.3k
  if (tmp == NULL)
4932
0
      node = node->children;
4933
18.3k
  else
4934
18.3k
      node = tmp;
4935
4936
18.3k
  if (node == NULL)
4937
0
      return(0);
4938
18.3k
    }
4939
4940
81.6k
    switch (node->type) {
4941
775
  case XML_COMMENT_NODE:
4942
1.98k
  case XML_PI_NODE:
4943
2.26k
  case XML_CDATA_SECTION_NODE:
4944
8.76k
  case XML_TEXT_NODE:
4945
8.76k
      string = node->content;
4946
8.76k
      if (string == NULL)
4947
1.21k
    return(0);
4948
7.55k
      if (string[0] == 0)
4949
107
    return(0);
4950
7.44k
      return(string[0] + (string[1] << 8));
4951
487
  case XML_NAMESPACE_DECL:
4952
487
      string = ((xmlNsPtr)node)->href;
4953
487
      if (string == NULL)
4954
222
    return(0);
4955
265
      if (string[0] == 0)
4956
0
    return(0);
4957
265
      return(string[0] + (string[1] << 8));
4958
925
  case XML_ATTRIBUTE_NODE:
4959
925
      tmp = ((xmlAttrPtr) node)->children;
4960
925
      break;
4961
71.5k
  case XML_ELEMENT_NODE:
4962
71.5k
      tmp = node->children;
4963
71.5k
      break;
4964
0
  default:
4965
0
      return(0);
4966
81.6k
    }
4967
361k
    while (tmp != NULL) {
4968
323k
  switch (tmp->type) {
4969
14.4k
      case XML_CDATA_SECTION_NODE:
4970
54.9k
      case XML_TEXT_NODE:
4971
54.9k
    string = tmp->content;
4972
54.9k
    break;
4973
268k
      default:
4974
268k
                string = NULL;
4975
268k
    break;
4976
323k
  }
4977
323k
  if ((string != NULL) && (string[0] != 0)) {
4978
54.5k
      if (len == 1) {
4979
18.1k
    return(ret + (string[0] << 8));
4980
18.1k
      }
4981
36.4k
      if (string[1] == 0) {
4982
19.6k
    len = 1;
4983
19.6k
    ret = string[0];
4984
19.6k
      } else {
4985
16.7k
    return(string[0] + (string[1] << 8));
4986
16.7k
      }
4987
36.4k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
288k
        if ((tmp->children != NULL) &&
4992
96.8k
            (tmp->type != XML_DTD_NODE) &&
4993
96.8k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
96.8k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
96.8k
            tmp = tmp->children;
4996
96.8k
            continue;
4997
96.8k
  }
4998
191k
  if (tmp == node)
4999
0
      break;
5000
5001
191k
  if (tmp->next != NULL) {
5002
187k
      tmp = tmp->next;
5003
187k
      continue;
5004
187k
  }
5005
5006
7.67k
  do {
5007
7.67k
      tmp = tmp->parent;
5008
7.67k
      if (tmp == NULL)
5009
0
    break;
5010
7.67k
      if (tmp == node) {
5011
2.42k
    tmp = NULL;
5012
2.42k
    break;
5013
2.42k
      }
5014
5.24k
      if (tmp->next != NULL) {
5015
2.31k
    tmp = tmp->next;
5016
2.31k
    break;
5017
2.31k
      }
5018
5.24k
  } while (tmp != NULL);
5019
4.73k
    }
5020
37.5k
    return(ret);
5021
72.4k
}
5022
5023
/**
5024
 * Function computing the beginning of the string value of the node,
5025
 * used to speed up comparisons
5026
 *
5027
 * @param string  a string
5028
 * @returns an int usable as a hash
5029
 */
5030
static unsigned int
5031
1.31k
xmlXPathStringHash(const xmlChar * string) {
5032
1.31k
    if (string == NULL)
5033
0
  return(0);
5034
1.31k
    if (string[0] == 0)
5035
354
  return(0);
5036
961
    return(string[0] + (string[1] << 8));
5037
1.31k
}
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
64.1k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
64.1k
    int i, ret = 0;
5063
64.1k
    xmlNodeSetPtr ns;
5064
64.1k
    xmlChar *str2;
5065
5066
64.1k
    if ((f == NULL) || (arg == NULL) ||
5067
64.1k
  ((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
64.1k
    ns = arg->nodesetval;
5073
64.1k
    if (ns != NULL) {
5074
145k
  for (i = 0;i < ns->nodeNr;i++) {
5075
83.0k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
83.0k
       if (str2 != NULL) {
5077
83.0k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
83.0k
     xmlFree(str2);
5079
83.0k
     xmlXPathNumberFunction(ctxt, 1);
5080
83.0k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
83.0k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
83.0k
     if (ret)
5083
1.75k
         break;
5084
83.0k
       } else {
5085
7
                 xmlXPathPErrMemory(ctxt);
5086
7
             }
5087
83.0k
  }
5088
64.1k
    }
5089
64.1k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
64.1k
    xmlXPathReleaseObject(ctxt->context, f);
5091
64.1k
    return(ret);
5092
64.1k
}
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
1.35k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
1.35k
    int i, ret = 0;
5117
1.35k
    xmlNodeSetPtr ns;
5118
1.35k
    xmlChar *str2;
5119
5120
1.35k
    if ((s == NULL) || (arg == NULL) ||
5121
1.35k
  ((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
1.35k
    ns = arg->nodesetval;
5127
1.35k
    if (ns != NULL) {
5128
2.36k
  for (i = 0;i < ns->nodeNr;i++) {
5129
1.01k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
1.01k
       if (str2 != NULL) {
5131
1.00k
     xmlXPathValuePush(ctxt,
5132
1.00k
         xmlXPathCacheNewString(ctxt, str2));
5133
1.00k
     xmlFree(str2);
5134
1.00k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
1.00k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
1.00k
     if (ret)
5137
0
         break;
5138
1.00k
       } else {
5139
1
                 xmlXPathPErrMemory(ctxt);
5140
1
             }
5141
1.01k
  }
5142
1.35k
    }
5143
1.35k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
1.35k
    xmlXPathReleaseObject(ctxt->context, s);
5145
1.35k
    return(ret);
5146
1.35k
}
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
85.1k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
85.1k
    int i, j, init = 0;
5180
85.1k
    double val1;
5181
85.1k
    double *values2;
5182
85.1k
    int ret = 0;
5183
85.1k
    xmlNodeSetPtr ns1;
5184
85.1k
    xmlNodeSetPtr ns2;
5185
5186
85.1k
    if ((arg1 == NULL) ||
5187
85.1k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
85.1k
    if ((arg2 == NULL) ||
5192
85.1k
  ((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
85.1k
    ns1 = arg1->nodesetval;
5199
85.1k
    ns2 = arg2->nodesetval;
5200
5201
85.1k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
52.2k
  xmlXPathFreeObject(arg1);
5203
52.2k
  xmlXPathFreeObject(arg2);
5204
52.2k
  return(0);
5205
52.2k
    }
5206
32.8k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
25.5k
  xmlXPathFreeObject(arg1);
5208
25.5k
  xmlXPathFreeObject(arg2);
5209
25.5k
  return(0);
5210
25.5k
    }
5211
5212
7.29k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
7.29k
    if (values2 == NULL) {
5214
2
        xmlXPathPErrMemory(ctxt);
5215
2
  xmlXPathFreeObject(arg1);
5216
2
  xmlXPathFreeObject(arg2);
5217
2
  return(0);
5218
2
    }
5219
49.6k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
45.3k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
45.3k
  if (xmlXPathIsNaN(val1))
5222
39.7k
      continue;
5223
54.0k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
51.4k
      if (init == 0) {
5225
46.2k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
46.2k
                                                          ns2->nodeTab[j]);
5227
46.2k
      }
5228
51.4k
      if (xmlXPathIsNaN(values2[j]))
5229
44.4k
    continue;
5230
6.96k
      if (inf && strict)
5231
251
    ret = (val1 < values2[j]);
5232
6.71k
      else if (inf && !strict)
5233
277
    ret = (val1 <= values2[j]);
5234
6.43k
      else if (!inf && strict)
5235
5.67k
    ret = (val1 > values2[j]);
5236
757
      else if (!inf && !strict)
5237
757
    ret = (val1 >= values2[j]);
5238
6.96k
      if (ret)
5239
2.92k
    break;
5240
6.96k
  }
5241
5.55k
  if (ret)
5242
2.92k
      break;
5243
2.63k
  init = 1;
5244
2.63k
    }
5245
7.28k
    xmlFree(values2);
5246
7.28k
    xmlXPathFreeObject(arg1);
5247
7.28k
    xmlXPathFreeObject(arg2);
5248
7.28k
    return(ret);
5249
7.29k
}
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
76.1k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
76.1k
    if ((val == NULL) || (arg == NULL) ||
5274
76.1k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
76.1k
    switch(val->type) {
5278
64.1k
        case XPATH_NUMBER:
5279
64.1k
      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
1.35k
        case XPATH_STRING:
5284
1.35k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
10.5k
        case XPATH_BOOLEAN:
5286
10.5k
      xmlXPathValuePush(ctxt, arg);
5287
10.5k
      xmlXPathBooleanFunction(ctxt, 1);
5288
10.5k
      xmlXPathValuePush(ctxt, val);
5289
10.5k
      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
76.1k
    }
5295
0
    return(0);
5296
76.1k
}
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
6.91k
{
5315
6.91k
    int i;
5316
6.91k
    xmlNodeSetPtr ns;
5317
6.91k
    xmlChar *str2;
5318
6.91k
    unsigned int hash;
5319
5320
6.91k
    if ((str == NULL) || (arg == NULL) ||
5321
6.91k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
6.91k
    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
6.91k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
5.59k
        return (0);
5330
1.31k
    hash = xmlXPathStringHash(str);
5331
21.8k
    for (i = 0; i < ns->nodeNr; i++) {
5332
21.2k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
1.18k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
1.18k
            if (str2 == NULL) {
5335
3
                xmlXPathPErrMemory(ctxt);
5336
3
                return(0);
5337
3
            }
5338
1.18k
            if (xmlStrEqual(str, str2)) {
5339
560
                xmlFree(str2);
5340
560
    if (neq)
5341
274
        continue;
5342
286
                return (1);
5343
622
            } else if (neq) {
5344
233
    xmlFree(str2);
5345
233
    return (1);
5346
233
      }
5347
389
            xmlFree(str2);
5348
20.0k
        } else if (neq)
5349
236
      return (1);
5350
21.2k
    }
5351
557
    return (0);
5352
1.31k
}
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
27.6k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
27.6k
  int i, ret=0;
5372
27.6k
  xmlNodeSetPtr ns;
5373
27.6k
  xmlChar *str2;
5374
27.6k
  xmlXPathObjectPtr val;
5375
27.6k
  double v;
5376
5377
27.6k
    if ((arg == NULL) ||
5378
27.6k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
27.6k
    ns = arg->nodesetval;
5382
27.6k
    if (ns != NULL) {
5383
68.0k
  for (i=0;i<ns->nodeNr;i++) {
5384
41.2k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
41.2k
      if (str2 != NULL) {
5386
41.2k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
41.2k
    xmlFree(str2);
5388
41.2k
    xmlXPathNumberFunction(ctxt, 1);
5389
41.2k
                CHECK_ERROR0;
5390
41.2k
    val = xmlXPathValuePop(ctxt);
5391
41.2k
    v = val->floatval;
5392
41.2k
    xmlXPathReleaseObject(ctxt->context, val);
5393
41.2k
    if (!xmlXPathIsNaN(v)) {
5394
4.32k
        if ((!neq) && (v==f)) {
5395
495
      ret = 1;
5396
495
      break;
5397
3.82k
        } else if ((neq) && (v!=f)) {
5398
364
      ret = 1;
5399
364
      break;
5400
364
        }
5401
36.8k
    } else { /* NaN is unequal to any value */
5402
36.8k
        if (neq)
5403
5.47k
      ret = 1;
5404
36.8k
    }
5405
41.2k
      } else {
5406
10
                xmlXPathPErrMemory(ctxt);
5407
10
            }
5408
41.2k
  }
5409
27.6k
    }
5410
5411
27.6k
    return(ret);
5412
27.6k
}
5413
5414
5415
/**
5416
 * Implement the equal / not equal operation on XPath nodesets:
5417
 * `arg1` == `arg2`  or  `arg1` != `arg2`
5418
 * If both objects to be compared are node-sets, then the comparison
5419
 * will be true if and only if there is a node in the first node-set and
5420
 * a node in the second node-set such that the result of performing the
5421
 * comparison on the string-values of the two nodes is true.
5422
 *
5423
 * (needless to say, this is a costly operation)
5424
 *
5425
 * @param ctxt  XPath parser context
5426
 * @param arg1  first nodeset object argument
5427
 * @param arg2  second nodeset object argument
5428
 * @param neq  flag to show whether to test '=' (0) or '!=' (1)
5429
 * @returns 0 or 1 depending on the results of the test.
5430
 */
5431
static int
5432
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5433
33.8k
                      xmlXPathObjectPtr arg2, int neq) {
5434
33.8k
    int i, j;
5435
33.8k
    unsigned int *hashs1;
5436
33.8k
    unsigned int *hashs2;
5437
33.8k
    xmlChar **values1;
5438
33.8k
    xmlChar **values2;
5439
33.8k
    int ret = 0;
5440
33.8k
    xmlNodeSetPtr ns1;
5441
33.8k
    xmlNodeSetPtr ns2;
5442
5443
33.8k
    if ((arg1 == NULL) ||
5444
33.8k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
33.8k
    if ((arg2 == NULL) ||
5447
33.8k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
33.8k
    ns1 = arg1->nodesetval;
5451
33.8k
    ns2 = arg2->nodesetval;
5452
5453
33.8k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
8.40k
  return(0);
5455
25.4k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
2.91k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
22.4k
    if (neq == 0)
5462
43.1k
  for (i = 0;i < ns1->nodeNr;i++)
5463
108k
      for (j = 0;j < ns2->nodeNr;j++)
5464
87.2k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
4.58k
        return(1);
5466
5467
17.9k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
17.9k
    if (values1 == NULL) {
5469
1
        xmlXPathPErrMemory(ctxt);
5470
1
  return(0);
5471
1
    }
5472
17.9k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
17.9k
    if (hashs1 == NULL) {
5474
1
        xmlXPathPErrMemory(ctxt);
5475
1
  xmlFree(values1);
5476
1
  return(0);
5477
1
    }
5478
17.9k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
17.9k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
17.9k
    if (values2 == NULL) {
5481
4
        xmlXPathPErrMemory(ctxt);
5482
4
  xmlFree(hashs1);
5483
4
  xmlFree(values1);
5484
4
  return(0);
5485
4
    }
5486
17.8k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
17.8k
    if (hashs2 == NULL) {
5488
2
        xmlXPathPErrMemory(ctxt);
5489
2
  xmlFree(hashs1);
5490
2
  xmlFree(values1);
5491
2
  xmlFree(values2);
5492
2
  return(0);
5493
2
    }
5494
17.8k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
37.8k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
21.5k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
62.7k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
42.8k
      if (i == 0)
5499
38.8k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
42.8k
      if (hashs1[i] != hashs2[j]) {
5501
39.9k
    if (neq) {
5502
497
        ret = 1;
5503
497
        break;
5504
497
    }
5505
39.9k
      }
5506
2.84k
      else {
5507
2.84k
    if (values1[i] == NULL) {
5508
2.48k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
2.48k
                    if (values1[i] == NULL)
5510
6
                        xmlXPathPErrMemory(ctxt);
5511
2.48k
                }
5512
2.84k
    if (values2[j] == NULL) {
5513
2.08k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
2.08k
                    if (values2[j] == NULL)
5515
1
                        xmlXPathPErrMemory(ctxt);
5516
2.08k
                }
5517
2.84k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
2.84k
    if (ret)
5519
1.08k
        break;
5520
2.84k
      }
5521
42.8k
  }
5522
21.5k
  if (ret)
5523
1.57k
      break;
5524
21.5k
    }
5525
41.8k
    for (i = 0;i < ns1->nodeNr;i++)
5526
23.9k
  if (values1[i] != NULL)
5527
2.48k
      xmlFree(values1[i]);
5528
56.8k
    for (j = 0;j < ns2->nodeNr;j++)
5529
38.9k
  if (values2[j] != NULL)
5530
2.08k
      xmlFree(values2[j]);
5531
17.8k
    xmlFree(values1);
5532
17.8k
    xmlFree(values2);
5533
17.8k
    xmlFree(hashs1);
5534
17.8k
    xmlFree(hashs2);
5535
17.8k
    return(ret);
5536
17.8k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
237k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
237k
    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
237k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
115k
        case XPATH_BOOLEAN:
5550
115k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
69.9k
    case XPATH_BOOLEAN:
5554
69.9k
        ret = (arg1->boolval == arg2->boolval);
5555
69.9k
        break;
5556
33.0k
    case XPATH_NUMBER:
5557
33.0k
        ret = (arg1->boolval ==
5558
33.0k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
33.0k
        break;
5560
12.7k
    case XPATH_STRING:
5561
12.7k
        if ((arg2->stringval == NULL) ||
5562
12.7k
      (arg2->stringval[0] == 0)) ret = 0;
5563
10.5k
        else
5564
10.5k
      ret = 1;
5565
12.7k
        ret = (arg1->boolval == ret);
5566
12.7k
        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
115k
      }
5574
115k
      break;
5575
120k
        case XPATH_NUMBER:
5576
120k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
31.7k
    case XPATH_BOOLEAN:
5580
31.7k
        ret = (arg2->boolval==
5581
31.7k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
31.7k
        break;
5583
639
    case XPATH_STRING:
5584
639
        xmlXPathValuePush(ctxt, arg2);
5585
639
        xmlXPathNumberFunction(ctxt, 1);
5586
639
        arg2 = xmlXPathValuePop(ctxt);
5587
639
                    if (ctxt->error)
5588
1
                        break;
5589
                    /* Falls through. */
5590
88.6k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
88.6k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
84.8k
          xmlXPathIsNaN(arg2->floatval)) {
5594
4.39k
            ret = 0;
5595
84.2k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
4.55k
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
366
          ret = 1;
5598
4.19k
      else
5599
4.19k
          ret = 0;
5600
79.7k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
846
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
309
          ret = 1;
5603
537
      else
5604
537
          ret = 0;
5605
78.8k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
647
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
647
      else
5609
647
          ret = 0;
5610
78.2k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
261
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
261
      else
5614
261
          ret = 0;
5615
77.9k
        } else {
5616
77.9k
            ret = (arg1->floatval == arg2->floatval);
5617
77.9k
        }
5618
88.6k
        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
120k
      }
5626
120k
      break;
5627
120k
        case XPATH_STRING:
5628
1.61k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
591
    case XPATH_BOOLEAN:
5632
591
        if ((arg1->stringval == NULL) ||
5633
591
      (arg1->stringval[0] == 0)) ret = 0;
5634
392
        else
5635
392
      ret = 1;
5636
591
        ret = (arg2->boolval == ret);
5637
591
        break;
5638
72
    case XPATH_STRING:
5639
72
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
72
        break;
5641
956
    case XPATH_NUMBER:
5642
956
        xmlXPathValuePush(ctxt, arg1);
5643
956
        xmlXPathNumberFunction(ctxt, 1);
5644
956
        arg1 = xmlXPathValuePop(ctxt);
5645
956
                    if (ctxt->error)
5646
1
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
955
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
861
          xmlXPathIsNaN(arg2->floatval)) {
5650
861
            ret = 0;
5651
861
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
1
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
0
          ret = 1;
5654
1
      else
5655
1
          ret = 0;
5656
93
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
1
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
0
          ret = 1;
5659
1
      else
5660
1
          ret = 0;
5661
92
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
10
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
10
      else
5665
10
          ret = 0;
5666
82
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
3
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
3
      else
5670
3
          ret = 0;
5671
79
        } else {
5672
79
            ret = (arg1->floatval == arg2->floatval);
5673
79
        }
5674
955
        break;
5675
0
    case XPATH_USERS:
5676
        /* TODO */
5677
0
        break;
5678
0
    case XPATH_NODESET:
5679
0
    case XPATH_XSLT_TREE:
5680
0
        break;
5681
1.61k
      }
5682
1.61k
      break;
5683
1.61k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
237k
    }
5690
237k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
237k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
237k
    return(ret);
5693
237k
}
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
396k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
396k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
396k
    int ret = 0;
5705
5706
396k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
396k
    arg2 = xmlXPathValuePop(ctxt);
5708
396k
    arg1 = xmlXPathValuePop(ctxt);
5709
396k
    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
396k
    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
396k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
259k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
160k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
104k
    argtmp = arg2;
5732
104k
    arg2 = arg1;
5733
104k
    arg1 = argtmp;
5734
104k
  }
5735
160k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
32.4k
      case XPATH_NODESET:
5739
32.4k
      case XPATH_XSLT_TREE:
5740
32.4k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
32.4k
    break;
5742
95.1k
      case XPATH_BOOLEAN:
5743
95.1k
    if ((arg1->nodesetval == NULL) ||
5744
95.1k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
43.2k
    else
5746
43.2k
        ret = 1;
5747
95.1k
    ret = (ret == arg2->boolval);
5748
95.1k
    break;
5749
26.7k
      case XPATH_NUMBER:
5750
26.7k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
26.7k
    break;
5752
6.33k
      case XPATH_STRING:
5753
6.33k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
6.33k
                                                 arg2->stringval, 0);
5755
6.33k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
160k
  }
5760
160k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
160k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
160k
  return(ret);
5763
160k
    }
5764
5765
235k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
396k
}
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
6.82k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
6.82k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
6.82k
    int ret = 0;
5778
5779
6.82k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
6.82k
    arg2 = xmlXPathValuePop(ctxt);
5781
6.82k
    arg1 = xmlXPathValuePop(ctxt);
5782
6.82k
    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
6.82k
    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
6.82k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
4.87k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
4.87k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
2.72k
    argtmp = arg2;
5805
2.72k
    arg2 = arg1;
5806
2.72k
    arg1 = argtmp;
5807
2.72k
  }
5808
4.87k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
1.34k
      case XPATH_NODESET:
5812
1.34k
      case XPATH_XSLT_TREE:
5813
1.34k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
1.34k
    break;
5815
1.97k
      case XPATH_BOOLEAN:
5816
1.97k
    if ((arg1->nodesetval == NULL) ||
5817
1.97k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
831
    else
5819
831
        ret = 1;
5820
1.97k
    ret = (ret != arg2->boolval);
5821
1.97k
    break;
5822
977
      case XPATH_NUMBER:
5823
977
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
977
    break;
5825
577
      case XPATH_STRING:
5826
577
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
577
                                                 arg2->stringval, 1);
5828
577
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
4.87k
  }
5833
4.87k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
4.87k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
4.87k
  return(ret);
5836
4.87k
    }
5837
5838
1.94k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
6.82k
}
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
281k
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
281k
    int ret = 0, arg1i = 0, arg2i = 0;
5866
281k
    xmlXPathObjectPtr arg1, arg2;
5867
5868
281k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
281k
    arg2 = xmlXPathValuePop(ctxt);
5870
281k
    arg1 = xmlXPathValuePop(ctxt);
5871
281k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
8
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
8
  else
5875
8
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
8
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
281k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
161k
      (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
161k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
135k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
85.1k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
85.1k
  } else {
5890
76.1k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
25.7k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
25.7k
                                arg1, arg2);
5893
50.3k
      } else {
5894
50.3k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
50.3k
                                arg2, arg1);
5896
50.3k
      }
5897
76.1k
  }
5898
161k
  return(ret);
5899
161k
    }
5900
5901
120k
    if (arg1->type != XPATH_NUMBER) {
5902
15.6k
  xmlXPathValuePush(ctxt, arg1);
5903
15.6k
  xmlXPathNumberFunction(ctxt, 1);
5904
15.6k
  arg1 = xmlXPathValuePop(ctxt);
5905
15.6k
    }
5906
120k
    if (arg2->type != XPATH_NUMBER) {
5907
11.8k
  xmlXPathValuePush(ctxt, arg2);
5908
11.8k
  xmlXPathNumberFunction(ctxt, 1);
5909
11.8k
  arg2 = xmlXPathValuePop(ctxt);
5910
11.8k
    }
5911
120k
    if (ctxt->error)
5912
261
        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
120k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
89.2k
  ret=0;
5920
89.2k
    } else {
5921
31.0k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
31.0k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
31.0k
  if (inf && strict) {
5924
15.4k
      if ((arg1i == -1 && arg2i != -1) ||
5925
15.1k
    (arg2i == 1 && arg1i != 1)) {
5926
668
    ret = 1;
5927
14.7k
      } else if (arg1i == 0 && arg2i == 0) {
5928
13.3k
    ret = (arg1->floatval < arg2->floatval);
5929
13.3k
      } else {
5930
1.39k
    ret = 0;
5931
1.39k
      }
5932
15.4k
  }
5933
15.6k
  else if (inf && !strict) {
5934
2.81k
      if (arg1i == -1 || arg2i == 1) {
5935
1.39k
    ret = 1;
5936
1.41k
      } else if (arg1i == 0 && arg2i == 0) {
5937
791
    ret = (arg1->floatval <= arg2->floatval);
5938
791
      } else {
5939
623
    ret = 0;
5940
623
      }
5941
2.81k
  }
5942
12.8k
  else if (!inf && strict) {
5943
5.47k
      if ((arg1i == 1 && arg2i != 1) ||
5944
4.83k
    (arg2i == -1 && arg1i != -1)) {
5945
1.15k
    ret = 1;
5946
4.32k
      } else if (arg1i == 0 && arg2i == 0) {
5947
2.94k
    ret = (arg1->floatval > arg2->floatval);
5948
2.94k
      } else {
5949
1.37k
    ret = 0;
5950
1.37k
      }
5951
5.47k
  }
5952
7.33k
  else if (!inf && !strict) {
5953
7.33k
      if (arg1i == 1 || arg2i == -1) {
5954
4.59k
    ret = 1;
5955
4.59k
      } else if (arg1i == 0 && arg2i == 0) {
5956
2.21k
    ret = (arg1->floatval >= arg2->floatval);
5957
2.21k
      } else {
5958
526
    ret = 0;
5959
526
      }
5960
7.33k
  }
5961
31.0k
    }
5962
120k
error:
5963
120k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
120k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
120k
    return(ret);
5966
120k
}
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
114k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
114k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
114k
    CAST_TO_NUMBER;
5979
114k
    CHECK_TYPE(XPATH_NUMBER);
5980
114k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
114k
}
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
71.9k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
71.9k
    xmlXPathObjectPtr arg;
5993
71.9k
    double val;
5994
5995
71.9k
    arg = xmlXPathValuePop(ctxt);
5996
71.9k
    if (arg == NULL)
5997
71.9k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
71.9k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
71.9k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
71.9k
    CAST_TO_NUMBER;
6001
71.9k
    CHECK_TYPE(XPATH_NUMBER);
6002
71.9k
    ctxt->value->floatval += val;
6003
71.9k
}
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
69.2k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
69.2k
    xmlXPathObjectPtr arg;
6015
69.2k
    double val;
6016
6017
69.2k
    arg = xmlXPathValuePop(ctxt);
6018
69.2k
    if (arg == NULL)
6019
69.2k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
69.2k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
69.2k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
69.2k
    CAST_TO_NUMBER;
6023
69.2k
    CHECK_TYPE(XPATH_NUMBER);
6024
69.1k
    ctxt->value->floatval -= val;
6025
69.1k
}
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
169k
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
169k
    xmlXPathObjectPtr arg;
6037
169k
    double val;
6038
6039
169k
    arg = xmlXPathValuePop(ctxt);
6040
169k
    if (arg == NULL)
6041
169k
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
169k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
169k
    xmlXPathReleaseObject(ctxt->context, arg);
6044
169k
    CAST_TO_NUMBER;
6045
169k
    CHECK_TYPE(XPATH_NUMBER);
6046
169k
    ctxt->value->floatval *= val;
6047
169k
}
6048
6049
/**
6050
 * Implement the div operation on XPath objects `arg1` / `arg2`.
6051
 * The numeric operators convert their operands to numbers as if
6052
 * by calling the number function.
6053
 *
6054
 * @param ctxt  the XPath Parser context
6055
 */
6056
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6057
void
6058
1.50k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
1.50k
    xmlXPathObjectPtr arg;
6060
1.50k
    double val;
6061
6062
1.50k
    arg = xmlXPathValuePop(ctxt);
6063
1.50k
    if (arg == NULL)
6064
1.50k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
1.50k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
1.50k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
1.50k
    CAST_TO_NUMBER;
6068
1.50k
    CHECK_TYPE(XPATH_NUMBER);
6069
1.50k
    ctxt->value->floatval /= val;
6070
1.50k
}
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
1.56k
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
1.56k
    xmlXPathObjectPtr arg;
6082
1.56k
    double arg1, arg2;
6083
6084
1.56k
    arg = xmlXPathValuePop(ctxt);
6085
1.56k
    if (arg == NULL)
6086
1.56k
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
1.56k
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
1.56k
    xmlXPathReleaseObject(ctxt->context, arg);
6089
1.56k
    CAST_TO_NUMBER;
6090
1.56k
    CHECK_TYPE(XPATH_NUMBER);
6091
1.56k
    arg1 = ctxt->value->floatval;
6092
1.56k
    if (arg2 == 0)
6093
434
  ctxt->value->floatval = xmlXPathNAN;
6094
1.13k
    else {
6095
1.13k
  ctxt->value->floatval = fmod(arg1, arg2);
6096
1.13k
    }
6097
1.56k
}
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
874
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
874
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
874
    if (cur == NULL)
6141
437
        return(ctxt->context->node);
6142
437
    return(NULL);
6143
874
}
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
220k
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
220k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
220k
    if (cur == NULL) {
6157
93.3k
  if (ctxt->context->node == NULL) return(NULL);
6158
93.3k
  switch (ctxt->context->node->type) {
6159
22.9k
            case XML_ELEMENT_NODE:
6160
67.0k
            case XML_TEXT_NODE:
6161
79.3k
            case XML_CDATA_SECTION_NODE:
6162
79.3k
            case XML_ENTITY_REF_NODE:
6163
79.3k
            case XML_ENTITY_NODE:
6164
80.6k
            case XML_PI_NODE:
6165
92.8k
            case XML_COMMENT_NODE:
6166
92.8k
            case XML_NOTATION_NODE:
6167
92.8k
            case XML_DTD_NODE:
6168
92.8k
    return(ctxt->context->node->children);
6169
415
            case XML_DOCUMENT_NODE:
6170
415
            case XML_DOCUMENT_TYPE_NODE:
6171
415
            case XML_DOCUMENT_FRAG_NODE:
6172
415
            case XML_HTML_DOCUMENT_NODE:
6173
415
    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
107
            case XML_ATTRIBUTE_NODE:
6178
107
      case XML_NAMESPACE_DECL:
6179
107
      case XML_XINCLUDE_START:
6180
107
      case XML_XINCLUDE_END:
6181
107
    return(NULL);
6182
93.3k
  }
6183
0
  return(NULL);
6184
93.3k
    }
6185
127k
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
127k
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
127k
    return(cur->next);
6189
127k
}
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
2.86M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
2.86M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
2.86M
    if (cur == NULL) {
6203
1.41M
  cur = ctxt->context->node;
6204
1.41M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
1.41M
  switch (cur->type) {
6209
1.09M
            case XML_ELEMENT_NODE:
6210
1.09M
      case XML_DOCUMENT_FRAG_NODE:
6211
1.09M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
1.09M
            case XML_ENTITY_NODE:
6213
1.09M
    cur = cur->children;
6214
1.09M
    if (cur != NULL) {
6215
381k
        if (cur->type == XML_ELEMENT_NODE)
6216
184k
      return(cur);
6217
205k
        do {
6218
205k
      cur = cur->next;
6219
205k
        } while ((cur != NULL) &&
6220
126k
      (cur->type != XML_ELEMENT_NODE));
6221
197k
        return(cur);
6222
381k
    }
6223
710k
    return(NULL);
6224
209k
            case XML_DOCUMENT_NODE:
6225
209k
            case XML_HTML_DOCUMENT_NODE:
6226
209k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
112k
      default:
6228
112k
    return(NULL);
6229
1.41M
  }
6230
0
  return(NULL);
6231
1.41M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
1.44M
    switch (cur->type) {
6236
1.44M
  case XML_ELEMENT_NODE:
6237
1.44M
  case XML_TEXT_NODE:
6238
1.44M
  case XML_ENTITY_REF_NODE:
6239
1.44M
  case XML_ENTITY_NODE:
6240
1.44M
  case XML_CDATA_SECTION_NODE:
6241
1.44M
  case XML_PI_NODE:
6242
1.44M
  case XML_COMMENT_NODE:
6243
1.44M
  case XML_XINCLUDE_END:
6244
1.44M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
1.44M
    }
6249
1.44M
    if (cur->next != NULL) {
6250
1.04M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
881k
      return(cur->next);
6252
162k
  cur = cur->next;
6253
224k
  do {
6254
224k
      cur = cur->next;
6255
224k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
162k
  return(cur);
6257
1.04M
    }
6258
405k
    return(NULL);
6259
1.44M
}
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
5.13M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
5.13M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
5.13M
    if (cur == NULL) {
6274
107k
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
107k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
107k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
10.1k
      return(NULL);
6279
6280
97.5k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
49.1k
      return(ctxt->context->doc->children);
6282
48.4k
        return(ctxt->context->node->children);
6283
97.5k
    }
6284
6285
5.03M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
5.03M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
1.30M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
1.30M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
1.30M
      if (cur->type != XML_DTD_NODE)
6297
1.30M
    return(cur);
6298
1.30M
  }
6299
1.30M
    }
6300
6301
3.72M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
3.71M
    while (cur->next != NULL) {
6304
3.16M
  cur = cur->next;
6305
3.16M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
3.16M
      (cur->type != XML_DTD_NODE))
6307
3.16M
      return(cur);
6308
3.16M
    }
6309
6310
1.33M
    do {
6311
1.33M
        cur = cur->parent;
6312
1.33M
  if (cur == NULL) break;
6313
1.33M
  if (cur == ctxt->context->node) return(NULL);
6314
1.18M
  if (cur->next != NULL) {
6315
399k
      cur = cur->next;
6316
399k
      return(cur);
6317
399k
  }
6318
1.18M
    } while (cur != NULL);
6319
0
    return(cur);
6320
546k
}
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
3.99M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
3.99M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
3.99M
    if (cur == NULL)
6337
146k
        return(ctxt->context->node);
6338
6339
3.84M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
3.84M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
3.84M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
6.30k
        return(NULL);
6344
6345
3.84M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
3.84M
}
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
232k
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
232k
    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
232k
    if (cur == NULL) {
6365
120k
  if (ctxt->context->node == NULL) return(NULL);
6366
120k
  switch (ctxt->context->node->type) {
6367
81.6k
            case XML_ELEMENT_NODE:
6368
109k
            case XML_TEXT_NODE:
6369
110k
            case XML_CDATA_SECTION_NODE:
6370
110k
            case XML_ENTITY_REF_NODE:
6371
110k
            case XML_ENTITY_NODE:
6372
110k
            case XML_PI_NODE:
6373
111k
            case XML_COMMENT_NODE:
6374
111k
            case XML_NOTATION_NODE:
6375
111k
            case XML_DTD_NODE:
6376
111k
      case XML_ELEMENT_DECL:
6377
111k
      case XML_ATTRIBUTE_DECL:
6378
111k
      case XML_XINCLUDE_START:
6379
111k
      case XML_XINCLUDE_END:
6380
111k
      case XML_ENTITY_DECL:
6381
111k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
111k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
106k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
106k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
106k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
111k
    return(ctxt->context->node->parent);
6389
713
            case XML_ATTRIBUTE_NODE: {
6390
713
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
713
    return(att->parent);
6393
111k
      }
6394
7.56k
            case XML_DOCUMENT_NODE:
6395
7.56k
            case XML_DOCUMENT_TYPE_NODE:
6396
7.56k
            case XML_DOCUMENT_FRAG_NODE:
6397
7.56k
            case XML_HTML_DOCUMENT_NODE:
6398
7.56k
                return(NULL);
6399
266
      case XML_NAMESPACE_DECL: {
6400
266
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
266
    if ((ns->next != NULL) &&
6403
266
        (ns->next->type != XML_NAMESPACE_DECL))
6404
266
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
266
      }
6407
120k
  }
6408
120k
    }
6409
111k
    return(NULL);
6410
232k
}
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
163k
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
163k
    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
163k
    if (cur == NULL) {
6433
30.4k
  if (ctxt->context->node == NULL) return(NULL);
6434
30.4k
  switch (ctxt->context->node->type) {
6435
27.5k
            case XML_ELEMENT_NODE:
6436
29.1k
            case XML_TEXT_NODE:
6437
29.2k
            case XML_CDATA_SECTION_NODE:
6438
29.2k
            case XML_ENTITY_REF_NODE:
6439
29.2k
            case XML_ENTITY_NODE:
6440
29.7k
            case XML_PI_NODE:
6441
29.9k
            case XML_COMMENT_NODE:
6442
29.9k
      case XML_DTD_NODE:
6443
29.9k
      case XML_ELEMENT_DECL:
6444
29.9k
      case XML_ATTRIBUTE_DECL:
6445
29.9k
      case XML_ENTITY_DECL:
6446
29.9k
            case XML_NOTATION_NODE:
6447
29.9k
      case XML_XINCLUDE_START:
6448
29.9k
      case XML_XINCLUDE_END:
6449
29.9k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
29.9k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
29.0k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
29.0k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
29.0k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
29.9k
    return(ctxt->context->node->parent);
6457
10
            case XML_ATTRIBUTE_NODE: {
6458
10
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
10
    return(tmp->parent);
6461
29.9k
      }
6462
446
            case XML_DOCUMENT_NODE:
6463
446
            case XML_DOCUMENT_TYPE_NODE:
6464
446
            case XML_DOCUMENT_FRAG_NODE:
6465
446
            case XML_HTML_DOCUMENT_NODE:
6466
446
                return(NULL);
6467
0
      case XML_NAMESPACE_DECL: {
6468
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
0
    if ((ns->next != NULL) &&
6471
0
        (ns->next->type != XML_NAMESPACE_DECL))
6472
0
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
0
      }
6476
30.4k
  }
6477
0
  return(NULL);
6478
30.4k
    }
6479
133k
    if (cur == ctxt->context->doc->children)
6480
4.10k
  return((xmlNodePtr) ctxt->context->doc);
6481
129k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
34.3k
  return(NULL);
6483
94.8k
    switch (cur->type) {
6484
92.7k
  case XML_ELEMENT_NODE:
6485
94.2k
  case XML_TEXT_NODE:
6486
94.4k
  case XML_CDATA_SECTION_NODE:
6487
94.4k
  case XML_ENTITY_REF_NODE:
6488
94.4k
  case XML_ENTITY_NODE:
6489
94.8k
  case XML_PI_NODE:
6490
94.8k
  case XML_COMMENT_NODE:
6491
94.8k
  case XML_NOTATION_NODE:
6492
94.8k
  case XML_DTD_NODE:
6493
94.8k
        case XML_ELEMENT_DECL:
6494
94.8k
        case XML_ATTRIBUTE_DECL:
6495
94.8k
        case XML_ENTITY_DECL:
6496
94.8k
  case XML_XINCLUDE_START:
6497
94.8k
  case XML_XINCLUDE_END:
6498
94.8k
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
94.8k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
65.8k
    ((cur->parent->name[0] == ' ') ||
6502
65.8k
     (xmlStrEqual(cur->parent->name,
6503
65.8k
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
94.8k
      return(cur->parent);
6506
34
  case XML_ATTRIBUTE_NODE: {
6507
34
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
34
      return(att->parent);
6510
94.8k
  }
6511
0
  case XML_NAMESPACE_DECL: {
6512
0
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
0
      if ((ns->next != NULL) &&
6515
0
          (ns->next->type != XML_NAMESPACE_DECL))
6516
0
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
0
  }
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
94.8k
    }
6526
0
    return(NULL);
6527
94.8k
}
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
30.7k
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
30.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
30.7k
    if (cur == NULL)
6544
4.33k
        return(ctxt->context->node);
6545
26.4k
    return(xmlXPathNextAncestor(ctxt, cur));
6546
30.7k
}
6547
6548
/**
6549
 * Traversal function for the "following-sibling" direction
6550
 * The following-sibling axis contains the following siblings of the context
6551
 * node in document order.
6552
 *
6553
 * @param ctxt  the XPath Parser context
6554
 * @param cur  the current node in the traversal
6555
 * @returns the next element following that axis
6556
 */
6557
xmlNode *
6558
0
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
0
        return(NULL);
6563
6564
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6565
0
        return(NULL);
6566
6567
0
    if (cur == NULL)
6568
0
        cur = ctxt->context->node;
6569
6570
0
    if (cur->type == XML_DOCUMENT_NODE)
6571
0
        return(NULL);
6572
6573
0
    return(cur->next);
6574
0
}
6575
6576
/**
6577
 * Traversal function for the "preceding-sibling" direction
6578
 * The preceding-sibling axis contains the preceding siblings of the context
6579
 * node in reverse document order; the first preceding sibling is first on the
6580
 * axis; the sibling preceding that node is the second on the axis and so on.
6581
 *
6582
 * @param ctxt  the XPath Parser context
6583
 * @param cur  the current node in the traversal
6584
 * @returns the next element following that axis
6585
 */
6586
xmlNode *
6587
3
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6588
3
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589
3
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6590
3
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6591
0
        return(NULL);
6592
6593
3
    if (cur == (xmlNodePtr) ctxt->context->doc)
6594
0
        return(NULL);
6595
6596
3
    if (cur == NULL) {
6597
3
        cur = ctxt->context->node;
6598
3
    } else if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6599
0
        cur = cur->prev;
6600
0
        if (cur == NULL)
6601
0
            cur = ctxt->context->node;
6602
0
    }
6603
6604
3
    if (cur->type == XML_DOCUMENT_NODE)
6605
3
        return(NULL);
6606
6607
0
    return(cur->prev);
6608
3
}
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
6.27k
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6623
6.27k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6624
6.27k
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6625
5.51k
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6626
216
        return(cur->children);
6627
6628
6.06k
    if (cur == NULL) {
6629
760
        cur = ctxt->context->node;
6630
760
        if (cur->type == XML_ATTRIBUTE_NODE) {
6631
77
            cur = cur->parent;
6632
683
        } else if (cur->type == XML_NAMESPACE_DECL) {
6633
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6634
6635
0
            if ((ns->next == NULL) ||
6636
0
                (ns->next->type == XML_NAMESPACE_DECL))
6637
0
                return (NULL);
6638
0
            cur = (xmlNodePtr) ns->next;
6639
0
        }
6640
760
    }
6641
6642
    /* ERROR */
6643
6.06k
    if (cur == NULL)
6644
0
        return(NULL);
6645
6646
6.06k
    if (cur->type == XML_DOCUMENT_NODE)
6647
153
        return(NULL);
6648
6649
5.91k
    if (cur->next != NULL)
6650
5.08k
        return(cur->next);
6651
6652
1.37k
    do {
6653
1.37k
        cur = cur->parent;
6654
1.37k
        if (cur == NULL)
6655
0
            break;
6656
1.37k
        if (cur == (xmlNodePtr) ctxt->context->doc)
6657
607
            return(NULL);
6658
768
        if (cur->next != NULL && cur->type != XML_DOCUMENT_NODE)
6659
216
            return(cur->next);
6660
768
    } while (cur != NULL);
6661
6662
0
    return(cur);
6663
823
}
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
91.3k
{
6757
91.3k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6758
91.3k
    if (cur == NULL) {
6759
4.10k
        cur = ctxt->context->node;
6760
4.10k
        if (cur == NULL)
6761
0
            return (NULL);
6762
4.10k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6763
0
            cur = cur->parent;
6764
4.10k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6765
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6766
6767
0
            if ((ns->next == NULL) ||
6768
0
                (ns->next->type == XML_NAMESPACE_DECL))
6769
0
                return (NULL);
6770
0
            cur = (xmlNodePtr) ns->next;
6771
0
        }
6772
4.10k
        ctxt->ancestor = cur->parent;
6773
4.10k
    }
6774
6775
91.3k
    if (cur->type == XML_NAMESPACE_DECL || cur->type == XML_DOCUMENT_NODE)
6776
64
        return(NULL);
6777
6778
91.3k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6779
2.47k
  cur = cur->prev;
6780
6781
1.33M
    while (cur->prev == NULL) {
6782
1.29M
        cur = cur->parent;
6783
1.29M
        if (cur == NULL)
6784
2.76k
            return (NULL);
6785
1.29M
        if (cur == ctxt->context->doc->children)
6786
1.27k
            return (NULL);
6787
1.29M
        if (cur != ctxt->ancestor)
6788
43.5k
            return (cur);
6789
1.24M
        ctxt->ancestor = cur->parent;
6790
1.24M
    }
6791
6792
43.7k
    if (cur->type == XML_DOCUMENT_NODE)
6793
0
        return(NULL);
6794
6795
43.7k
    cur = cur->prev;
6796
87.2k
    while (cur->last != NULL)
6797
43.5k
        cur = cur->last;
6798
43.7k
    return (cur);
6799
43.7k
}
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
120k
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6815
120k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6816
120k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6817
113k
    if (cur == NULL) {
6818
31.8k
        if (ctxt->context->tmpNsList != NULL)
6819
512
      xmlFree(ctxt->context->tmpNsList);
6820
31.8k
  ctxt->context->tmpNsNr = 0;
6821
31.8k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6822
31.8k
                             &ctxt->context->tmpNsList) < 0) {
6823
5
            xmlXPathPErrMemory(ctxt);
6824
5
            return(NULL);
6825
5
        }
6826
31.8k
        if (ctxt->context->tmpNsList != NULL) {
6827
81.5k
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6828
51.1k
                ctxt->context->tmpNsNr++;
6829
51.1k
            }
6830
30.4k
        }
6831
31.8k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6832
31.8k
    }
6833
81.6k
    if (ctxt->context->tmpNsNr > 0) {
6834
50.6k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6835
50.6k
    } else {
6836
31.0k
  if (ctxt->context->tmpNsList != NULL)
6837
29.7k
      xmlFree(ctxt->context->tmpNsList);
6838
31.0k
  ctxt->context->tmpNsList = NULL;
6839
31.0k
  return(NULL);
6840
31.0k
    }
6841
81.6k
}
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
313k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6853
313k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854
313k
    if (ctxt->context->node == NULL)
6855
0
  return(NULL);
6856
313k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6857
61.9k
  return(NULL);
6858
251k
    if (cur == NULL) {
6859
237k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6860
0
      return(NULL);
6861
237k
        return((xmlNodePtr)ctxt->context->node->properties);
6862
237k
    }
6863
14.4k
    return((xmlNodePtr)cur->next);
6864
251k
}
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
394k
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6888
394k
    if ((ctxt == NULL) || (ctxt->context == NULL))
6889
0
  return;
6890
394k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6891
394k
                                            (xmlNodePtr) ctxt->context->doc));
6892
394k
}
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
617
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6912
1.84k
    CHECK_ARITY(0);
6913
1.84k
    if (ctxt->context->contextSize >= 0) {
6914
616
  xmlXPathValuePush(ctxt,
6915
616
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6916
616
    } else {
6917
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6918
0
    }
6919
1.84k
}
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
6.07k
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6933
18.2k
    CHECK_ARITY(0);
6934
18.2k
    if (ctxt->context->proximityPosition >= 0) {
6935
6.07k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6936
6.07k
            (double) ctxt->context->proximityPosition));
6937
6.07k
    } else {
6938
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6939
0
    }
6940
18.2k
}
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
55
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6951
55
    xmlXPathObjectPtr cur;
6952
6953
157
    CHECK_ARITY(1);
6954
157
    if ((ctxt->value == NULL) ||
6955
51
  ((ctxt->value->type != XPATH_NODESET) &&
6956
3
   (ctxt->value->type != XPATH_XSLT_TREE)))
6957
48
  XP_ERROR(XPATH_INVALID_TYPE);
6958
48
    cur = xmlXPathValuePop(ctxt);
6959
6960
48
    if ((cur == NULL) || (cur->nodesetval == NULL))
6961
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6962
48
    else
6963
48
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6964
48
      (double) cur->nodesetval->nodeNr));
6965
48
    xmlXPathReleaseObject(ctxt->context, cur);
6966
48
}
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
6.99k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6977
6.99k
    xmlNodeSetPtr ret;
6978
6.99k
    const xmlChar *cur = ids;
6979
6.99k
    xmlChar *ID;
6980
6.99k
    xmlAttrPtr attr;
6981
6.99k
    xmlNodePtr elem = NULL;
6982
6983
6.99k
    if (ids == NULL) return(NULL);
6984
6985
6.97k
    ret = xmlXPathNodeSetCreate(NULL);
6986
6.97k
    if (ret == NULL)
6987
9
        return(ret);
6988
6989
6.96k
    while (IS_BLANK_CH(*cur)) cur++;
6990
15.7k
    while (*cur != 0) {
6991
52.3k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6992
43.4k
      cur++;
6993
6994
8.82k
        ID = xmlStrndup(ids, cur - ids);
6995
8.82k
  if (ID == NULL) {
6996
17
            xmlXPathFreeNodeSet(ret);
6997
17
            return(NULL);
6998
17
        }
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
8.81k
        attr = xmlGetID(doc, ID);
7007
8.81k
        xmlFree(ID);
7008
8.81k
        if (attr != NULL) {
7009
2.29k
            if (attr->type == XML_ATTRIBUTE_NODE)
7010
2.29k
                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
2.29k
            if (elem != NULL) {
7016
2.29k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7017
1
                    xmlXPathFreeNodeSet(ret);
7018
1
                    return(NULL);
7019
1
                }
7020
2.29k
            }
7021
2.29k
        }
7022
7023
10.8k
  while (IS_BLANK_CH(*cur)) cur++;
7024
8.80k
  ids = cur;
7025
8.80k
    }
7026
6.95k
    return(ret);
7027
6.96k
}
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
5.15k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7048
5.15k
    xmlChar *tokens;
7049
5.15k
    xmlNodeSetPtr ret;
7050
5.15k
    xmlXPathObjectPtr obj;
7051
7052
15.4k
    CHECK_ARITY(1);
7053
15.4k
    obj = xmlXPathValuePop(ctxt);
7054
15.4k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7055
5.14k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7056
1.91k
  xmlNodeSetPtr ns;
7057
1.91k
  int i;
7058
7059
1.91k
  ret = xmlXPathNodeSetCreate(NULL);
7060
1.91k
        if (ret == NULL)
7061
4
            xmlXPathPErrMemory(ctxt);
7062
7063
1.91k
  if (obj->nodesetval != NULL) {
7064
5.67k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7065
3.76k
    tokens =
7066
3.76k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7067
3.76k
                if (tokens == NULL)
7068
14
                    xmlXPathPErrMemory(ctxt);
7069
3.76k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7070
3.76k
                if (ns == NULL)
7071
34
                    xmlXPathPErrMemory(ctxt);
7072
3.76k
    ret = xmlXPathNodeSetMerge(ret, ns);
7073
3.76k
                if (ret == NULL)
7074
1
                    xmlXPathPErrMemory(ctxt);
7075
3.76k
    xmlXPathFreeNodeSet(ns);
7076
3.76k
    if (tokens != NULL)
7077
3.75k
        xmlFree(tokens);
7078
3.76k
      }
7079
1.91k
  }
7080
1.91k
  xmlXPathReleaseObject(ctxt->context, obj);
7081
1.91k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7082
1.91k
  return;
7083
1.91k
    }
7084
3.23k
    tokens = xmlXPathCastToString(obj);
7085
3.23k
    if (tokens == NULL)
7086
4
        xmlXPathPErrMemory(ctxt);
7087
3.23k
    xmlXPathReleaseObject(ctxt->context, obj);
7088
3.23k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7089
3.23k
    if (ret == NULL)
7090
11
        xmlXPathPErrMemory(ctxt);
7091
3.23k
    xmlFree(tokens);
7092
3.23k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7093
3.23k
}
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
1.48k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7109
1.48k
    xmlXPathObjectPtr cur;
7110
7111
1.48k
    if (ctxt == NULL) return;
7112
7113
1.48k
    if (nargs == 0) {
7114
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7115
0
  nargs = 1;
7116
0
    }
7117
7118
4.44k
    CHECK_ARITY(1);
7119
4.44k
    if ((ctxt->value == NULL) ||
7120
1.48k
  ((ctxt->value->type != XPATH_NODESET) &&
7121
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7122
1.47k
  XP_ERROR(XPATH_INVALID_TYPE);
7123
1.47k
    cur = xmlXPathValuePop(ctxt);
7124
7125
1.47k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7126
1
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7127
1.47k
    } else {
7128
1.47k
  int i = 0; /* Should be first in document order !!!!! */
7129
1.47k
  switch (cur->nodesetval->nodeTab[i]->type) {
7130
1
  case XML_ELEMENT_NODE:
7131
2
  case XML_ATTRIBUTE_NODE:
7132
2
  case XML_PI_NODE:
7133
2
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7134
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7135
2
      else
7136
2
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7137
2
      cur->nodesetval->nodeTab[i]->name));
7138
2
      break;
7139
0
  case XML_NAMESPACE_DECL:
7140
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7141
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7142
0
      break;
7143
1.47k
  default:
7144
1.47k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7145
1.47k
  }
7146
1.47k
    }
7147
1.47k
    xmlXPathReleaseObject(ctxt->context, cur);
7148
1.47k
}
7149
7150
/**
7151
 * Implement the namespace-uri() XPath function
7152
 *    string namespace-uri(node-set?)
7153
 * The namespace-uri function returns a string containing the
7154
 * namespace URI of the expanded name of the node in the argument
7155
 * node-set that is first in document order. If the node-set is empty,
7156
 * the first node has no name, or the expanded name has no namespace
7157
 * URI, an empty string is returned. If the argument is omitted it
7158
 * defaults to the context node.
7159
 *
7160
 * @param ctxt  the XPath Parser context
7161
 * @param nargs  the number of arguments
7162
 */
7163
void
7164
0
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7165
0
    xmlXPathObjectPtr cur;
7166
7167
0
    if (ctxt == NULL) return;
7168
7169
0
    if (nargs == 0) {
7170
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7171
0
  nargs = 1;
7172
0
    }
7173
0
    CHECK_ARITY(1);
7174
0
    if ((ctxt->value == NULL) ||
7175
0
  ((ctxt->value->type != XPATH_NODESET) &&
7176
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7177
0
  XP_ERROR(XPATH_INVALID_TYPE);
7178
0
    cur = xmlXPathValuePop(ctxt);
7179
7180
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7181
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7182
0
    } else {
7183
0
  int i = 0; /* Should be first in document order !!!!! */
7184
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7185
0
  case XML_ELEMENT_NODE:
7186
0
  case XML_ATTRIBUTE_NODE:
7187
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7188
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7189
0
      else
7190
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7191
0
        cur->nodesetval->nodeTab[i]->ns->href));
7192
0
      break;
7193
0
  default:
7194
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7195
0
  }
7196
0
    }
7197
0
    xmlXPathReleaseObject(ctxt->context, cur);
7198
0
}
7199
7200
/**
7201
 * Implement the name() XPath function
7202
 *    string name(node-set?)
7203
 * The name function returns a string containing a QName representing
7204
 * the name of the node in the argument node-set that is first in document
7205
 * order. The QName must represent the name with respect to the namespace
7206
 * declarations in effect on the node whose name is being represented.
7207
 * Typically, this will be the form in which the name occurred in the XML
7208
 * source. This need not be the case if there are namespace declarations
7209
 * in effect on the node that associate multiple prefixes with the same
7210
 * namespace. However, an implementation may include information about
7211
 * the original prefix in its representation of nodes; in this case, an
7212
 * implementation can ensure that the returned string is always the same
7213
 * as the QName used in the XML source. If the argument it omitted it
7214
 * defaults to the context node.
7215
 * Libxml keep the original prefix so the "real qualified name" used is
7216
 * returned.
7217
 *
7218
 * @param ctxt  the XPath Parser context
7219
 * @param nargs  the number of arguments
7220
 */
7221
static void
7222
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7223
7.58k
{
7224
7.58k
    xmlXPathObjectPtr cur;
7225
7226
7.58k
    if (nargs == 0) {
7227
2.84k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7228
2.84k
        nargs = 1;
7229
2.84k
    }
7230
7231
22.7k
    CHECK_ARITY(1);
7232
22.7k
    if ((ctxt->value == NULL) ||
7233
7.57k
        ((ctxt->value->type != XPATH_NODESET) &&
7234
4
         (ctxt->value->type != XPATH_XSLT_TREE)))
7235
7.57k
        XP_ERROR(XPATH_INVALID_TYPE);
7236
7.57k
    cur = xmlXPathValuePop(ctxt);
7237
7238
7.57k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7239
2.06k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7240
5.50k
    } else {
7241
5.50k
        int i = 0;              /* Should be first in document order !!!!! */
7242
7243
5.50k
        switch (cur->nodesetval->nodeTab[i]->type) {
7244
4.02k
            case XML_ELEMENT_NODE:
7245
4.02k
            case XML_ATTRIBUTE_NODE:
7246
4.02k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7247
0
        xmlXPathValuePush(ctxt,
7248
0
      xmlXPathCacheNewCString(ctxt, ""));
7249
4.02k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7250
3.80k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7251
3.80k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7252
3.80k
          cur->nodesetval->nodeTab[i]->name));
7253
3.80k
    } else {
7254
218
        xmlChar *fullname;
7255
7256
218
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7257
218
             cur->nodesetval->nodeTab[i]->ns->prefix,
7258
218
             NULL, 0);
7259
218
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7260
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7261
218
        if (fullname == NULL)
7262
1
                        xmlXPathPErrMemory(ctxt);
7263
218
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7264
218
                }
7265
4.02k
                break;
7266
1.48k
            default:
7267
1.48k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7268
1.48k
        cur->nodesetval->nodeTab[i]));
7269
1.48k
                xmlXPathLocalNameFunction(ctxt, 1);
7270
5.50k
        }
7271
5.50k
    }
7272
7.57k
    xmlXPathReleaseObject(ctxt->context, cur);
7273
7.57k
}
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
47.9k
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7313
47.9k
    xmlXPathObjectPtr cur;
7314
47.9k
    xmlChar *stringval;
7315
7316
47.9k
    if (ctxt == NULL) return;
7317
47.9k
    if (nargs == 0) {
7318
99
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7319
99
        if (stringval == NULL)
7320
1
            xmlXPathPErrMemory(ctxt);
7321
99
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7322
99
  return;
7323
99
    }
7324
7325
191k
    CHECK_ARITY(1);
7326
191k
    cur = xmlXPathValuePop(ctxt);
7327
191k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7328
47.8k
    if (cur->type != XPATH_STRING) {
7329
47.7k
        stringval = xmlXPathCastToString(cur);
7330
47.7k
        if (stringval == NULL)
7331
29
            xmlXPathPErrMemory(ctxt);
7332
47.7k
        xmlXPathReleaseObject(ctxt->context, cur);
7333
47.7k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7334
47.7k
    }
7335
47.8k
    xmlXPathValuePush(ctxt, cur);
7336
47.8k
}
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
149
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7351
149
    xmlXPathObjectPtr cur;
7352
7353
149
    if (nargs == 0) {
7354
10
        if ((ctxt == NULL) || (ctxt->context == NULL))
7355
0
      return;
7356
10
  if (ctxt->context->node == NULL) {
7357
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7358
10
  } else {
7359
10
      xmlChar *content;
7360
7361
10
      content = xmlXPathCastNodeToString(ctxt->context->node);
7362
10
            if (content == NULL)
7363
1
                xmlXPathPErrMemory(ctxt);
7364
10
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7365
10
    xmlUTF8Strlen(content)));
7366
10
      xmlFree(content);
7367
10
  }
7368
10
  return;
7369
10
    }
7370
550
    CHECK_ARITY(1);
7371
550
    CAST_TO_STRING;
7372
550
    CHECK_TYPE(XPATH_STRING);
7373
134
    cur = xmlXPathValuePop(ctxt);
7374
134
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7375
134
  xmlUTF8Strlen(cur->stringval)));
7376
134
    xmlXPathReleaseObject(ctxt->context, cur);
7377
134
}
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
549
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7389
549
    xmlXPathObjectPtr cur, newobj;
7390
549
    xmlChar *tmp;
7391
7392
549
    if (ctxt == NULL) return;
7393
549
    if (nargs < 2) {
7394
8
  CHECK_ARITY(2);
7395
8
    }
7396
7397
541
    CAST_TO_STRING;
7398
541
    cur = xmlXPathValuePop(ctxt);
7399
541
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7400
2
  xmlXPathReleaseObject(ctxt->context, cur);
7401
2
  return;
7402
2
    }
7403
539
    nargs--;
7404
7405
1.83k
    while (nargs > 0) {
7406
1.29k
  CAST_TO_STRING;
7407
1.29k
  newobj = xmlXPathValuePop(ctxt);
7408
1.29k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7409
3
      xmlXPathReleaseObject(ctxt->context, newobj);
7410
3
      xmlXPathReleaseObject(ctxt->context, cur);
7411
3
      XP_ERROR(XPATH_INVALID_TYPE);
7412
0
  }
7413
1.29k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7414
1.29k
        if (tmp == NULL)
7415
2
            xmlXPathPErrMemory(ctxt);
7416
1.29k
  newobj->stringval = cur->stringval;
7417
1.29k
  cur->stringval = tmp;
7418
1.29k
  xmlXPathReleaseObject(ctxt->context, newobj);
7419
1.29k
  nargs--;
7420
1.29k
    }
7421
536
    xmlXPathValuePush(ctxt, cur);
7422
536
}
7423
7424
/**
7425
 * Implement the contains() XPath function
7426
 *    boolean contains(string, string)
7427
 * The contains function returns true if the first argument string
7428
 * contains the second argument string, and otherwise returns false.
7429
 *
7430
 * @param ctxt  the XPath Parser context
7431
 * @param nargs  the number of arguments
7432
 */
7433
void
7434
0
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7435
0
    xmlXPathObjectPtr hay, needle;
7436
7437
0
    CHECK_ARITY(2);
7438
0
    CAST_TO_STRING;
7439
0
    CHECK_TYPE(XPATH_STRING);
7440
0
    needle = xmlXPathValuePop(ctxt);
7441
0
    CAST_TO_STRING;
7442
0
    hay = xmlXPathValuePop(ctxt);
7443
7444
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7445
0
  xmlXPathReleaseObject(ctxt->context, hay);
7446
0
  xmlXPathReleaseObject(ctxt->context, needle);
7447
0
  XP_ERROR(XPATH_INVALID_TYPE);
7448
0
    }
7449
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7450
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7451
0
    else
7452
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7453
0
    xmlXPathReleaseObject(ctxt->context, hay);
7454
0
    xmlXPathReleaseObject(ctxt->context, needle);
7455
0
}
7456
7457
/**
7458
 * Implement the starts-with() XPath function
7459
 *    boolean starts-with(string, string)
7460
 * The starts-with function returns true if the first argument string
7461
 * starts with the second argument string, and otherwise returns false.
7462
 *
7463
 * @param ctxt  the XPath Parser context
7464
 * @param nargs  the number of arguments
7465
 */
7466
void
7467
236
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7468
236
    xmlXPathObjectPtr hay, needle;
7469
236
    int n;
7470
7471
706
    CHECK_ARITY(2);
7472
706
    CAST_TO_STRING;
7473
706
    CHECK_TYPE(XPATH_STRING);
7474
234
    needle = xmlXPathValuePop(ctxt);
7475
234
    CAST_TO_STRING;
7476
234
    hay = xmlXPathValuePop(ctxt);
7477
7478
234
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7479
2
  xmlXPathReleaseObject(ctxt->context, hay);
7480
2
  xmlXPathReleaseObject(ctxt->context, needle);
7481
2
  XP_ERROR(XPATH_INVALID_TYPE);
7482
0
    }
7483
232
    n = xmlStrlen(needle->stringval);
7484
232
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7485
194
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7486
38
    else
7487
38
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7488
232
    xmlXPathReleaseObject(ctxt->context, hay);
7489
232
    xmlXPathReleaseObject(ctxt->context, needle);
7490
232
}
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
11.3k
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7521
11.3k
    xmlXPathObjectPtr str, start, len;
7522
11.3k
    double le=0, in;
7523
11.3k
    int i = 1, j = INT_MAX;
7524
7525
11.3k
    if (nargs < 2) {
7526
6
  CHECK_ARITY(2);
7527
6
    }
7528
11.3k
    if (nargs > 3) {
7529
3
  CHECK_ARITY(3);
7530
3
    }
7531
    /*
7532
     * take care of possible last (position) argument
7533
    */
7534
11.3k
    if (nargs == 3) {
7535
6.82k
  CAST_TO_NUMBER;
7536
6.82k
  CHECK_TYPE(XPATH_NUMBER);
7537
6.82k
  len = xmlXPathValuePop(ctxt);
7538
6.82k
  le = len->floatval;
7539
6.82k
  xmlXPathReleaseObject(ctxt->context, len);
7540
6.82k
    }
7541
7542
11.3k
    CAST_TO_NUMBER;
7543
11.3k
    CHECK_TYPE(XPATH_NUMBER);
7544
11.3k
    start = xmlXPathValuePop(ctxt);
7545
11.3k
    in = start->floatval;
7546
11.3k
    xmlXPathReleaseObject(ctxt->context, start);
7547
11.3k
    CAST_TO_STRING;
7548
11.3k
    CHECK_TYPE(XPATH_STRING);
7549
11.3k
    str = xmlXPathValuePop(ctxt);
7550
7551
11.3k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7552
894
        i = INT_MAX;
7553
10.4k
    } else if (in >= 1.0) {
7554
5.33k
        i = (int)in;
7555
5.33k
        if (in - floor(in) >= 0.5)
7556
258
            i += 1;
7557
5.33k
    }
7558
7559
11.3k
    if (nargs == 3) {
7560
6.82k
        double rin, rle, end;
7561
7562
6.82k
        rin = floor(in);
7563
6.82k
        if (in - rin >= 0.5)
7564
232
            rin += 1.0;
7565
7566
6.82k
        rle = floor(le);
7567
6.82k
        if (le - rle >= 0.5)
7568
571
            rle += 1.0;
7569
7570
6.82k
        end = rin + rle;
7571
6.82k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7572
944
            j = 1;
7573
5.87k
        } else if (end < INT_MAX) {
7574
5.40k
            j = (int)end;
7575
5.40k
        }
7576
6.82k
    }
7577
7578
11.3k
    i -= 1;
7579
11.3k
    j -= 1;
7580
7581
11.3k
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7582
7.95k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7583
7.95k
        if (ret == NULL)
7584
1
            xmlXPathPErrMemory(ctxt);
7585
7.95k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7586
7.95k
  xmlFree(ret);
7587
7.95k
    } else {
7588
3.35k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7589
3.35k
    }
7590
7591
11.3k
    xmlXPathReleaseObject(ctxt->context, str);
7592
11.3k
}
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
558
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7608
558
    xmlXPathObjectPtr str = NULL;
7609
558
    xmlXPathObjectPtr find = NULL;
7610
558
    const xmlChar *point;
7611
558
    xmlChar *result;
7612
7613
1.67k
    CHECK_ARITY(2);
7614
1.67k
    CAST_TO_STRING;
7615
1.67k
    find = xmlXPathValuePop(ctxt);
7616
1.67k
    CAST_TO_STRING;
7617
1.67k
    str = xmlXPathValuePop(ctxt);
7618
1.67k
    if (ctxt->error != 0)
7619
7
        goto error;
7620
7621
550
    point = xmlStrstr(str->stringval, find->stringval);
7622
550
    if (point == NULL) {
7623
221
        result = xmlStrdup(BAD_CAST "");
7624
329
    } else {
7625
329
        result = xmlStrndup(str->stringval, point - str->stringval);
7626
329
    }
7627
550
    if (result == NULL) {
7628
1
        xmlXPathPErrMemory(ctxt);
7629
1
        goto error;
7630
1
    }
7631
549
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7632
7633
557
error:
7634
557
    xmlXPathReleaseObject(ctxt->context, str);
7635
557
    xmlXPathReleaseObject(ctxt->context, find);
7636
557
}
7637
7638
/**
7639
 * Implement the substring-after() XPath function
7640
 *    string substring-after(string, string)
7641
 * The substring-after function returns the substring of the first
7642
 * argument string that follows the first occurrence of the second
7643
 * argument string in the first argument string, or the empty string
7644
 * if the first argument string does not contain the second argument
7645
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7646
 * and substring-after("1999/04/01","19") returns 99/04/01.
7647
 *
7648
 * @param ctxt  the XPath Parser context
7649
 * @param nargs  the number of arguments
7650
 */
7651
void
7652
0
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7653
0
    xmlXPathObjectPtr str = NULL;
7654
0
    xmlXPathObjectPtr find = NULL;
7655
0
    const xmlChar *point;
7656
0
    xmlChar *result;
7657
7658
0
    CHECK_ARITY(2);
7659
0
    CAST_TO_STRING;
7660
0
    find = xmlXPathValuePop(ctxt);
7661
0
    CAST_TO_STRING;
7662
0
    str = xmlXPathValuePop(ctxt);
7663
0
    if (ctxt->error != 0)
7664
0
        goto error;
7665
7666
0
    point = xmlStrstr(str->stringval, find->stringval);
7667
0
    if (point == NULL) {
7668
0
        result = xmlStrdup(BAD_CAST "");
7669
0
    } else {
7670
0
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7671
0
    }
7672
0
    if (result == NULL) {
7673
0
        xmlXPathPErrMemory(ctxt);
7674
0
        goto error;
7675
0
    }
7676
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7677
7678
0
error:
7679
0
    xmlXPathReleaseObject(ctxt->context, str);
7680
0
    xmlXPathReleaseObject(ctxt->context, find);
7681
0
}
7682
7683
/**
7684
 * Implement the normalize-space() XPath function
7685
 *    string normalize-space(string?)
7686
 * The normalize-space function returns the argument string with white
7687
 * space normalized by stripping leading and trailing whitespace
7688
 * and replacing sequences of whitespace characters by a single
7689
 * space. Whitespace characters are the same allowed by the S production
7690
 * in XML. If the argument is omitted, it defaults to the context
7691
 * node converted to a string, in other words the value of the context node.
7692
 *
7693
 * @param ctxt  the XPath Parser context
7694
 * @param nargs  the number of arguments
7695
 */
7696
void
7697
0
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7698
0
    xmlChar *source, *target;
7699
0
    int blank;
7700
7701
0
    if (ctxt == NULL) return;
7702
0
    if (nargs == 0) {
7703
        /* Use current context node */
7704
0
        source = xmlXPathCastNodeToString(ctxt->context->node);
7705
0
        if (source == NULL)
7706
0
            xmlXPathPErrMemory(ctxt);
7707
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7708
0
        nargs = 1;
7709
0
    }
7710
7711
0
    CHECK_ARITY(1);
7712
0
    CAST_TO_STRING;
7713
0
    CHECK_TYPE(XPATH_STRING);
7714
0
    source = ctxt->value->stringval;
7715
0
    if (source == NULL)
7716
0
        return;
7717
0
    target = source;
7718
7719
    /* Skip leading whitespaces */
7720
0
    while (IS_BLANK_CH(*source))
7721
0
        source++;
7722
7723
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7724
0
    blank = 0;
7725
0
    while (*source) {
7726
0
        if (IS_BLANK_CH(*source)) {
7727
0
      blank = 1;
7728
0
        } else {
7729
0
            if (blank) {
7730
0
                *target++ = 0x20;
7731
0
                blank = 0;
7732
0
            }
7733
0
            *target++ = *source;
7734
0
        }
7735
0
        source++;
7736
0
    }
7737
0
    *target = 0;
7738
0
}
7739
7740
/**
7741
 * Implement the translate() XPath function
7742
 *    string translate(string, string, string)
7743
 * The translate function returns the first argument string with
7744
 * occurrences of characters in the second argument string replaced
7745
 * by the character at the corresponding position in the third argument
7746
 * string. For example, translate("bar","abc","ABC") returns the string
7747
 * BAr. If there is a character in the second argument string with no
7748
 * character at a corresponding position in the third argument string
7749
 * (because the second argument string is longer than the third argument
7750
 * string), then occurrences of that character in the first argument
7751
 * string are removed. For example,
7752
 * translate("--aaa--","abc-","ABC") returns "AAA".
7753
 * If a character occurs more than once in second
7754
 * argument string, then the first occurrence determines the replacement
7755
 * character. If the third argument string is longer than the second
7756
 * argument string, then excess characters are ignored.
7757
 *
7758
 * @param ctxt  the XPath Parser context
7759
 * @param nargs  the number of arguments
7760
 */
7761
void
7762
9.16k
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7763
9.16k
    xmlXPathObjectPtr str = NULL;
7764
9.16k
    xmlXPathObjectPtr from = NULL;
7765
9.16k
    xmlXPathObjectPtr to = NULL;
7766
9.16k
    xmlBufPtr target;
7767
9.16k
    int offset, max;
7768
9.16k
    int ch;
7769
9.16k
    const xmlChar *point;
7770
9.16k
    xmlChar *cptr, *content;
7771
7772
27.4k
    CHECK_ARITY(3);
7773
7774
27.4k
    CAST_TO_STRING;
7775
27.4k
    to = xmlXPathValuePop(ctxt);
7776
27.4k
    CAST_TO_STRING;
7777
27.4k
    from = xmlXPathValuePop(ctxt);
7778
27.4k
    CAST_TO_STRING;
7779
27.4k
    str = xmlXPathValuePop(ctxt);
7780
27.4k
    if (ctxt->error != 0)
7781
22
        goto error;
7782
7783
    /*
7784
     * Account for quadratic runtime
7785
     */
7786
9.13k
    if (ctxt->context->opLimit != 0) {
7787
9.13k
        unsigned long f1 = xmlStrlen(from->stringval);
7788
9.13k
        unsigned long f2 = xmlStrlen(str->stringval);
7789
7790
9.13k
        if ((f1 > 0) && (f2 > 0)) {
7791
8.09k
            unsigned long p;
7792
7793
8.09k
            f1 = f1 / 10 + 1;
7794
8.09k
            f2 = f2 / 10 + 1;
7795
8.09k
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7796
8.09k
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7797
6
                goto error;
7798
8.09k
        }
7799
9.13k
    }
7800
7801
9.13k
    target = xmlBufCreate(50);
7802
9.13k
    if (target == NULL) {
7803
13
        xmlXPathPErrMemory(ctxt);
7804
13
        goto error;
7805
13
    }
7806
7807
9.11k
    max = xmlUTF8Strlen(to->stringval);
7808
118k
    for (cptr = str->stringval; (ch=*cptr); ) {
7809
109k
        offset = xmlUTF8Strloc(from->stringval, cptr);
7810
109k
        if (offset >= 0) {
7811
58.7k
            if (offset < max) {
7812
19.7k
                point = xmlUTF8Strpos(to->stringval, offset);
7813
19.7k
                if (point)
7814
19.7k
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7815
19.7k
            }
7816
58.7k
        } else
7817
50.2k
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7818
7819
        /* Step to next character in input */
7820
109k
        cptr++;
7821
109k
        if ( ch & 0x80 ) {
7822
            /* if not simple ascii, verify proper format */
7823
0
            if ( (ch & 0xc0) != 0xc0 ) {
7824
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7825
0
                break;
7826
0
            }
7827
            /* then skip over remaining bytes for this char */
7828
0
            while ( (ch <<= 1) & 0x80 )
7829
0
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7830
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7831
0
                    break;
7832
0
                }
7833
0
            if (ch & 0x80) /* must have had error encountered */
7834
0
                break;
7835
0
        }
7836
109k
    }
7837
7838
9.11k
    content = xmlBufDetach(target);
7839
9.11k
    if (content == NULL)
7840
0
        xmlXPathPErrMemory(ctxt);
7841
9.11k
    else
7842
9.11k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7843
9.11k
    xmlBufFree(target);
7844
9.15k
error:
7845
9.15k
    xmlXPathReleaseObject(ctxt->context, str);
7846
9.15k
    xmlXPathReleaseObject(ctxt->context, from);
7847
9.15k
    xmlXPathReleaseObject(ctxt->context, to);
7848
9.15k
}
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
20.8k
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7864
20.8k
    xmlXPathObjectPtr cur;
7865
7866
62.6k
    CHECK_ARITY(1);
7867
62.6k
    cur = xmlXPathValuePop(ctxt);
7868
62.6k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7869
20.8k
    if (cur->type != XPATH_BOOLEAN) {
7870
14.0k
        int boolval = xmlXPathCastToBoolean(cur);
7871
7872
14.0k
        xmlXPathReleaseObject(ctxt->context, cur);
7873
14.0k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7874
14.0k
    }
7875
20.8k
    xmlXPathValuePush(ctxt, cur);
7876
20.8k
}
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
6
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7889
16
    CHECK_ARITY(1);
7890
16
    CAST_TO_BOOLEAN;
7891
16
    CHECK_TYPE(XPATH_BOOLEAN);
7892
4
    ctxt->value->boolval = ! ctxt->value->boolval;
7893
4
}
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
15
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7904
39
    CHECK_ARITY(0);
7905
39
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7906
39
}
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
31
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7917
91
    CHECK_ARITY(0);
7918
91
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7919
91
}
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
6.95k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7943
6.95k
    xmlXPathObjectPtr val;
7944
6.95k
    xmlNodePtr cur;
7945
6.95k
    xmlChar *theLang = NULL;
7946
6.95k
    const xmlChar *lang;
7947
6.95k
    int ret = 0;
7948
6.95k
    int i;
7949
7950
20.8k
    CHECK_ARITY(1);
7951
20.8k
    CAST_TO_STRING;
7952
20.8k
    CHECK_TYPE(XPATH_STRING);
7953
6.94k
    val = xmlXPathValuePop(ctxt);
7954
6.94k
    lang = val->stringval;
7955
6.94k
    cur = ctxt->context->node;
7956
61.7k
    while (cur != NULL) {
7957
54.8k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7958
54.8k
                                &theLang) < 0)
7959
0
            xmlXPathPErrMemory(ctxt);
7960
54.8k
        if (theLang != NULL)
7961
0
            break;
7962
54.8k
        cur = cur->parent;
7963
54.8k
    }
7964
6.94k
    if ((theLang != NULL) && (lang != NULL)) {
7965
0
        for (i = 0;lang[i] != 0;i++)
7966
0
            if (toupper(lang[i]) != toupper(theLang[i]))
7967
0
                goto not_equal;
7968
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7969
0
            ret = 1;
7970
0
    }
7971
6.94k
not_equal:
7972
6.94k
    if (theLang != NULL)
7973
0
  xmlFree((void *)theLang);
7974
7975
6.94k
    xmlXPathReleaseObject(ctxt->context, val);
7976
6.94k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7977
6.94k
}
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
406k
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7988
406k
    xmlXPathObjectPtr cur;
7989
406k
    double res;
7990
7991
406k
    if (ctxt == NULL) return;
7992
406k
    if (nargs == 0) {
7993
0
  if (ctxt->context->node == NULL) {
7994
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7995
0
  } else {
7996
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7997
0
            if (content == NULL)
7998
0
                xmlXPathPErrMemory(ctxt);
7999
8000
0
      res = xmlXPathStringEvalNumber(content);
8001
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8002
0
      xmlFree(content);
8003
0
  }
8004
0
  return;
8005
0
    }
8006
8007
1.62M
    CHECK_ARITY(1);
8008
1.62M
    cur = xmlXPathValuePop(ctxt);
8009
1.62M
    if (cur->type != XPATH_NUMBER) {
8010
406k
        double floatval;
8011
8012
406k
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8013
406k
        xmlXPathReleaseObject(ctxt->context, cur);
8014
406k
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8015
406k
    }
8016
1.62M
    xmlXPathValuePush(ctxt, cur);
8017
1.62M
}
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
41
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
41
    xmlXPathObjectPtr cur;
8031
41
    int i;
8032
41
    double res = 0.0;
8033
8034
117
    CHECK_ARITY(1);
8035
117
    if ((ctxt->value == NULL) ||
8036
38
  ((ctxt->value->type != XPATH_NODESET) &&
8037
3
   (ctxt->value->type != XPATH_XSLT_TREE)))
8038
35
  XP_ERROR(XPATH_INVALID_TYPE);
8039
35
    cur = xmlXPathValuePop(ctxt);
8040
8041
35
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8042
53
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8043
39
      res += xmlXPathNodeToNumberInternal(ctxt,
8044
39
                                                cur->nodesetval->nodeTab[i]);
8045
39
  }
8046
14
    }
8047
35
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8048
35
    xmlXPathReleaseObject(ctxt->context, cur);
8049
35
}
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
121
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8062
353
    CHECK_ARITY(1);
8063
353
    CAST_TO_NUMBER;
8064
353
    CHECK_TYPE(XPATH_NUMBER);
8065
8066
115
    ctxt->value->floatval = floor(ctxt->value->floatval);
8067
115
}
8068
8069
/**
8070
 * Implement the ceiling() XPath function
8071
 *    number ceiling(number)
8072
 * The ceiling function returns the smallest (closest to negative infinity)
8073
 * number that is not less than the argument and that is an integer.
8074
 *
8075
 * @param ctxt  the XPath Parser context
8076
 * @param nargs  the number of arguments
8077
 */
8078
void
8079
0
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8080
0
    CHECK_ARITY(1);
8081
0
    CAST_TO_NUMBER;
8082
0
    CHECK_TYPE(XPATH_NUMBER);
8083
8084
#ifdef _AIX
8085
    /* Work around buggy ceil() function on AIX */
8086
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8087
#else
8088
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8089
0
#endif
8090
0
}
8091
8092
/**
8093
 * Implement the round() XPath function
8094
 *    number round(number)
8095
 * The round function returns the number that is closest to the
8096
 * argument and that is an integer. If there are two such numbers,
8097
 * then the one that is closest to positive infinity is returned.
8098
 *
8099
 * @param ctxt  the XPath Parser context
8100
 * @param nargs  the number of arguments
8101
 */
8102
void
8103
0
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8104
0
    double f;
8105
8106
0
    CHECK_ARITY(1);
8107
0
    CAST_TO_NUMBER;
8108
0
    CHECK_TYPE(XPATH_NUMBER);
8109
8110
0
    f = ctxt->value->floatval;
8111
8112
0
    if ((f >= -0.5) && (f < 0.5)) {
8113
        /* Handles negative zero. */
8114
0
        ctxt->value->floatval *= 0.0;
8115
0
    }
8116
0
    else {
8117
0
        double rounded = floor(f);
8118
0
        if (f - rounded >= 0.5)
8119
0
            rounded += 1.0;
8120
0
        ctxt->value->floatval = rounded;
8121
0
    }
8122
0
}
8123
8124
/************************************************************************
8125
 *                  *
8126
 *      The Parser          *
8127
 *                  *
8128
 ************************************************************************/
8129
8130
/*
8131
 * a few forward declarations since we use a recursive call based
8132
 * implementation.
8133
 */
8134
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8135
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8136
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8137
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8138
8139
/**
8140
 * Parse an XML non-colonized name.
8141
 *
8142
 * @param ctxt  the XPath Parser context
8143
 * @returns the nc name or NULL
8144
 */
8145
8146
xmlChar *
8147
98.1k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8148
98.1k
    const xmlChar *end;
8149
98.1k
    xmlChar *ret;
8150
8151
98.1k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8152
8153
98.1k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8154
98.1k
    if (end == NULL) {
8155
3
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8156
0
    }
8157
98.1k
    if (end == ctxt->cur)
8158
4.50k
        return(NULL);
8159
8160
93.6k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8161
93.6k
    if (ret == NULL)
8162
84
        xmlXPathPErrMemory(ctxt);
8163
93.6k
    ctxt->cur = end;
8164
93.6k
    return(ret);
8165
98.1k
}
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
10.8k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8179
10.8k
    xmlChar *ret = NULL;
8180
8181
10.8k
    *prefix = NULL;
8182
10.8k
    ret = xmlXPathParseNCName(ctxt);
8183
10.8k
    if (ret && CUR == ':') {
8184
1.05k
        *prefix = ret;
8185
1.05k
  NEXT;
8186
1.05k
  ret = xmlXPathParseNCName(ctxt);
8187
1.05k
    }
8188
10.8k
    return(ret);
8189
10.8k
}
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
22.2k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8200
22.2k
    const xmlChar *end;
8201
22.2k
    xmlChar *ret;
8202
8203
22.2k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8204
8205
22.2k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8206
22.2k
    if (end == NULL) {
8207
3
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8208
0
    }
8209
22.2k
    if (end == ctxt->cur)
8210
3.00k
        return(NULL);
8211
8212
19.2k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8213
19.2k
    if (ret == NULL)
8214
50
        xmlXPathPErrMemory(ctxt);
8215
19.2k
    ctxt->cur = end;
8216
19.2k
    return(ret);
8217
22.2k
}
8218
8219
56.9k
#define MAX_FRAC 20
8220
8221
/**
8222
 *  [30a]  Float  ::= Number ('e' Digits?)?
8223
 *
8224
 *  [30]   Number ::=   Digits ('.' Digits?)?
8225
 *                    | '.' Digits
8226
 *  [31]   Digits ::=   [0-9]+
8227
 *
8228
 * Compile a Number in the string
8229
 * In complement of the Number expression, this function also handles
8230
 * negative values : '-' Number.
8231
 *
8232
 * @param str  A string to scan
8233
 * @returns the double value.
8234
 */
8235
double
8236
712k
xmlXPathStringEvalNumber(const xmlChar *str) {
8237
712k
    const xmlChar *cur = str;
8238
712k
    double ret;
8239
712k
    int ok = 0;
8240
712k
    int isneg = 0;
8241
712k
    int exponent = 0;
8242
712k
    int is_exponent_negative = 0;
8243
712k
#ifdef __GNUC__
8244
712k
    unsigned long tmp = 0;
8245
712k
    double temp;
8246
712k
#endif
8247
712k
    if (cur == NULL) return(0);
8248
712k
    while (IS_BLANK_CH(*cur)) cur++;
8249
712k
    if (*cur == '-') {
8250
71.2k
  isneg = 1;
8251
71.2k
  cur++;
8252
71.2k
    }
8253
712k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8254
622k
        return(xmlXPathNAN);
8255
622k
    }
8256
8257
90.4k
#ifdef __GNUC__
8258
    /*
8259
     * tmp/temp is a workaround against a gcc compiler bug
8260
     * http://veillard.com/gcc.bug
8261
     */
8262
90.4k
    ret = 0;
8263
135k
    while ((*cur >= '0') && (*cur <= '9')) {
8264
45.1k
  ret = ret * 10;
8265
45.1k
  tmp = (*cur - '0');
8266
45.1k
  ok = 1;
8267
45.1k
  cur++;
8268
45.1k
  temp = (double) tmp;
8269
45.1k
  ret = ret + temp;
8270
45.1k
    }
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
90.4k
    if (*cur == '.') {
8281
79.2k
  int v, frac = 0, max;
8282
79.2k
  double fraction = 0;
8283
8284
79.2k
        cur++;
8285
79.2k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8286
33.5k
      return(xmlXPathNAN);
8287
33.5k
  }
8288
73.0k
        while (*cur == '0') {
8289
27.3k
      frac = frac + 1;
8290
27.3k
      cur++;
8291
27.3k
        }
8292
45.7k
        max = frac + MAX_FRAC;
8293
134k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8294
88.9k
      v = (*cur - '0');
8295
88.9k
      fraction = fraction * 10 + v;
8296
88.9k
      frac = frac + 1;
8297
88.9k
      cur++;
8298
88.9k
  }
8299
45.7k
  fraction /= pow(10.0, frac);
8300
45.7k
  ret = ret + fraction;
8301
47.8k
  while ((*cur >= '0') && (*cur <= '9'))
8302
2.10k
      cur++;
8303
45.7k
    }
8304
56.8k
    if ((*cur == 'e') || (*cur == 'E')) {
8305
16.8k
      cur++;
8306
16.8k
      if (*cur == '-') {
8307
6.68k
  is_exponent_negative = 1;
8308
6.68k
  cur++;
8309
10.2k
      } else if (*cur == '+') {
8310
5.91k
        cur++;
8311
5.91k
      }
8312
64.1k
      while ((*cur >= '0') && (*cur <= '9')) {
8313
47.2k
        if (exponent < 1000000)
8314
46.2k
    exponent = exponent * 10 + (*cur - '0');
8315
47.2k
  cur++;
8316
47.2k
      }
8317
16.8k
    }
8318
56.8k
    while (IS_BLANK_CH(*cur)) cur++;
8319
56.8k
    if (*cur != 0) return(xmlXPathNAN);
8320
34.7k
    if (isneg) ret = -ret;
8321
34.7k
    if (is_exponent_negative) exponent = -exponent;
8322
34.7k
    ret *= pow(10.0, (double)exponent);
8323
34.7k
    return(ret);
8324
56.8k
}
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
73.7k
{
8338
73.7k
    double ret = 0.0;
8339
73.7k
    int ok = 0;
8340
73.7k
    int exponent = 0;
8341
73.7k
    int is_exponent_negative = 0;
8342
73.7k
    xmlXPathObjectPtr num;
8343
73.7k
#ifdef __GNUC__
8344
73.7k
    unsigned long tmp = 0;
8345
73.7k
    double temp;
8346
73.7k
#endif
8347
8348
73.7k
    CHECK_ERROR;
8349
73.7k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8350
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8351
0
    }
8352
73.7k
#ifdef __GNUC__
8353
    /*
8354
     * tmp/temp is a workaround against a gcc compiler bug
8355
     * http://veillard.com/gcc.bug
8356
     */
8357
73.7k
    ret = 0;
8358
283k
    while ((CUR >= '0') && (CUR <= '9')) {
8359
209k
  ret = ret * 10;
8360
209k
  tmp = (CUR - '0');
8361
209k
        ok = 1;
8362
209k
        NEXT;
8363
209k
  temp = (double) tmp;
8364
209k
  ret = ret + temp;
8365
209k
    }
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
73.7k
    if (CUR == '.') {
8375
11.2k
  int v, frac = 0, max;
8376
11.2k
  double fraction = 0;
8377
8378
11.2k
        NEXT;
8379
11.2k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8380
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8381
0
        }
8382
16.2k
        while (CUR == '0') {
8383
4.94k
            frac = frac + 1;
8384
4.94k
            NEXT;
8385
4.94k
        }
8386
11.2k
        max = frac + MAX_FRAC;
8387
36.7k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8388
25.5k
      v = (CUR - '0');
8389
25.5k
      fraction = fraction * 10 + v;
8390
25.5k
      frac = frac + 1;
8391
25.5k
            NEXT;
8392
25.5k
        }
8393
11.2k
        fraction /= pow(10.0, frac);
8394
11.2k
        ret = ret + fraction;
8395
12.0k
        while ((CUR >= '0') && (CUR <= '9'))
8396
814
            NEXT;
8397
11.2k
    }
8398
73.7k
    if ((CUR == 'e') || (CUR == 'E')) {
8399
11.9k
        NEXT;
8400
11.9k
        if (CUR == '-') {
8401
578
            is_exponent_negative = 1;
8402
578
            NEXT;
8403
11.3k
        } else if (CUR == '+') {
8404
742
      NEXT;
8405
742
  }
8406
93.9k
        while ((CUR >= '0') && (CUR <= '9')) {
8407
81.9k
            if (exponent < 1000000)
8408
63.7k
                exponent = exponent * 10 + (CUR - '0');
8409
81.9k
            NEXT;
8410
81.9k
        }
8411
11.9k
        if (is_exponent_negative)
8412
578
            exponent = -exponent;
8413
11.9k
        ret *= pow(10.0, (double) exponent);
8414
11.9k
    }
8415
73.7k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8416
73.7k
    if (num == NULL) {
8417
44
  ctxt->error = XPATH_MEMORY_ERROR;
8418
73.6k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8419
73.6k
                              NULL) == -1) {
8420
16
        xmlXPathReleaseObject(ctxt->context, num);
8421
16
    }
8422
73.7k
}
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
1.73k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8435
1.73k
    const xmlChar *q;
8436
1.73k
    xmlChar *ret = NULL;
8437
1.73k
    int quote;
8438
8439
1.73k
    if (CUR == '"') {
8440
84
        quote = '"';
8441
1.64k
    } else if (CUR == '\'') {
8442
1.64k
        quote = '\'';
8443
1.64k
    } else {
8444
7
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8445
0
    }
8446
8447
1.72k
    NEXT;
8448
1.72k
    q = CUR_PTR;
8449
19.2k
    while (CUR != quote) {
8450
17.6k
        int ch;
8451
17.6k
        int len = 4;
8452
8453
17.6k
        if (CUR == 0)
8454
17.5k
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8455
17.5k
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8456
17.5k
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8457
17.5k
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8458
17.5k
        CUR_PTR += len;
8459
17.5k
    }
8460
1.59k
    ret = xmlStrndup(q, CUR_PTR - q);
8461
1.59k
    if (ret == NULL)
8462
4
        xmlXPathPErrMemory(ctxt);
8463
1.59k
    NEXT;
8464
1.59k
    return(ret);
8465
1.72k
}
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
1.63k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8479
1.63k
    xmlChar *ret = NULL;
8480
1.63k
    xmlXPathObjectPtr lit;
8481
8482
1.63k
    ret = xmlXPathParseLiteral(ctxt);
8483
1.63k
    if (ret == NULL)
8484
133
        return;
8485
1.49k
    lit = xmlXPathCacheNewString(ctxt, ret);
8486
1.49k
    if (lit == NULL) {
8487
7
        ctxt->error = XPATH_MEMORY_ERROR;
8488
1.49k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8489
1.49k
                              NULL) == -1) {
8490
4
        xmlXPathReleaseObject(ctxt->context, lit);
8491
4
    }
8492
1.49k
    xmlFree(ret);
8493
1.49k
}
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
1.38k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8512
1.38k
    xmlChar *name;
8513
1.38k
    xmlChar *prefix;
8514
8515
1.38k
    SKIP_BLANKS;
8516
1.38k
    if (CUR != '$') {
8517
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8518
0
    }
8519
1.38k
    NEXT;
8520
1.38k
    name = xmlXPathParseQName(ctxt, &prefix);
8521
1.38k
    if (name == NULL) {
8522
38
        xmlFree(prefix);
8523
38
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8524
0
    }
8525
1.34k
    ctxt->comp->last = -1;
8526
1.34k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8527
3
        xmlFree(prefix);
8528
3
        xmlFree(name);
8529
3
    }
8530
1.34k
    SKIP_BLANKS;
8531
1.34k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8532
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8533
0
    }
8534
1.34k
}
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
9.76k
xmlXPathIsNodeType(const xmlChar *name) {
8549
9.76k
    if (name == NULL)
8550
0
  return(0);
8551
8552
9.76k
    if (xmlStrEqual(name, BAD_CAST "node"))
8553
34
  return(1);
8554
9.72k
    if (xmlStrEqual(name, BAD_CAST "text"))
8555
49
  return(1);
8556
9.67k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8557
20
  return(1);
8558
9.65k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8559
148
  return(1);
8560
9.50k
    return(0);
8561
9.65k
}
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
9.50k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8574
9.50k
    xmlChar *name;
8575
9.50k
    xmlChar *prefix;
8576
9.50k
    int nbargs = 0;
8577
9.50k
    int sort = 1;
8578
8579
9.50k
    name = xmlXPathParseQName(ctxt, &prefix);
8580
9.50k
    if (name == NULL) {
8581
21
  xmlFree(prefix);
8582
21
  XP_ERROR(XPATH_EXPR_ERROR);
8583
0
    }
8584
9.48k
    SKIP_BLANKS;
8585
8586
9.48k
    if (CUR != '(') {
8587
3
  xmlFree(name);
8588
3
  xmlFree(prefix);
8589
3
  XP_ERROR(XPATH_EXPR_ERROR);
8590
0
    }
8591
9.48k
    NEXT;
8592
9.48k
    SKIP_BLANKS;
8593
8594
    /*
8595
    * Optimization for count(): we don't need the node-set to be sorted.
8596
    */
8597
9.48k
    if ((prefix == NULL) && (name[0] == 'c') &&
8598
1.11k
  xmlStrEqual(name, BAD_CAST "count"))
8599
57
    {
8600
57
  sort = 0;
8601
57
    }
8602
9.48k
    ctxt->comp->last = -1;
8603
9.48k
    if (CUR != ')') {
8604
12.2k
  while (CUR != 0) {
8605
12.2k
      int op1 = ctxt->comp->last;
8606
12.2k
      ctxt->comp->last = -1;
8607
12.2k
      xmlXPathCompileExpr(ctxt, sort);
8608
12.2k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8609
742
    xmlFree(name);
8610
742
    xmlFree(prefix);
8611
742
    return;
8612
742
      }
8613
11.4k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8614
11.4k
      nbargs++;
8615
11.4k
      if (CUR == ')') break;
8616
4.41k
      if (CUR != ',') {
8617
104
    xmlFree(name);
8618
104
    xmlFree(prefix);
8619
104
    XP_ERROR(XPATH_EXPR_ERROR);
8620
0
      }
8621
4.30k
      NEXT;
8622
4.30k
      SKIP_BLANKS;
8623
4.30k
  }
8624
7.93k
    }
8625
8.63k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8626
2
        xmlFree(prefix);
8627
2
        xmlFree(name);
8628
2
    }
8629
8.63k
    NEXT;
8630
8.63k
    SKIP_BLANKS;
8631
8.63k
}
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
90.0k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8646
90.0k
    SKIP_BLANKS;
8647
90.0k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8648
88.6k
    else if (CUR == '(') {
8649
3.78k
  NEXT;
8650
3.78k
  SKIP_BLANKS;
8651
3.78k
  xmlXPathCompileExpr(ctxt, 1);
8652
3.78k
  CHECK_ERROR;
8653
3.33k
  if (CUR != ')') {
8654
68
      XP_ERROR(XPATH_EXPR_ERROR);
8655
0
  }
8656
3.26k
  NEXT;
8657
3.26k
  SKIP_BLANKS;
8658
84.8k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8659
73.7k
  xmlXPathCompNumber(ctxt);
8660
73.7k
    } else if ((CUR == '\'') || (CUR == '"')) {
8661
1.63k
  xmlXPathCompLiteral(ctxt);
8662
9.50k
    } else {
8663
9.50k
  xmlXPathCompFunctionCall(ctxt);
8664
9.50k
    }
8665
89.5k
    SKIP_BLANKS;
8666
89.5k
}
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
90.0k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8684
90.0k
    xmlXPathCompPrimaryExpr(ctxt);
8685
90.0k
    CHECK_ERROR;
8686
88.3k
    SKIP_BLANKS;
8687
8688
104k
    while (CUR == '[') {
8689
15.9k
  xmlXPathCompPredicate(ctxt, 1);
8690
15.9k
  SKIP_BLANKS;
8691
15.9k
    }
8692
8693
8694
88.3k
}
8695
8696
/**
8697
 * Trickery: parse an XML name but without consuming the input flow
8698
 * Needed to avoid insanity in the parser state.
8699
 *
8700
 * @param ctxt  the XPath Parser context
8701
 * @returns the Name parsed or NULL
8702
 */
8703
8704
static xmlChar *
8705
68.0k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8706
68.0k
    const xmlChar *end;
8707
68.0k
    xmlChar *ret;
8708
8709
68.0k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8710
68.0k
    if (end == NULL) {
8711
3
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8712
0
    }
8713
68.0k
    if (end == ctxt->cur)
8714
2.89k
        return(NULL);
8715
8716
65.1k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8717
65.1k
    if (ret == NULL)
8718
60
        xmlXPathPErrMemory(ctxt);
8719
65.1k
    return(ret);
8720
68.0k
}
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
355k
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8735
355k
    int lc = 1;           /* Should we branch to LocationPath ?         */
8736
355k
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8737
8738
355k
    SKIP_BLANKS;
8739
355k
    if ((CUR == '$') || (CUR == '(') ||
8740
350k
  (IS_ASCII_DIGIT(CUR)) ||
8741
278k
        (CUR == '\'') || (CUR == '"') ||
8742
277k
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8743
80.5k
  lc = 0;
8744
274k
    } else if (CUR == '*') {
8745
  /* relative or absolute location path */
8746
162k
  lc = 1;
8747
162k
    } else if (CUR == '/') {
8748
  /* relative or absolute location path */
8749
34.7k
  lc = 1;
8750
77.7k
    } else if (CUR == '@') {
8751
  /* relative abbreviated attribute location path */
8752
527
  lc = 1;
8753
77.2k
    } else if (CUR == '.') {
8754
  /* relative abbreviated attribute location path */
8755
9.19k
  lc = 1;
8756
68.0k
    } else {
8757
  /*
8758
   * Problem is finding if we have a name here whether it's:
8759
   *   - a nodetype
8760
   *   - a function call in which case it's followed by '('
8761
   *   - an axis in which case it's followed by ':'
8762
   *   - a element name
8763
   * We do an a priori analysis here rather than having to
8764
   * maintain parsed token content through the recursive function
8765
   * calls. This looks uglier but makes the code easier to
8766
   * read/write/debug.
8767
   */
8768
68.0k
  SKIP_BLANKS;
8769
68.0k
  name = xmlXPathScanName(ctxt);
8770
68.0k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8771
1.52k
      lc = 1;
8772
1.52k
      xmlFree(name);
8773
66.5k
  } else if (name != NULL) {
8774
63.5k
      int len =xmlStrlen(name);
8775
8776
8777
423k
      while (NXT(len) != 0) {
8778
422k
    if (NXT(len) == '/') {
8779
        /* element name */
8780
3.51k
        lc = 1;
8781
3.51k
        break;
8782
419k
    } else if (IS_BLANK_CH(NXT(len))) {
8783
        /* ignore blanks */
8784
360k
        ;
8785
360k
    } else if (NXT(len) == ':') {
8786
657
        lc = 1;
8787
657
        break;
8788
58.4k
    } else if ((NXT(len) == '(')) {
8789
        /* Node Type or Function */
8790
9.76k
        if (xmlXPathIsNodeType(name)) {
8791
251
      lc = 1;
8792
9.50k
        } else {
8793
9.50k
      lc = 0;
8794
9.50k
        }
8795
9.76k
                    break;
8796
48.6k
    } else if ((NXT(len) == '[')) {
8797
        /* element name */
8798
958
        lc = 1;
8799
958
        break;
8800
47.6k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8801
38.9k
         (NXT(len) == '=')) {
8802
16.9k
        lc = 1;
8803
16.9k
        break;
8804
30.7k
    } else {
8805
30.7k
        lc = 1;
8806
30.7k
        break;
8807
30.7k
    }
8808
360k
    len++;
8809
360k
      }
8810
63.5k
      if (NXT(len) == 0) {
8811
    /* element name */
8812
978
    lc = 1;
8813
978
      }
8814
63.5k
      xmlFree(name);
8815
63.5k
  } else {
8816
      /* make sure all cases are covered explicitly */
8817
2.96k
      XP_ERROR(XPATH_EXPR_ERROR);
8818
0
  }
8819
68.0k
    }
8820
8821
352k
    if (lc) {
8822
262k
  if (CUR == '/') {
8823
34.7k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8824
227k
  } else {
8825
227k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8826
227k
  }
8827
262k
  xmlXPathCompLocationPath(ctxt);
8828
262k
    } else {
8829
90.0k
  xmlXPathCompFilterExpr(ctxt);
8830
90.0k
  CHECK_ERROR;
8831
87.8k
  if ((CUR == '/') && (NXT(1) == '/')) {
8832
770
      SKIP(2);
8833
770
      SKIP_BLANKS;
8834
8835
770
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8836
770
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8837
8838
770
      xmlXPathCompRelativeLocationPath(ctxt);
8839
87.0k
  } else if (CUR == '/') {
8840
1.79k
      xmlXPathCompRelativeLocationPath(ctxt);
8841
1.79k
  }
8842
87.8k
    }
8843
350k
    SKIP_BLANKS;
8844
350k
}
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
345k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8857
345k
    xmlXPathCompPathExpr(ctxt);
8858
345k
    CHECK_ERROR;
8859
339k
    SKIP_BLANKS;
8860
349k
    while (CUR == '|') {
8861
10.1k
  int op1 = ctxt->comp->last;
8862
10.1k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8863
8864
10.1k
  NEXT;
8865
10.1k
  SKIP_BLANKS;
8866
10.1k
  xmlXPathCompPathExpr(ctxt);
8867
8868
10.1k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8869
8870
10.1k
  SKIP_BLANKS;
8871
10.1k
    }
8872
339k
}
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
345k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8885
345k
    int minus = 0;
8886
345k
    int found = 0;
8887
8888
345k
    SKIP_BLANKS;
8889
403k
    while (CUR == '-') {
8890
57.8k
        minus = 1 - minus;
8891
57.8k
  found = 1;
8892
57.8k
  NEXT;
8893
57.8k
  SKIP_BLANKS;
8894
57.8k
    }
8895
8896
345k
    xmlXPathCompUnionExpr(ctxt);
8897
345k
    CHECK_ERROR;
8898
339k
    if (found) {
8899
31.8k
  if (minus)
8900
22.5k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8901
9.29k
  else
8902
9.29k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8903
31.8k
    }
8904
339k
}
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
176k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8920
176k
    xmlXPathCompUnaryExpr(ctxt);
8921
176k
    CHECK_ERROR;
8922
171k
    SKIP_BLANKS;
8923
339k
    while ((CUR == '*') ||
8924
172k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8925
171k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8926
168k
  int op = -1;
8927
168k
  int op1 = ctxt->comp->last;
8928
8929
168k
        if (CUR == '*') {
8930
167k
      op = 0;
8931
167k
      NEXT;
8932
167k
  } else if (CUR == 'd') {
8933
602
      op = 1;
8934
602
      SKIP(3);
8935
602
  } else if (CUR == 'm') {
8936
393
      op = 2;
8937
393
      SKIP(3);
8938
393
  }
8939
168k
  SKIP_BLANKS;
8940
168k
        xmlXPathCompUnaryExpr(ctxt);
8941
168k
  CHECK_ERROR;
8942
167k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8943
167k
  SKIP_BLANKS;
8944
167k
    }
8945
171k
}
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
144k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8959
8960
144k
    xmlXPathCompMultiplicativeExpr(ctxt);
8961
144k
    CHECK_ERROR;
8962
139k
    SKIP_BLANKS;
8963
171k
    while ((CUR == '+') || (CUR == '-')) {
8964
32.7k
  int plus;
8965
32.7k
  int op1 = ctxt->comp->last;
8966
8967
32.7k
        if (CUR == '+') plus = 1;
8968
27.4k
  else plus = 0;
8969
32.7k
  NEXT;
8970
32.7k
  SKIP_BLANKS;
8971
32.7k
        xmlXPathCompMultiplicativeExpr(ctxt);
8972
32.7k
  CHECK_ERROR;
8973
31.9k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8974
31.9k
  SKIP_BLANKS;
8975
31.9k
    }
8976
139k
}
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
112k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8997
112k
    xmlXPathCompAdditiveExpr(ctxt);
8998
112k
    CHECK_ERROR;
8999
108k
    SKIP_BLANKS;
9000
138k
    while ((CUR == '<') || (CUR == '>')) {
9001
31.2k
  int inf, strict;
9002
31.2k
  int op1 = ctxt->comp->last;
9003
9004
31.2k
        if (CUR == '<') inf = 1;
9005
26.1k
  else inf = 0;
9006
31.2k
  if (NXT(1) == '=') strict = 0;
9007
21.1k
  else strict = 1;
9008
31.2k
  NEXT;
9009
31.2k
  if (!strict) NEXT;
9010
31.2k
  SKIP_BLANKS;
9011
31.2k
        xmlXPathCompAdditiveExpr(ctxt);
9012
31.2k
  CHECK_ERROR;
9013
30.1k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9014
30.1k
  SKIP_BLANKS;
9015
30.1k
    }
9016
108k
}
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
63.7k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9034
63.7k
    xmlXPathCompRelationalExpr(ctxt);
9035
63.7k
    CHECK_ERROR;
9036
58.6k
    SKIP_BLANKS;
9037
107k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9038
49.1k
  int eq;
9039
49.1k
  int op1 = ctxt->comp->last;
9040
9041
49.1k
        if (CUR == '=') eq = 1;
9042
2.21k
  else eq = 0;
9043
49.1k
  NEXT;
9044
49.1k
  if (!eq) NEXT;
9045
49.1k
  SKIP_BLANKS;
9046
49.1k
        xmlXPathCompRelationalExpr(ctxt);
9047
49.1k
  CHECK_ERROR;
9048
48.3k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9049
48.3k
  SKIP_BLANKS;
9050
48.3k
    }
9051
58.6k
}
9052
9053
/**
9054
 *  [22]   AndExpr ::=   EqualityExpr
9055
 *                 | AndExpr 'and' EqualityExpr
9056
 *
9057
 * Compile an AND expression.
9058
 *
9059
 * @param ctxt  the XPath Parser context
9060
 */
9061
static void
9062
62.7k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9063
62.7k
    xmlXPathCompEqualityExpr(ctxt);
9064
62.7k
    CHECK_ERROR;
9065
56.9k
    SKIP_BLANKS;
9066
57.8k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9067
1.00k
  int op1 = ctxt->comp->last;
9068
1.00k
        SKIP(3);
9069
1.00k
  SKIP_BLANKS;
9070
1.00k
        xmlXPathCompEqualityExpr(ctxt);
9071
1.00k
  CHECK_ERROR;
9072
953
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9073
953
  SKIP_BLANKS;
9074
953
    }
9075
56.9k
}
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
57.1k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9089
57.1k
    xmlXPathContextPtr xpctxt = ctxt->context;
9090
9091
57.1k
    if (xpctxt != NULL) {
9092
57.1k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9093
56.8k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9094
        /*
9095
         * Parsing a single '(' pushes about 10 functions on the call stack
9096
         * before recursing!
9097
         */
9098
56.8k
        xpctxt->depth += 10;
9099
56.8k
    }
9100
9101
56.8k
    xmlXPathCompAndExpr(ctxt);
9102
56.8k
    CHECK_ERROR;
9103
51.1k
    SKIP_BLANKS;
9104
56.8k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9105
5.83k
  int op1 = ctxt->comp->last;
9106
5.83k
        SKIP(2);
9107
5.83k
  SKIP_BLANKS;
9108
5.83k
        xmlXPathCompAndExpr(ctxt);
9109
5.83k
  CHECK_ERROR;
9110
5.70k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9111
5.70k
  SKIP_BLANKS;
9112
5.70k
    }
9113
51.0k
    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
30.0k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9121
30.0k
    }
9122
9123
51.0k
    if (xpctxt != NULL)
9124
51.0k
        xpctxt->depth -= 10;
9125
51.0k
}
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
25.1k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9138
25.1k
    int op1 = ctxt->comp->last;
9139
9140
25.1k
    SKIP_BLANKS;
9141
25.1k
    if (CUR != '[') {
9142
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9143
0
    }
9144
25.1k
    NEXT;
9145
25.1k
    SKIP_BLANKS;
9146
9147
25.1k
    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
25.1k
    if (! filter)
9158
9.27k
  xmlXPathCompileExpr(ctxt, 0);
9159
15.9k
    else
9160
15.9k
  xmlXPathCompileExpr(ctxt, 1);
9161
25.1k
    CHECK_ERROR;
9162
9163
22.1k
    if (CUR != ']') {
9164
235
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9165
0
    }
9166
9167
21.9k
    if (filter)
9168
14.7k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9169
7.13k
    else
9170
7.13k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9171
9172
21.9k
    NEXT;
9173
21.9k
    SKIP_BLANKS;
9174
21.9k
}
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
249k
         xmlChar *name) {
9202
249k
    int blanks;
9203
9204
249k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9205
0
  return(NULL);
9206
0
    }
9207
249k
    *type = (xmlXPathTypeVal) 0;
9208
249k
    *test = (xmlXPathTestVal) 0;
9209
249k
    *prefix = NULL;
9210
249k
    SKIP_BLANKS;
9211
9212
249k
    if ((name == NULL) && (CUR == '*')) {
9213
  /*
9214
   * All elements
9215
   */
9216
173k
  NEXT;
9217
173k
  *test = NODE_TEST_ALL;
9218
173k
  return(NULL);
9219
173k
    }
9220
9221
76.0k
    if (name == NULL)
9222
5.85k
  name = xmlXPathParseNCName(ctxt);
9223
76.0k
    if (name == NULL) {
9224
368
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9225
0
    }
9226
9227
75.7k
    blanks = IS_BLANK_CH(CUR);
9228
75.7k
    SKIP_BLANKS;
9229
75.7k
    if (CUR == '(') {
9230
805
  NEXT;
9231
  /*
9232
   * NodeType or PI search
9233
   */
9234
805
  if (xmlStrEqual(name, BAD_CAST "comment"))
9235
25
      *type = NODE_TYPE_COMMENT;
9236
780
  else if (xmlStrEqual(name, BAD_CAST "node"))
9237
75
      *type = NODE_TYPE_NODE;
9238
705
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9239
148
      *type = NODE_TYPE_PI;
9240
557
  else if (xmlStrEqual(name, BAD_CAST "text"))
9241
511
      *type = NODE_TYPE_TEXT;
9242
46
  else {
9243
46
      if (name != NULL)
9244
46
    xmlFree(name);
9245
46
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9246
0
  }
9247
9248
759
  *test = NODE_TEST_TYPE;
9249
9250
759
  SKIP_BLANKS;
9251
759
  if (*type == NODE_TYPE_PI) {
9252
      /*
9253
       * Specific case: search a PI by name.
9254
       */
9255
148
      if (name != NULL)
9256
148
    xmlFree(name);
9257
148
      name = NULL;
9258
148
      if (CUR != ')') {
9259
101
    name = xmlXPathParseLiteral(ctxt);
9260
101
    *test = NODE_TEST_PI;
9261
101
    SKIP_BLANKS;
9262
101
      }
9263
148
  }
9264
759
  if (CUR != ')') {
9265
52
      if (name != NULL)
9266
41
    xmlFree(name);
9267
52
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9268
0
  }
9269
707
  NEXT;
9270
707
  return(name);
9271
759
    }
9272
74.9k
    *test = NODE_TEST_NAME;
9273
74.9k
    if ((!blanks) && (CUR == ':')) {
9274
2.83k
  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
2.83k
  *prefix = name;
9284
9285
2.83k
  if (CUR == '*') {
9286
      /*
9287
       * All elements
9288
       */
9289
541
      NEXT;
9290
541
      *test = NODE_TEST_ALL;
9291
541
      return(NULL);
9292
541
  }
9293
9294
2.29k
  name = xmlXPathParseNCName(ctxt);
9295
2.29k
  if (name == NULL) {
9296
52
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9297
0
  }
9298
2.29k
    }
9299
74.3k
    return(name);
9300
74.9k
}
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
73.4k
xmlXPathIsAxisName(const xmlChar *name) {
9322
73.4k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9323
73.4k
    switch (name[0]) {
9324
8.64k
  case 'a':
9325
8.64k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9326
1.11k
    ret = AXIS_ANCESTOR;
9327
8.64k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9328
696
    ret = AXIS_ANCESTOR_OR_SELF;
9329
8.64k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9330
69
    ret = AXIS_ATTRIBUTE;
9331
8.64k
      break;
9332
2.14k
  case 'c':
9333
2.14k
      if (xmlStrEqual(name, BAD_CAST "child"))
9334
12
    ret = AXIS_CHILD;
9335
2.14k
      break;
9336
1.45k
  case 'd':
9337
1.45k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9338
34
    ret = AXIS_DESCENDANT;
9339
1.45k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9340
10
    ret = AXIS_DESCENDANT_OR_SELF;
9341
1.45k
      break;
9342
2.05k
  case 'f':
9343
2.05k
      if (xmlStrEqual(name, BAD_CAST "following"))
9344
273
    ret = AXIS_FOLLOWING;
9345
2.05k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9346
68
    ret = AXIS_FOLLOWING_SIBLING;
9347
2.05k
      break;
9348
6.28k
  case 'n':
9349
6.28k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9350
476
    ret = AXIS_NAMESPACE;
9351
6.28k
      break;
9352
2.04k
  case 'p':
9353
2.04k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9354
292
    ret = AXIS_PARENT;
9355
2.04k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9356
64
    ret = AXIS_PRECEDING;
9357
2.04k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9358
7
    ret = AXIS_PRECEDING_SIBLING;
9359
2.04k
      break;
9360
2.59k
  case 's':
9361
2.59k
      if (xmlStrEqual(name, BAD_CAST "self"))
9362
959
    ret = AXIS_SELF;
9363
2.59k
      break;
9364
73.4k
    }
9365
73.4k
    return(ret);
9366
73.4k
}
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
277k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9391
277k
    SKIP_BLANKS;
9392
277k
    if ((CUR == '.') && (NXT(1) == '.')) {
9393
7.11k
  SKIP(2);
9394
7.11k
  SKIP_BLANKS;
9395
7.11k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9396
7.11k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9397
270k
    } else if (CUR == '.') {
9398
20.3k
  NEXT;
9399
20.3k
  SKIP_BLANKS;
9400
250k
    } else {
9401
250k
  xmlChar *name = NULL;
9402
250k
  xmlChar *prefix = NULL;
9403
250k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9404
250k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9405
250k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9406
250k
  int op1;
9407
9408
250k
  if (CUR == '*') {
9409
172k
      axis = AXIS_CHILD;
9410
172k
  } else {
9411
77.6k
      if (name == NULL)
9412
77.6k
    name = xmlXPathParseNCName(ctxt);
9413
77.6k
      if (name != NULL) {
9414
73.4k
    axis = xmlXPathIsAxisName(name);
9415
73.4k
    if (axis != 0) {
9416
4.07k
        SKIP_BLANKS;
9417
4.07k
        if ((CUR == ':') && (NXT(1) == ':')) {
9418
2.82k
      SKIP(2);
9419
2.82k
      xmlFree(name);
9420
2.82k
      name = NULL;
9421
2.82k
        } else {
9422
      /* an element name can conflict with an axis one :-\ */
9423
1.25k
      axis = AXIS_CHILD;
9424
1.25k
        }
9425
69.4k
    } else {
9426
69.4k
        axis = AXIS_CHILD;
9427
69.4k
    }
9428
73.4k
      } else if (CUR == '@') {
9429
3.31k
    NEXT;
9430
3.31k
    axis = AXIS_ATTRIBUTE;
9431
3.31k
      } else {
9432
786
    axis = AXIS_CHILD;
9433
786
      }
9434
77.6k
  }
9435
9436
250k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9437
894
            xmlFree(name);
9438
894
            return;
9439
894
        }
9440
9441
249k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9442
249k
  if (test == 0)
9443
414
      return;
9444
9445
248k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9446
2.83k
      (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
248k
  op1 = ctxt->comp->last;
9454
248k
  ctxt->comp->last = -1;
9455
9456
248k
  SKIP_BLANKS;
9457
258k
  while (CUR == '[') {
9458
9.27k
      xmlXPathCompPredicate(ctxt, 0);
9459
9.27k
  }
9460
9461
248k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9462
248k
                           test, type, (void *)prefix, (void *)name) == -1) {
9463
31
            xmlFree(prefix);
9464
31
            xmlFree(name);
9465
31
        }
9466
248k
    }
9467
277k
}
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
260k
(xmlXPathParserContextPtr ctxt) {
9482
260k
    SKIP_BLANKS;
9483
260k
    if ((CUR == '/') && (NXT(1) == '/')) {
9484
3.59k
  SKIP(2);
9485
3.59k
  SKIP_BLANKS;
9486
3.59k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9487
3.59k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9488
257k
    } else if (CUR == '/') {
9489
4.20k
      NEXT;
9490
4.20k
  SKIP_BLANKS;
9491
4.20k
    }
9492
260k
    xmlXPathCompStep(ctxt);
9493
260k
    CHECK_ERROR;
9494
259k
    SKIP_BLANKS;
9495
276k
    while (CUR == '/') {
9496
16.5k
  if ((CUR == '/') && (NXT(1) == '/')) {
9497
5.96k
      SKIP(2);
9498
5.96k
      SKIP_BLANKS;
9499
5.96k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9500
5.96k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9501
5.96k
      xmlXPathCompStep(ctxt);
9502
10.6k
  } else if (CUR == '/') {
9503
10.6k
      NEXT;
9504
10.6k
      SKIP_BLANKS;
9505
10.6k
      xmlXPathCompStep(ctxt);
9506
10.6k
  }
9507
16.5k
  SKIP_BLANKS;
9508
16.5k
    }
9509
259k
}
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
262k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9525
262k
    SKIP_BLANKS;
9526
262k
    if (CUR != '/') {
9527
227k
        xmlXPathCompRelativeLocationPath(ctxt);
9528
227k
    } else {
9529
71.8k
  while (CUR == '/') {
9530
37.5k
      if ((CUR == '/') && (NXT(1) == '/')) {
9531
11.6k
    SKIP(2);
9532
11.6k
    SKIP_BLANKS;
9533
11.6k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9534
11.6k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9535
11.6k
    xmlXPathCompRelativeLocationPath(ctxt);
9536
25.8k
      } else if (CUR == '/') {
9537
25.8k
    NEXT;
9538
25.8k
    SKIP_BLANKS;
9539
25.8k
    if ((CUR != 0) &&
9540
25.1k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9541
18.0k
                     (CUR == '_') || (CUR == '.') ||
9542
11.2k
         (CUR == '@') || (CUR == '*')))
9543
19.1k
        xmlXPathCompRelativeLocationPath(ctxt);
9544
25.8k
      }
9545
37.5k
      CHECK_ERROR;
9546
37.5k
  }
9547
34.7k
    }
9548
262k
}
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
149k
{
9578
149k
    xmlXPathContextPtr xpctxt;
9579
149k
    xmlNodePtr oldnode;
9580
149k
    xmlDocPtr olddoc;
9581
149k
    xmlXPathStepOpPtr filterOp;
9582
149k
    int oldcs, oldpp;
9583
149k
    int i, j, pos;
9584
9585
149k
    if ((set == NULL) || (set->nodeNr == 0))
9586
3.83k
        return;
9587
9588
    /*
9589
    * Check if the node set contains a sufficient number of nodes for
9590
    * the requested range.
9591
    */
9592
145k
    if (set->nodeNr < minPos) {
9593
2.12k
        xmlXPathNodeSetClear(set, hasNsNodes);
9594
2.12k
        return;
9595
2.12k
    }
9596
9597
143k
    xpctxt = ctxt->context;
9598
143k
    oldnode = xpctxt->node;
9599
143k
    olddoc = xpctxt->doc;
9600
143k
    oldcs = xpctxt->contextSize;
9601
143k
    oldpp = xpctxt->proximityPosition;
9602
143k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9603
9604
143k
    xpctxt->contextSize = set->nodeNr;
9605
9606
573k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9607
496k
        xmlNodePtr node = set->nodeTab[i];
9608
496k
        int res;
9609
9610
496k
        xpctxt->node = node;
9611
496k
        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
496k
        if ((node->type != XML_NAMESPACE_DECL) &&
9620
481k
            (node->doc != NULL))
9621
481k
            xpctxt->doc = node->doc;
9622
9623
496k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9624
9625
496k
        if (ctxt->error != XPATH_EXPRESSION_OK)
9626
1.76k
            break;
9627
494k
        if (res < 0) {
9628
            /* Shouldn't happen */
9629
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9630
0
            break;
9631
0
        }
9632
9633
494k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9634
169k
            if (i != j) {
9635
6.95k
                set->nodeTab[j] = node;
9636
6.95k
                set->nodeTab[i] = NULL;
9637
6.95k
            }
9638
9639
169k
            j += 1;
9640
325k
        } else {
9641
            /* Remove the entry from the initial node set. */
9642
325k
            set->nodeTab[i] = NULL;
9643
325k
            if (node->type == XML_NAMESPACE_DECL)
9644
2.50k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9645
325k
        }
9646
9647
494k
        if (res != 0) {
9648
202k
            if (pos == maxPos) {
9649
65.1k
                i += 1;
9650
65.1k
                break;
9651
65.1k
            }
9652
9653
136k
            pos += 1;
9654
136k
        }
9655
494k
    }
9656
9657
    /* Free remaining nodes. */
9658
143k
    if (hasNsNodes) {
9659
11.6k
        for (; i < set->nodeNr; i++) {
9660
670
            xmlNodePtr node = set->nodeTab[i];
9661
670
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9662
27
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9663
670
        }
9664
10.9k
    }
9665
9666
143k
    set->nodeNr = j;
9667
9668
    /* If too many elements were removed, shrink table to preserve memory. */
9669
143k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9670
12.6k
        (set->nodeNr < set->nodeMax / 2)) {
9671
7.88k
        xmlNodePtr *tmp;
9672
7.88k
        int nodeMax = set->nodeNr;
9673
9674
7.88k
        if (nodeMax < XML_NODESET_DEFAULT)
9675
7.77k
            nodeMax = XML_NODESET_DEFAULT;
9676
7.88k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9677
7.88k
                nodeMax * sizeof(xmlNodePtr));
9678
7.88k
        if (tmp == NULL) {
9679
2
            xmlXPathPErrMemory(ctxt);
9680
7.87k
        } else {
9681
7.87k
            set->nodeTab = tmp;
9682
7.87k
            set->nodeMax = nodeMax;
9683
7.87k
        }
9684
7.88k
    }
9685
9686
143k
    xpctxt->node = oldnode;
9687
143k
    xpctxt->doc = olddoc;
9688
143k
    xpctxt->contextSize = oldcs;
9689
143k
    xpctxt->proximityPosition = oldpp;
9690
143k
}
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
142k
{
9711
142k
    if (op->ch1 != -1) {
9712
1.42k
  xmlXPathCompExprPtr comp = ctxt->comp;
9713
  /*
9714
  * Process inner predicates first.
9715
  */
9716
1.42k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9717
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9718
0
  }
9719
1.42k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9720
1.42k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9721
1.42k
        ctxt->context->depth += 1;
9722
1.42k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9723
1.42k
                                    1, set->nodeNr, hasNsNodes);
9724
1.42k
        ctxt->context->depth -= 1;
9725
1.42k
  CHECK_ERROR;
9726
1.42k
    }
9727
9728
142k
    if (op->ch2 != -1)
9729
142k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9730
142k
}
9731
9732
static int
9733
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9734
          xmlXPathStepOpPtr op,
9735
          int *maxPos)
9736
127k
{
9737
9738
127k
    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
127k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9754
0
  return(0);
9755
9756
127k
    if (op->ch2 != -1) {
9757
127k
  exprOp = &ctxt->comp->steps[op->ch2];
9758
127k
    } else
9759
0
  return(0);
9760
9761
127k
    if ((exprOp != NULL) &&
9762
127k
  (exprOp->op == XPATH_OP_VALUE) &&
9763
67.6k
  (exprOp->value4 != NULL) &&
9764
67.6k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9765
67.3k
    {
9766
67.3k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
9767
9768
  /*
9769
  * We have a "[n]" predicate here.
9770
  * TODO: Unfortunately this simplistic test here is not
9771
  * able to detect a position() predicate in compound
9772
  * expressions like "[@attr = 'a" and position() = 1],
9773
  * and even not the usage of position() in
9774
  * "[position() = 1]"; thus - obviously - a position-range,
9775
  * like it "[position() < 5]", is also not detected.
9776
  * Maybe we could rewrite the AST to ease the optimization.
9777
  */
9778
9779
67.3k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9780
64.9k
      *maxPos = (int) floatval;
9781
64.9k
            if (floatval == (double) *maxPos)
9782
62.5k
                return(1);
9783
64.9k
        }
9784
67.3k
    }
9785
65.1k
    return(0);
9786
127k
}
9787
9788
static int
9789
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9790
                           xmlXPathStepOpPtr op,
9791
         xmlNodePtr * first, xmlNodePtr * last,
9792
         int toBool)
9793
1.16M
{
9794
9795
1.16M
#define XP_TEST_HIT \
9796
5.56M
    if (hasAxisRange != 0) { \
9797
54.5k
  if (++pos == maxPos) { \
9798
20.8k
      if (addNode(seq, cur) < 0) \
9799
20.8k
          xmlXPathPErrMemory(ctxt); \
9800
20.8k
      goto axis_range_end; } \
9801
5.50M
    } else { \
9802
5.50M
  if (addNode(seq, cur) < 0) \
9803
5.50M
      xmlXPathPErrMemory(ctxt); \
9804
5.50M
  if (breakOnFirstHit) goto first_hit; }
9805
9806
1.16M
#define XP_TEST_HIT_NS \
9807
1.16M
    if (hasAxisRange != 0) { \
9808
1.34k
  if (++pos == maxPos) { \
9809
747
      hasNsNodes = 1; \
9810
747
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9811
747
          xmlXPathPErrMemory(ctxt); \
9812
747
  goto axis_range_end; } \
9813
78.9k
    } else { \
9814
78.9k
  hasNsNodes = 1; \
9815
78.9k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9816
78.9k
      xmlXPathPErrMemory(ctxt); \
9817
78.9k
  if (breakOnFirstHit) goto first_hit; }
9818
9819
1.16M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9820
1.16M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9821
1.16M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9822
1.16M
    const xmlChar *prefix = op->value4;
9823
1.16M
    const xmlChar *name = op->value5;
9824
1.16M
    const xmlChar *URI = NULL;
9825
9826
1.16M
    int total = 0, hasNsNodes = 0;
9827
    /* The popped object holding the context nodes */
9828
1.16M
    xmlXPathObjectPtr obj;
9829
    /* The set of context nodes for the node tests */
9830
1.16M
    xmlNodeSetPtr contextSeq;
9831
1.16M
    int contextIdx;
9832
1.16M
    xmlNodePtr contextNode;
9833
    /* The final resulting node set wrt to all context nodes */
9834
1.16M
    xmlNodeSetPtr outSeq;
9835
    /*
9836
    * The temporary resulting node set wrt 1 context node.
9837
    * Used to feed predicate evaluation.
9838
    */
9839
1.16M
    xmlNodeSetPtr seq;
9840
1.16M
    xmlNodePtr cur;
9841
    /* First predicate operator */
9842
1.16M
    xmlXPathStepOpPtr predOp;
9843
1.16M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9844
1.16M
    int hasPredicateRange, hasAxisRange, pos;
9845
1.16M
    int breakOnFirstHit;
9846
9847
1.16M
    xmlXPathTraversalFunction next = NULL;
9848
1.16M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9849
1.16M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9850
1.16M
    xmlNodePtr oldContextNode;
9851
1.16M
    xmlXPathContextPtr xpctxt = ctxt->context;
9852
9853
9854
1.16M
    CHECK_TYPE0(XPATH_NODESET);
9855
1.16M
    obj = xmlXPathValuePop(ctxt);
9856
    /*
9857
    * Setup namespaces.
9858
    */
9859
1.16M
    if (prefix != NULL) {
9860
7.99k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9861
7.99k
        if (URI == NULL) {
9862
175
      xmlXPathReleaseObject(xpctxt, obj);
9863
175
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9864
175
                           "Undefined namespace prefix: %s\n", prefix);
9865
175
            return 0;
9866
175
  }
9867
7.99k
    }
9868
    /*
9869
    * Setup axis.
9870
    *
9871
    * MAYBE FUTURE TODO: merging optimizations:
9872
    * - If the nodes to be traversed wrt to the initial nodes and
9873
    *   the current axis cannot overlap, then we could avoid searching
9874
    *   for duplicates during the merge.
9875
    *   But the question is how/when to evaluate if they cannot overlap.
9876
    *   Example: if we know that for two initial nodes, the one is
9877
    *   not in the ancestor-or-self axis of the other, then we could safely
9878
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
9879
    *   the descendant-or-self axis.
9880
    */
9881
1.16M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9882
1.16M
    switch (axis) {
9883
453
        case AXIS_ANCESTOR:
9884
453
            first = NULL;
9885
453
            next = xmlXPathNextAncestor;
9886
453
            break;
9887
340
        case AXIS_ANCESTOR_OR_SELF:
9888
340
            first = NULL;
9889
340
            next = xmlXPathNextAncestorOrSelf;
9890
340
            break;
9891
20.6k
        case AXIS_ATTRIBUTE:
9892
20.6k
            first = NULL;
9893
20.6k
      last = NULL;
9894
20.6k
            next = xmlXPathNextAttribute;
9895
20.6k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9896
20.6k
            break;
9897
922k
        case AXIS_CHILD:
9898
922k
      last = NULL;
9899
922k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9900
917k
    (type == NODE_TYPE_NODE))
9901
917k
      {
9902
    /*
9903
    * Optimization if an element node type is 'element'.
9904
    */
9905
917k
    next = xmlXPathNextChildElement;
9906
917k
      } else
9907
4.53k
    next = xmlXPathNextChild;
9908
922k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9909
922k
            break;
9910
52.3k
        case AXIS_DESCENDANT:
9911
52.3k
      last = NULL;
9912
52.3k
            next = xmlXPathNextDescendant;
9913
52.3k
            break;
9914
139k
        case AXIS_DESCENDANT_OR_SELF:
9915
139k
      last = NULL;
9916
139k
            next = xmlXPathNextDescendantOrSelf;
9917
139k
            break;
9918
427
        case AXIS_FOLLOWING:
9919
427
      last = NULL;
9920
427
            next = xmlXPathNextFollowing;
9921
427
            break;
9922
0
        case AXIS_FOLLOWING_SIBLING:
9923
0
      last = NULL;
9924
0
            next = xmlXPathNextFollowingSibling;
9925
0
            break;
9926
2.24k
        case AXIS_NAMESPACE:
9927
2.24k
            first = NULL;
9928
2.24k
      last = NULL;
9929
2.24k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9930
2.24k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9931
2.24k
            break;
9932
29.0k
        case AXIS_PARENT:
9933
29.0k
            first = NULL;
9934
29.0k
            next = xmlXPathNextParent;
9935
29.0k
            break;
9936
64
        case AXIS_PRECEDING:
9937
64
            first = NULL;
9938
64
            next = xmlXPathNextPrecedingInternal;
9939
64
            break;
9940
3
        case AXIS_PRECEDING_SIBLING:
9941
3
            first = NULL;
9942
3
            next = xmlXPathNextPrecedingSibling;
9943
3
            break;
9944
438
        case AXIS_SELF:
9945
438
            first = NULL;
9946
438
      last = NULL;
9947
438
            next = xmlXPathNextSelf;
9948
438
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9949
438
            break;
9950
1.16M
    }
9951
9952
1.16M
    if (next == NULL) {
9953
0
  xmlXPathReleaseObject(xpctxt, obj);
9954
0
        return(0);
9955
0
    }
9956
1.16M
    contextSeq = obj->nodesetval;
9957
1.16M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9958
81.7k
        xmlXPathValuePush(ctxt, obj);
9959
81.7k
        return(0);
9960
81.7k
    }
9961
    /*
9962
    * Predicate optimization ---------------------------------------------
9963
    * If this step has a last predicate, which contains a position(),
9964
    * then we'll optimize (although not exactly "position()", but only
9965
    * the  short-hand form, i.e., "[n]".
9966
    *
9967
    * Example - expression "/foo[parent::bar][1]":
9968
    *
9969
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
9970
    *   ROOT                               -- op->ch1
9971
    *   PREDICATE                          -- op->ch2 (predOp)
9972
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
9973
    *       SORT
9974
    *         COLLECT  'parent' 'name' 'node' bar
9975
    *           NODE
9976
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
9977
    *
9978
    */
9979
1.08M
    maxPos = 0;
9980
1.08M
    predOp = NULL;
9981
1.08M
    hasPredicateRange = 0;
9982
1.08M
    hasAxisRange = 0;
9983
1.08M
    if (op->ch2 != -1) {
9984
  /*
9985
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9986
  */
9987
127k
  predOp = &ctxt->comp->steps[op->ch2];
9988
127k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9989
62.5k
      if (predOp->ch1 != -1) {
9990
    /*
9991
    * Use the next inner predicate operator.
9992
    */
9993
38.9k
    predOp = &ctxt->comp->steps[predOp->ch1];
9994
38.9k
    hasPredicateRange = 1;
9995
38.9k
      } else {
9996
    /*
9997
    * There's no other predicate than the [n] predicate.
9998
    */
9999
23.5k
    predOp = NULL;
10000
23.5k
    hasAxisRange = 1;
10001
23.5k
      }
10002
62.5k
  }
10003
127k
    }
10004
1.08M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
10005
    /*
10006
    * Axis traversal -----------------------------------------------------
10007
    */
10008
    /*
10009
     * 2.3 Node Tests
10010
     *  - For the attribute axis, the principal node type is attribute.
10011
     *  - For the namespace axis, the principal node type is namespace.
10012
     *  - For other axes, the principal node type is element.
10013
     *
10014
     * A node test * is true for any node of the
10015
     * principal node type. For example, child::* will
10016
     * select all element children of the context node
10017
     */
10018
1.08M
    oldContextNode = xpctxt->node;
10019
1.08M
    addNode = xmlXPathNodeSetAddUnique;
10020
1.08M
    outSeq = NULL;
10021
1.08M
    seq = NULL;
10022
1.08M
    contextNode = NULL;
10023
1.08M
    contextIdx = 0;
10024
10025
10026
3.27M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10027
2.26M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
10028
2.26M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
10029
10030
2.26M
  if (seq == NULL) {
10031
1.10M
      seq = xmlXPathNodeSetCreate(NULL);
10032
1.10M
      if (seq == NULL) {
10033
135
                xmlXPathPErrMemory(ctxt);
10034
135
    total = 0;
10035
135
    goto error;
10036
135
      }
10037
1.10M
  }
10038
  /*
10039
  * Traverse the axis and test the nodes.
10040
  */
10041
2.26M
  pos = 0;
10042
2.26M
  cur = NULL;
10043
2.26M
  hasNsNodes = 0;
10044
9.30M
        do {
10045
9.30M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10046
40
                goto error;
10047
10048
9.30M
            cur = next(ctxt, cur);
10049
9.30M
            if (cur == NULL)
10050
2.18M
                break;
10051
10052
      /*
10053
      * QUESTION TODO: What does the "first" and "last" stuff do?
10054
      */
10055
7.12M
            if ((first != NULL) && (*first != NULL)) {
10056
1.37k
    if (*first == cur)
10057
261
        break;
10058
1.11k
    if (((total % 256) == 0) &&
10059
1.01k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10060
1.01k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10061
#else
10062
        (xmlXPathCmpNodes(*first, cur) >= 0))
10063
#endif
10064
852
    {
10065
852
        break;
10066
852
    }
10067
1.11k
      }
10068
7.12M
      if ((last != NULL) && (*last != NULL)) {
10069
1.47k
    if (*last == cur)
10070
169
        break;
10071
1.30k
    if (((total % 256) == 0) &&
10072
763
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10073
763
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10074
#else
10075
        (xmlXPathCmpNodes(cur, *last) >= 0))
10076
#endif
10077
682
    {
10078
682
        break;
10079
682
    }
10080
1.30k
      }
10081
10082
7.12M
            total++;
10083
10084
7.12M
      switch (test) {
10085
0
                case NODE_TEST_NONE:
10086
0
        total = 0;
10087
0
        goto error;
10088
4.09M
                case NODE_TEST_TYPE:
10089
4.09M
        if (type == NODE_TYPE_NODE) {
10090
3.96M
      switch (cur->type) {
10091
123k
          case XML_DOCUMENT_NODE:
10092
123k
          case XML_HTML_DOCUMENT_NODE:
10093
2.67M
          case XML_ELEMENT_NODE:
10094
2.67M
          case XML_ATTRIBUTE_NODE:
10095
2.80M
          case XML_PI_NODE:
10096
2.82M
          case XML_COMMENT_NODE:
10097
2.92M
          case XML_CDATA_SECTION_NODE:
10098
3.96M
          case XML_TEXT_NODE:
10099
3.96M
        XP_TEST_HIT
10100
3.95M
        break;
10101
3.95M
          case XML_NAMESPACE_DECL: {
10102
5.73k
        if (axis == AXIS_NAMESPACE) {
10103
0
            XP_TEST_HIT_NS
10104
5.73k
        } else {
10105
5.73k
                              hasNsNodes = 1;
10106
5.73k
            XP_TEST_HIT
10107
5.73k
        }
10108
5.73k
        break;
10109
5.73k
                            }
10110
5.73k
          default:
10111
1.12k
        break;
10112
3.96M
      }
10113
3.96M
        } else if (cur->type == (xmlElementType) type) {
10114
63.2k
      if (cur->type == XML_NAMESPACE_DECL)
10115
0
          XP_TEST_HIT_NS
10116
63.2k
      else
10117
63.2k
          XP_TEST_HIT
10118
63.9k
        } else if ((type == NODE_TYPE_TEXT) &&
10119
63.9k
       (cur->type == XML_CDATA_SECTION_NODE))
10120
18.8k
        {
10121
18.8k
      XP_TEST_HIT
10122
18.8k
        }
10123
4.08M
        break;
10124
4.08M
                case NODE_TEST_PI:
10125
277
                    if ((cur->type == XML_PI_NODE) &&
10126
88
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10127
54
        {
10128
54
      XP_TEST_HIT
10129
54
                    }
10130
277
                    break;
10131
1.30M
                case NODE_TEST_ALL:
10132
1.30M
                    if (axis == AXIS_ATTRIBUTE) {
10133
23.6k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10134
23.6k
      {
10135
23.6k
                            if (prefix == NULL)
10136
22.7k
          {
10137
22.7k
        XP_TEST_HIT
10138
22.7k
                            } else if ((cur->ns != NULL) &&
10139
741
        (xmlStrEqual(URI, cur->ns->href)))
10140
741
          {
10141
741
        XP_TEST_HIT
10142
741
                            }
10143
23.6k
                        }
10144
1.27M
                    } else if (axis == AXIS_NAMESPACE) {
10145
79.6k
                        if (cur->type == XML_NAMESPACE_DECL)
10146
79.6k
      {
10147
79.6k
          XP_TEST_HIT_NS
10148
79.6k
                        }
10149
1.19M
                    } else {
10150
1.19M
                        if (cur->type == XML_ELEMENT_NODE) {
10151
1.10M
                            if (prefix == NULL)
10152
1.09M
          {
10153
1.09M
        XP_TEST_HIT
10154
10155
1.09M
                            } else if ((cur->ns != NULL) &&
10156
1.60k
        (xmlStrEqual(URI, cur->ns->href)))
10157
901
          {
10158
901
        XP_TEST_HIT
10159
901
                            }
10160
1.10M
                        }
10161
1.19M
                    }
10162
1.24M
                    break;
10163
1.24M
                case NODE_TEST_NS:{
10164
                        /* TODO */
10165
0
                        break;
10166
1.30M
                    }
10167
1.72M
                case NODE_TEST_NAME:
10168
1.72M
                    if (axis == AXIS_ATTRIBUTE) {
10169
4.64k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10170
0
          break;
10171
1.71M
        } else if (axis == AXIS_NAMESPACE) {
10172
2.83k
                        if (cur->type != XML_NAMESPACE_DECL)
10173
0
          break;
10174
1.71M
        } else {
10175
1.71M
            if (cur->type != XML_ELEMENT_NODE)
10176
218k
          break;
10177
1.71M
        }
10178
1.50M
                    switch (cur->type) {
10179
1.49M
                        case XML_ELEMENT_NODE:
10180
1.49M
                            if (xmlStrEqual(name, cur->name)) {
10181
399k
                                if (prefix == NULL) {
10182
396k
                                    if (cur->ns == NULL)
10183
395k
            {
10184
395k
          XP_TEST_HIT
10185
395k
                                    }
10186
396k
                                } else {
10187
3.41k
                                    if ((cur->ns != NULL) &&
10188
329
                                        (xmlStrEqual(URI, cur->ns->href)))
10189
77
            {
10190
77
          XP_TEST_HIT
10191
77
                                    }
10192
3.41k
                                }
10193
399k
                            }
10194
1.48M
                            break;
10195
1.48M
                        case XML_ATTRIBUTE_NODE:{
10196
4.64k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10197
10198
4.64k
                                if (xmlStrEqual(name, attr->name)) {
10199
3.24k
                                    if (prefix == NULL) {
10200
3.01k
                                        if ((attr->ns == NULL) ||
10201
81
                                            (attr->ns->prefix == NULL))
10202
2.93k
          {
10203
2.93k
              XP_TEST_HIT
10204
2.93k
                                        }
10205
3.01k
                                    } else {
10206
224
                                        if ((attr->ns != NULL) &&
10207
1
                                            (xmlStrEqual(URI,
10208
1
                attr->ns->href)))
10209
1
          {
10210
1
              XP_TEST_HIT
10211
1
                                        }
10212
224
                                    }
10213
3.24k
                                }
10214
3.71k
                                break;
10215
4.64k
                            }
10216
3.71k
                        case XML_NAMESPACE_DECL:
10217
2.83k
                            if (cur->type == XML_NAMESPACE_DECL) {
10218
2.83k
                                xmlNsPtr ns = (xmlNsPtr) cur;
10219
10220
2.83k
                                if ((ns->prefix != NULL) && (name != NULL)
10221
2.06k
                                    && (xmlStrEqual(ns->prefix, name)))
10222
670
        {
10223
670
            XP_TEST_HIT_NS
10224
670
                                }
10225
2.83k
                            }
10226
2.74k
                            break;
10227
2.74k
                        default:
10228
0
                            break;
10229
1.50M
                    }
10230
1.49M
                    break;
10231
7.12M
      } /* switch(test) */
10232
7.12M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10233
10234
2.18M
  goto apply_predicates;
10235
10236
2.18M
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
21.6k
  if (outSeq == NULL) {
10244
14.6k
      outSeq = seq;
10245
14.6k
      seq = NULL;
10246
14.6k
  } else {
10247
6.98k
      outSeq = mergeAndClear(outSeq, seq);
10248
6.98k
            if (outSeq == NULL)
10249
4
                xmlXPathPErrMemory(ctxt);
10250
6.98k
        }
10251
  /*
10252
  * Break if only a true/false result was requested.
10253
  */
10254
21.6k
  if (toBool)
10255
13.6k
      break;
10256
7.95k
  continue;
10257
10258
50.3k
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
50.3k
  if (outSeq == NULL) {
10264
50.3k
      outSeq = seq;
10265
50.3k
      seq = NULL;
10266
50.3k
  } else {
10267
0
      outSeq = mergeAndClear(outSeq, seq);
10268
0
            if (outSeq == NULL)
10269
0
                xmlXPathPErrMemory(ctxt);
10270
0
        }
10271
50.3k
  break;
10272
10273
2.18M
apply_predicates: /* --------------------------------------------------- */
10274
2.18M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10275
196
      goto error;
10276
10277
        /*
10278
  * Apply predicates.
10279
  */
10280
2.18M
        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
141k
      if (hasPredicateRange != 0)
10310
11.4k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10311
11.4k
              hasNsNodes);
10312
129k
      else
10313
129k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10314
129k
              hasNsNodes);
10315
10316
141k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10317
1.73k
    total = 0;
10318
1.73k
    goto error;
10319
1.73k
      }
10320
141k
        }
10321
10322
2.18M
        if (seq->nodeNr > 0) {
10323
      /*
10324
      * Add to result set.
10325
      */
10326
525k
      if (outSeq == NULL) {
10327
253k
    outSeq = seq;
10328
253k
    seq = NULL;
10329
272k
      } else {
10330
272k
    outSeq = mergeAndClear(outSeq, seq);
10331
272k
                if (outSeq == NULL)
10332
101
                    xmlXPathPErrMemory(ctxt);
10333
272k
      }
10334
10335
525k
            if (toBool)
10336
11.3k
                break;
10337
525k
  }
10338
2.18M
    }
10339
10340
1.08M
error:
10341
1.08M
    if ((obj->boolval) && (obj->user != NULL)) {
10342
  /*
10343
  * QUESTION TODO: What does this do and why?
10344
  * TODO: Do we have to do this also for the "error"
10345
  * cleanup further down?
10346
  */
10347
0
  ctxt->value->boolval = 1;
10348
0
  ctxt->value->user = obj->user;
10349
0
  obj->user = NULL;
10350
0
  obj->boolval = 0;
10351
0
    }
10352
1.08M
    xmlXPathReleaseObject(xpctxt, obj);
10353
10354
    /*
10355
    * Ensure we return at least an empty set.
10356
    */
10357
1.08M
    if (outSeq == NULL) {
10358
767k
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10359
767k
      outSeq = seq;
10360
767k
        } else {
10361
266
      outSeq = xmlXPathNodeSetCreate(NULL);
10362
266
            if (outSeq == NULL)
10363
1
                xmlXPathPErrMemory(ctxt);
10364
266
        }
10365
767k
    }
10366
1.08M
    if ((seq != NULL) && (seq != outSeq)) {
10367
18.2k
   xmlXPathFreeNodeSet(seq);
10368
18.2k
    }
10369
    /*
10370
    * Hand over the result. Better to push the set also in
10371
    * case of errors.
10372
    */
10373
1.08M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10374
    /*
10375
    * Reset the context node.
10376
    */
10377
1.08M
    xpctxt->node = oldContextNode;
10378
    /*
10379
    * When traversing the namespace axis in "toBool" mode, it's
10380
    * possible that tmpNsList wasn't freed.
10381
    */
10382
1.08M
    if (xpctxt->tmpNsList != NULL) {
10383
142
        xmlFree(xpctxt->tmpNsList);
10384
142
        xpctxt->tmpNsList = NULL;
10385
142
    }
10386
10387
1.08M
    return(total);
10388
1.08M
}
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
18.0k
{
10407
18.0k
    int total = 0, cur;
10408
18.0k
    xmlXPathCompExprPtr comp;
10409
18.0k
    xmlXPathObjectPtr arg1, arg2;
10410
10411
18.0k
    CHECK_ERROR0;
10412
18.0k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10413
0
        return(0);
10414
18.0k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10415
18.0k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10416
18.0k
    ctxt->context->depth += 1;
10417
18.0k
    comp = ctxt->comp;
10418
18.0k
    switch (op->op) {
10419
0
        case XPATH_OP_END:
10420
0
            break;
10421
2.61k
        case XPATH_OP_UNION:
10422
2.61k
            total =
10423
2.61k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10424
2.61k
                                        first);
10425
2.61k
      CHECK_ERROR0;
10426
2.38k
            if ((ctxt->value != NULL)
10427
2.38k
                && (ctxt->value->type == XPATH_NODESET)
10428
2.38k
                && (ctxt->value->nodesetval != NULL)
10429
2.38k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10430
                /*
10431
                 * limit tree traversing to first node in the result
10432
                 */
10433
    /*
10434
    * OPTIMIZE TODO: This implicitly sorts
10435
    *  the result, even if not needed. E.g. if the argument
10436
    *  of the count() function, no sorting is needed.
10437
    * OPTIMIZE TODO: How do we know if the node-list wasn't
10438
    *  already sorted?
10439
    */
10440
1.56k
    if (ctxt->value->nodesetval->nodeNr > 1)
10441
814
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10442
1.56k
                *first = ctxt->value->nodesetval->nodeTab[0];
10443
1.56k
            }
10444
2.38k
            cur =
10445
2.38k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10446
2.38k
                                        first);
10447
2.38k
      CHECK_ERROR0;
10448
10449
2.36k
            arg2 = xmlXPathValuePop(ctxt);
10450
2.36k
            arg1 = xmlXPathValuePop(ctxt);
10451
2.36k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10452
2.36k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10453
9
          xmlXPathReleaseObject(ctxt->context, arg1);
10454
9
          xmlXPathReleaseObject(ctxt->context, arg2);
10455
9
                XP_ERROR0(XPATH_INVALID_TYPE);
10456
0
            }
10457
2.35k
            if ((ctxt->context->opLimit != 0) &&
10458
2.35k
                (((arg1->nodesetval != NULL) &&
10459
2.35k
                  (xmlXPathCheckOpLimit(ctxt,
10460
2.35k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10461
2.35k
                 ((arg2->nodesetval != NULL) &&
10462
2.35k
                  (xmlXPathCheckOpLimit(ctxt,
10463
2.35k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10464
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10465
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10466
0
                break;
10467
0
            }
10468
10469
2.35k
            if ((arg2->nodesetval != NULL) &&
10470
2.35k
                (arg2->nodesetval->nodeNr != 0)) {
10471
236
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10472
236
                                                        arg2->nodesetval);
10473
236
                if (arg1->nodesetval == NULL)
10474
1
                    xmlXPathPErrMemory(ctxt);
10475
236
            }
10476
2.35k
            xmlXPathValuePush(ctxt, arg1);
10477
2.35k
      xmlXPathReleaseObject(ctxt->context, arg2);
10478
2.35k
            total += cur;
10479
2.35k
            break;
10480
426
        case XPATH_OP_ROOT:
10481
426
            xmlXPathRoot(ctxt);
10482
426
            break;
10483
1.00k
        case XPATH_OP_NODE:
10484
1.00k
            if (op->ch1 != -1)
10485
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10486
1.00k
      CHECK_ERROR0;
10487
1.00k
            if (op->ch2 != -1)
10488
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10489
1.00k
      CHECK_ERROR0;
10490
1.00k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10491
1.00k
    ctxt->context->node));
10492
1.00k
            break;
10493
4.88k
        case XPATH_OP_COLLECT:{
10494
4.88k
                if (op->ch1 == -1)
10495
0
                    break;
10496
10497
4.88k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10498
4.88k
    CHECK_ERROR0;
10499
10500
4.87k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10501
4.87k
                break;
10502
4.88k
            }
10503
6
        case XPATH_OP_VALUE:
10504
6
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10505
6
            break;
10506
4.15k
        case XPATH_OP_SORT:
10507
4.15k
            if (op->ch1 != -1)
10508
4.15k
                total +=
10509
4.15k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10510
4.15k
                                            first);
10511
4.15k
      CHECK_ERROR0;
10512
4.11k
            if ((ctxt->value != NULL)
10513
4.11k
                && (ctxt->value->type == XPATH_NODESET)
10514
4.00k
                && (ctxt->value->nodesetval != NULL)
10515
4.00k
    && (ctxt->value->nodesetval->nodeNr > 1))
10516
617
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10517
4.11k
            break;
10518
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10519
4.80k
  case XPATH_OP_FILTER:
10520
4.80k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10521
4.80k
            break;
10522
0
#endif
10523
112
        default:
10524
112
            total += xmlXPathCompOpEval(ctxt, op);
10525
112
            break;
10526
18.0k
    }
10527
10528
17.6k
    ctxt->context->depth -= 1;
10529
17.6k
    return(total);
10530
18.0k
}
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
31.3k
{
10545
31.3k
    int total = 0, cur;
10546
31.3k
    xmlXPathCompExprPtr comp;
10547
31.3k
    xmlXPathObjectPtr arg1, arg2;
10548
10549
31.3k
    CHECK_ERROR0;
10550
31.3k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10551
1
        return(0);
10552
31.3k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10553
31.3k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10554
31.3k
    ctxt->context->depth += 1;
10555
31.3k
    comp = ctxt->comp;
10556
31.3k
    switch (op->op) {
10557
0
        case XPATH_OP_END:
10558
0
            break;
10559
12.1k
        case XPATH_OP_UNION:
10560
12.1k
            total =
10561
12.1k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10562
12.1k
      CHECK_ERROR0;
10563
12.0k
            if ((ctxt->value != NULL)
10564
12.0k
                && (ctxt->value->type == XPATH_NODESET)
10565
12.0k
                && (ctxt->value->nodesetval != NULL)
10566
12.0k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10567
                /*
10568
                 * limit tree traversing to first node in the result
10569
                 */
10570
8.35k
    if (ctxt->value->nodesetval->nodeNr > 1)
10571
1.80k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10572
8.35k
                *last =
10573
8.35k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10574
8.35k
                                                     nodesetval->nodeNr -
10575
8.35k
                                                     1];
10576
8.35k
            }
10577
12.0k
            cur =
10578
12.0k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10579
12.0k
      CHECK_ERROR0;
10580
11.9k
            if ((ctxt->value != NULL)
10581
11.9k
                && (ctxt->value->type == XPATH_NODESET)
10582
11.9k
                && (ctxt->value->nodesetval != NULL)
10583
11.9k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10584
3.03k
            }
10585
10586
11.9k
            arg2 = xmlXPathValuePop(ctxt);
10587
11.9k
            arg1 = xmlXPathValuePop(ctxt);
10588
11.9k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10589
11.9k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10590
2
          xmlXPathReleaseObject(ctxt->context, arg1);
10591
2
          xmlXPathReleaseObject(ctxt->context, arg2);
10592
2
                XP_ERROR0(XPATH_INVALID_TYPE);
10593
0
            }
10594
11.9k
            if ((ctxt->context->opLimit != 0) &&
10595
11.9k
                (((arg1->nodesetval != NULL) &&
10596
11.9k
                  (xmlXPathCheckOpLimit(ctxt,
10597
11.9k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10598
11.9k
                 ((arg2->nodesetval != NULL) &&
10599
11.9k
                  (xmlXPathCheckOpLimit(ctxt,
10600
11.9k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10601
1
          xmlXPathReleaseObject(ctxt->context, arg1);
10602
1
          xmlXPathReleaseObject(ctxt->context, arg2);
10603
1
                break;
10604
1
            }
10605
10606
11.9k
            if ((arg2->nodesetval != NULL) &&
10607
11.9k
                (arg2->nodesetval->nodeNr != 0)) {
10608
3.03k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10609
3.03k
                                                        arg2->nodesetval);
10610
3.03k
                if (arg1->nodesetval == NULL)
10611
3
                    xmlXPathPErrMemory(ctxt);
10612
3.03k
            }
10613
11.9k
            xmlXPathValuePush(ctxt, arg1);
10614
11.9k
      xmlXPathReleaseObject(ctxt->context, arg2);
10615
11.9k
            total += cur;
10616
11.9k
            break;
10617
647
        case XPATH_OP_ROOT:
10618
647
            xmlXPathRoot(ctxt);
10619
647
            break;
10620
1.31k
        case XPATH_OP_NODE:
10621
1.31k
            if (op->ch1 != -1)
10622
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10623
1.31k
      CHECK_ERROR0;
10624
1.31k
            if (op->ch2 != -1)
10625
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10626
1.31k
      CHECK_ERROR0;
10627
1.31k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10628
1.31k
    ctxt->context->node));
10629
1.31k
            break;
10630
13.5k
        case XPATH_OP_COLLECT:{
10631
13.5k
                if (op->ch1 == -1)
10632
0
                    break;
10633
10634
13.5k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10635
13.5k
    CHECK_ERROR0;
10636
10637
13.5k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10638
13.5k
                break;
10639
13.5k
            }
10640
2
        case XPATH_OP_VALUE:
10641
2
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10642
2
            break;
10643
3.60k
        case XPATH_OP_SORT:
10644
3.60k
            if (op->ch1 != -1)
10645
3.60k
                total +=
10646
3.60k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10647
3.60k
                                           last);
10648
3.60k
      CHECK_ERROR0;
10649
3.55k
            if ((ctxt->value != NULL)
10650
3.55k
                && (ctxt->value->type == XPATH_NODESET)
10651
3.45k
                && (ctxt->value->nodesetval != NULL)
10652
3.45k
    && (ctxt->value->nodesetval->nodeNr > 1))
10653
681
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10654
3.55k
            break;
10655
110
        default:
10656
110
            total += xmlXPathCompOpEval(ctxt, op);
10657
110
            break;
10658
31.3k
    }
10659
10660
31.1k
    ctxt->context->depth -= 1;
10661
31.1k
    return (total);
10662
31.3k
}
10663
10664
#ifdef XP_OPTIMIZED_FILTER_FIRST
10665
static int
10666
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10667
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10668
4.80k
{
10669
4.80k
    int total = 0;
10670
4.80k
    xmlXPathCompExprPtr comp;
10671
4.80k
    xmlXPathObjectPtr obj;
10672
4.80k
    xmlNodeSetPtr set;
10673
10674
4.80k
    CHECK_ERROR0;
10675
4.80k
    comp = ctxt->comp;
10676
    /*
10677
    * Optimization for ()[last()] selection i.e. the last elem
10678
    */
10679
4.80k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10680
4.80k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10681
3.51k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10682
2.35k
  int f = comp->steps[op->ch2].ch1;
10683
10684
2.35k
  if ((f != -1) &&
10685
2.35k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10686
2.02k
      (comp->steps[f].value5 == NULL) &&
10687
1.94k
      (comp->steps[f].value == 0) &&
10688
1.74k
      (comp->steps[f].value4 != NULL) &&
10689
1.74k
      (xmlStrEqual
10690
1.74k
      (comp->steps[f].value4, BAD_CAST "last"))) {
10691
1.66k
      xmlNodePtr last = NULL;
10692
10693
1.66k
      total +=
10694
1.66k
    xmlXPathCompOpEvalLast(ctxt,
10695
1.66k
        &comp->steps[op->ch1],
10696
1.66k
        &last);
10697
1.66k
      CHECK_ERROR0;
10698
      /*
10699
      * The nodeset should be in document order,
10700
      * Keep only the last value
10701
      */
10702
1.65k
      if ((ctxt->value != NULL) &&
10703
1.65k
    (ctxt->value->type == XPATH_NODESET) &&
10704
1.58k
    (ctxt->value->nodesetval != NULL) &&
10705
1.58k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10706
1.32k
    (ctxt->value->nodesetval->nodeNr > 1)) {
10707
264
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10708
264
    *first = *(ctxt->value->nodesetval->nodeTab);
10709
264
      }
10710
1.65k
      return (total);
10711
1.66k
  }
10712
2.35k
    }
10713
10714
3.13k
    if (op->ch1 != -1)
10715
3.13k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10716
3.13k
    CHECK_ERROR0;
10717
1.88k
    if (op->ch2 == -1)
10718
0
  return (total);
10719
1.88k
    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
1.88k
    CHECK_TYPE0(XPATH_NODESET);
10728
1.86k
    obj = xmlXPathValuePop(ctxt);
10729
1.86k
    set = obj->nodesetval;
10730
1.86k
    if (set != NULL) {
10731
1.86k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10732
1.86k
        if (set->nodeNr > 0)
10733
410
            *first = set->nodeTab[0];
10734
1.86k
    }
10735
1.86k
    xmlXPathValuePush(ctxt, obj);
10736
10737
1.86k
    return (total);
10738
1.88k
}
10739
#endif /* XP_OPTIMIZED_FILTER_FIRST */
10740
10741
/**
10742
 * Evaluate the Precompiled XPath operation
10743
 *
10744
 * @param ctxt  the XPath parser context with the compiled expression
10745
 * @param op  an XPath compiled operation
10746
 * @returns the number of nodes traversed
10747
 */
10748
static int
10749
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10750
4.04M
{
10751
4.04M
    int total = 0;
10752
4.04M
    int equal, ret;
10753
4.04M
    xmlXPathCompExprPtr comp;
10754
4.04M
    xmlXPathObjectPtr arg1, arg2;
10755
10756
4.04M
    CHECK_ERROR0;
10757
4.04M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10758
44
        return(0);
10759
4.04M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10760
4.04M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10761
4.04M
    ctxt->context->depth += 1;
10762
4.04M
    comp = ctxt->comp;
10763
4.04M
    switch (op->op) {
10764
0
        case XPATH_OP_END:
10765
0
            break;
10766
2.11k
        case XPATH_OP_AND:
10767
2.11k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10768
2.11k
      CHECK_ERROR0;
10769
1.83k
            xmlXPathBooleanFunction(ctxt, 1);
10770
1.83k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10771
363
                break;
10772
1.47k
            arg2 = xmlXPathValuePop(ctxt);
10773
1.47k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10774
1.47k
      if (ctxt->error) {
10775
37
    xmlXPathFreeObject(arg2);
10776
37
    break;
10777
37
      }
10778
1.43k
            xmlXPathBooleanFunction(ctxt, 1);
10779
1.43k
            if (ctxt->value != NULL)
10780
1.43k
                ctxt->value->boolval &= arg2->boolval;
10781
1.43k
      xmlXPathReleaseObject(ctxt->context, arg2);
10782
1.43k
            break;
10783
4.86k
        case XPATH_OP_OR:
10784
4.86k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10785
4.86k
      CHECK_ERROR0;
10786
4.03k
            xmlXPathBooleanFunction(ctxt, 1);
10787
4.03k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10788
943
                break;
10789
3.08k
            arg2 = xmlXPathValuePop(ctxt);
10790
3.08k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10791
3.08k
      if (ctxt->error) {
10792
121
    xmlXPathFreeObject(arg2);
10793
121
    break;
10794
121
      }
10795
2.96k
            xmlXPathBooleanFunction(ctxt, 1);
10796
2.96k
            if (ctxt->value != NULL)
10797
2.96k
                ctxt->value->boolval |= arg2->boolval;
10798
2.96k
      xmlXPathReleaseObject(ctxt->context, arg2);
10799
2.96k
            break;
10800
413k
        case XPATH_OP_EQUAL:
10801
413k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10802
413k
      CHECK_ERROR0;
10803
404k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10804
404k
      CHECK_ERROR0;
10805
403k
      if (op->value)
10806
396k
    equal = xmlXPathEqualValues(ctxt);
10807
6.82k
      else
10808
6.82k
    equal = xmlXPathNotEqualValues(ctxt);
10809
403k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10810
403k
            break;
10811
189k
        case XPATH_OP_CMP:
10812
189k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10813
189k
      CHECK_ERROR0;
10814
187k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10815
187k
      CHECK_ERROR0;
10816
187k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10817
187k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10818
187k
            break;
10819
276k
        case XPATH_OP_PLUS:
10820
276k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10821
276k
      CHECK_ERROR0;
10822
273k
            if (op->ch2 != -1) {
10823
142k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10824
142k
      }
10825
273k
      CHECK_ERROR0;
10826
272k
            if (op->value == 0)
10827
69.2k
                xmlXPathSubValues(ctxt);
10828
203k
            else if (op->value == 1)
10829
71.9k
                xmlXPathAddValues(ctxt);
10830
131k
            else if (op->value == 2)
10831
114k
                xmlXPathValueFlipSign(ctxt);
10832
16.4k
            else if (op->value == 3) {
10833
16.4k
                CAST_TO_NUMBER;
10834
16.4k
                CHECK_TYPE0(XPATH_NUMBER);
10835
16.4k
            }
10836
272k
            break;
10837
272k
        case XPATH_OP_MULT:
10838
181k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10839
181k
      CHECK_ERROR0;
10840
172k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10841
172k
      CHECK_ERROR0;
10842
172k
            if (op->value == 0)
10843
169k
                xmlXPathMultValues(ctxt);
10844
3.07k
            else if (op->value == 1)
10845
1.50k
                xmlXPathDivValues(ctxt);
10846
1.56k
            else if (op->value == 2)
10847
1.56k
                xmlXPathModValues(ctxt);
10848
172k
            break;
10849
136k
        case XPATH_OP_UNION:
10850
136k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10851
136k
      CHECK_ERROR0;
10852
135k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10853
135k
      CHECK_ERROR0;
10854
10855
135k
            arg2 = xmlXPathValuePop(ctxt);
10856
135k
            arg1 = xmlXPathValuePop(ctxt);
10857
135k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10858
135k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10859
55
          xmlXPathReleaseObject(ctxt->context, arg1);
10860
55
          xmlXPathReleaseObject(ctxt->context, arg2);
10861
55
                XP_ERROR0(XPATH_INVALID_TYPE);
10862
0
            }
10863
135k
            if ((ctxt->context->opLimit != 0) &&
10864
135k
                (((arg1->nodesetval != NULL) &&
10865
135k
                  (xmlXPathCheckOpLimit(ctxt,
10866
135k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10867
135k
                 ((arg2->nodesetval != NULL) &&
10868
135k
                  (xmlXPathCheckOpLimit(ctxt,
10869
135k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10870
14
          xmlXPathReleaseObject(ctxt->context, arg1);
10871
14
          xmlXPathReleaseObject(ctxt->context, arg2);
10872
14
                break;
10873
14
            }
10874
10875
135k
      if (((arg2->nodesetval != NULL) &&
10876
135k
     (arg2->nodesetval->nodeNr != 0)))
10877
50.9k
      {
10878
50.9k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10879
50.9k
              arg2->nodesetval);
10880
50.9k
                if (arg1->nodesetval == NULL)
10881
44
                    xmlXPathPErrMemory(ctxt);
10882
50.9k
      }
10883
10884
135k
            xmlXPathValuePush(ctxt, arg1);
10885
135k
      xmlXPathReleaseObject(ctxt->context, arg2);
10886
135k
            break;
10887
393k
        case XPATH_OP_ROOT:
10888
393k
            xmlXPathRoot(ctxt);
10889
393k
            break;
10890
849k
        case XPATH_OP_NODE:
10891
849k
            if (op->ch1 != -1)
10892
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10893
849k
      CHECK_ERROR0;
10894
849k
            if (op->ch2 != -1)
10895
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10896
849k
      CHECK_ERROR0;
10897
849k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10898
849k
                                                    ctxt->context->node));
10899
849k
            break;
10900
1.02M
        case XPATH_OP_COLLECT:{
10901
1.02M
                if (op->ch1 == -1)
10902
0
                    break;
10903
10904
1.02M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10905
1.02M
    CHECK_ERROR0;
10906
10907
1.02M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10908
1.02M
                break;
10909
1.02M
            }
10910
325k
        case XPATH_OP_VALUE:
10911
325k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10912
325k
            break;
10913
64
        case XPATH_OP_VARIABLE:{
10914
64
    xmlXPathObjectPtr val;
10915
10916
64
                if (op->ch1 != -1)
10917
0
                    total +=
10918
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10919
64
                if (op->value5 == NULL) {
10920
44
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10921
44
        if (val == NULL) {
10922
44
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10923
44
                                       "Undefined variable: %s\n", op->value4);
10924
44
                        return 0;
10925
44
                    }
10926
0
                    xmlXPathValuePush(ctxt, val);
10927
20
    } else {
10928
20
                    const xmlChar *URI;
10929
10930
20
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10931
20
                    if (URI == NULL) {
10932
9
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10933
9
                                       "Undefined namespace prefix: %s\n",
10934
9
                                       op->value5);
10935
9
                        return 0;
10936
9
                    }
10937
11
        val = xmlXPathVariableLookupNS(ctxt->context,
10938
11
                                                       op->value4, URI);
10939
11
        if (val == NULL) {
10940
11
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10941
11
                                       "Undefined variable: %s:%s\n",
10942
11
                                       op->value5, op->value4);
10943
11
                        return 0;
10944
11
                    }
10945
0
                    xmlXPathValuePush(ctxt, val);
10946
0
                }
10947
0
                break;
10948
64
            }
10949
49.7k
        case XPATH_OP_FUNCTION:{
10950
49.7k
                xmlXPathFunction func;
10951
49.7k
                const xmlChar *oldFunc, *oldFuncURI;
10952
49.7k
    int i;
10953
49.7k
                int frame;
10954
10955
49.7k
                frame = ctxt->valueNr;
10956
49.7k
                if (op->ch1 != -1) {
10957
39.9k
                    total +=
10958
39.9k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10959
39.9k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10960
897
                        break;
10961
39.9k
                }
10962
48.8k
    if (ctxt->valueNr < frame + op->value)
10963
48.8k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10964
126k
    for (i = 0; i < op->value; i++) {
10965
78.0k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10966
78.0k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10967
78.0k
                }
10968
48.8k
                if (op->cache != NULL)
10969
42.8k
                    func = op->cache;
10970
6.02k
                else {
10971
6.02k
                    const xmlChar *URI = NULL;
10972
10973
6.02k
                    if (op->value5 == NULL) {
10974
5.95k
                        func = xmlXPathFunctionLookup(ctxt->context,
10975
5.95k
                                                      op->value4);
10976
5.95k
                        if (func == NULL) {
10977
534
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10978
534
                                           "Unregistered function: %s\n",
10979
534
                                           op->value4);
10980
534
                            return 0;
10981
534
                        }
10982
5.95k
                    } else {
10983
77
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10984
77
                        if (URI == NULL) {
10985
69
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10986
69
                                           "Undefined namespace prefix: %s\n",
10987
69
                                           op->value5);
10988
69
                            return 0;
10989
69
                        }
10990
8
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10991
8
                                                        op->value4, URI);
10992
8
                        if (func == NULL) {
10993
8
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10994
8
                                           "Unregistered function: %s:%s\n",
10995
8
                                           op->value5, op->value4);
10996
8
                            return 0;
10997
8
                        }
10998
8
                    }
10999
5.41k
                    op->cache = func;
11000
5.41k
                    op->cacheURI = (void *) URI;
11001
5.41k
                }
11002
48.2k
                oldFunc = ctxt->context->function;
11003
48.2k
                oldFuncURI = ctxt->context->functionURI;
11004
48.2k
                ctxt->context->function = op->value4;
11005
48.2k
                ctxt->context->functionURI = op->cacheURI;
11006
48.2k
                func(ctxt, op->value);
11007
48.2k
                ctxt->context->function = oldFunc;
11008
48.2k
                ctxt->context->functionURI = oldFuncURI;
11009
48.2k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11010
47.9k
                    (ctxt->valueNr != frame + 1))
11011
48.2k
                    XP_ERROR0(XPATH_STACK_ERROR);
11012
48.2k
                break;
11013
48.2k
            }
11014
79.9k
        case XPATH_OP_ARG:
11015
79.9k
            if (op->ch1 != -1) {
11016
39.9k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11017
39.9k
          CHECK_ERROR0;
11018
39.9k
            }
11019
79.4k
            if (op->ch2 != -1) {
11020
79.4k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11021
79.4k
          CHECK_ERROR0;
11022
79.4k
      }
11023
78.5k
            break;
11024
78.5k
        case XPATH_OP_PREDICATE:
11025
16.6k
        case XPATH_OP_FILTER:{
11026
16.6k
                xmlXPathObjectPtr obj;
11027
16.6k
                xmlNodeSetPtr set;
11028
11029
                /*
11030
                 * Optimization for ()[1] selection i.e. the first elem
11031
                 */
11032
16.6k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11033
16.6k
#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
16.6k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11044
7.62k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11045
#else
11046
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
#endif
11048
16.5k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11049
11.7k
                    xmlXPathObjectPtr val;
11050
11051
11.7k
                    val = comp->steps[op->ch2].value4;
11052
11.7k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11053
11.7k
                        (val->floatval == 1.0)) {
11054
8.85k
                        xmlNodePtr first = NULL;
11055
11056
8.85k
                        total +=
11057
8.85k
                            xmlXPathCompOpEvalFirst(ctxt,
11058
8.85k
                                                    &comp->steps[op->ch1],
11059
8.85k
                                                    &first);
11060
8.85k
      CHECK_ERROR0;
11061
                        /*
11062
                         * The nodeset should be in document order,
11063
                         * Keep only the first value
11064
                         */
11065
7.53k
                        if ((ctxt->value != NULL) &&
11066
7.53k
                            (ctxt->value->type == XPATH_NODESET) &&
11067
7.36k
                            (ctxt->value->nodesetval != NULL) &&
11068
7.36k
                            (ctxt->value->nodesetval->nodeNr > 1))
11069
606
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11070
606
                                                        1, 1);
11071
7.53k
                        break;
11072
8.85k
                    }
11073
11.7k
                }
11074
                /*
11075
                 * Optimization for ()[last()] selection i.e. the last elem
11076
                 */
11077
7.81k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11078
7.81k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11079
4.92k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11080
4.47k
                    int f = comp->steps[op->ch2].ch1;
11081
11082
4.47k
                    if ((f != -1) &&
11083
4.47k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11084
2.49k
                        (comp->steps[f].value5 == NULL) &&
11085
2.27k
                        (comp->steps[f].value == 0) &&
11086
2.00k
                        (comp->steps[f].value4 != NULL) &&
11087
2.00k
                        (xmlStrEqual
11088
2.00k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11089
1.93k
                        xmlNodePtr last = NULL;
11090
11091
1.93k
                        total +=
11092
1.93k
                            xmlXPathCompOpEvalLast(ctxt,
11093
1.93k
                                                   &comp->steps[op->ch1],
11094
1.93k
                                                   &last);
11095
1.93k
      CHECK_ERROR0;
11096
                        /*
11097
                         * The nodeset should be in document order,
11098
                         * Keep only the last value
11099
                         */
11100
1.90k
                        if ((ctxt->value != NULL) &&
11101
1.90k
                            (ctxt->value->type == XPATH_NODESET) &&
11102
1.86k
                            (ctxt->value->nodesetval != NULL) &&
11103
1.86k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11104
1.75k
                            (ctxt->value->nodesetval->nodeNr > 1))
11105
417
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11106
1.90k
                        break;
11107
1.93k
                    }
11108
4.47k
                }
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
5.87k
                if (op->ch1 != -1)
11121
5.87k
                    total +=
11122
5.87k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11123
5.87k
    CHECK_ERROR0;
11124
5.38k
                if (op->ch2 == -1)
11125
0
                    break;
11126
5.38k
                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
5.38k
                CHECK_TYPE0(XPATH_NODESET);
11136
5.34k
                obj = xmlXPathValuePop(ctxt);
11137
5.34k
                set = obj->nodesetval;
11138
5.34k
                if (set != NULL)
11139
5.34k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11140
5.34k
                                          1, set->nodeNr, 1);
11141
5.34k
                xmlXPathValuePush(ctxt, obj);
11142
5.34k
                break;
11143
5.38k
            }
11144
97.7k
        case XPATH_OP_SORT:
11145
97.7k
            if (op->ch1 != -1)
11146
97.7k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11147
97.7k
      CHECK_ERROR0;
11148
93.4k
            if ((ctxt->value != NULL) &&
11149
93.4k
                (ctxt->value->type == XPATH_NODESET) &&
11150
54.5k
                (ctxt->value->nodesetval != NULL) &&
11151
54.5k
    (ctxt->value->nodesetval->nodeNr > 1))
11152
3.72k
      {
11153
3.72k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11154
3.72k
      }
11155
93.4k
            break;
11156
0
        default:
11157
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11158
0
            break;
11159
4.04M
    }
11160
11161
4.00M
    ctxt->context->depth -= 1;
11162
4.00M
    return (total);
11163
4.04M
}
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
496k
{
11178
496k
    xmlXPathObjectPtr resObj = NULL;
11179
11180
499k
start:
11181
499k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11182
5
        return(0);
11183
    /* comp = ctxt->comp; */
11184
499k
    switch (op->op) {
11185
0
        case XPATH_OP_END:
11186
0
            return (0);
11187
30.2k
  case XPATH_OP_VALUE:
11188
30.2k
      resObj = (xmlXPathObjectPtr) op->value4;
11189
30.2k
      if (isPredicate)
11190
30.2k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11191
0
      return(xmlXPathCastToBoolean(resObj));
11192
2.68k
  case XPATH_OP_SORT:
11193
      /*
11194
      * We don't need sorting for boolean results. Skip this one.
11195
      */
11196
2.68k
            if (op->ch1 != -1) {
11197
2.68k
    op = &ctxt->comp->steps[op->ch1];
11198
2.68k
    goto start;
11199
2.68k
      }
11200
0
      return(0);
11201
126k
  case XPATH_OP_COLLECT:
11202
126k
      if (op->ch1 == -1)
11203
0
    return(0);
11204
11205
126k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11206
126k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11207
115
    return(-1);
11208
11209
126k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11210
126k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11211
298
    return(-1);
11212
11213
126k
      resObj = xmlXPathValuePop(ctxt);
11214
126k
      if (resObj == NULL)
11215
0
    return(-1);
11216
126k
      break;
11217
339k
  default:
11218
      /*
11219
      * Fallback to call xmlXPathCompOpEval().
11220
      */
11221
339k
      xmlXPathCompOpEval(ctxt, op);
11222
339k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11223
1.34k
    return(-1);
11224
11225
338k
      resObj = xmlXPathValuePop(ctxt);
11226
338k
      if (resObj == NULL)
11227
0
    return(-1);
11228
338k
      break;
11229
499k
    }
11230
11231
464k
    if (resObj) {
11232
464k
  int res;
11233
11234
464k
  if (resObj->type == XPATH_BOOLEAN) {
11235
240k
      res = resObj->boolval;
11236
240k
  } 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
224k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11246
224k
  } else {
11247
0
      res = xmlXPathCastToBoolean(resObj);
11248
0
  }
11249
464k
  xmlXPathReleaseObject(ctxt->context, resObj);
11250
464k
  return(res);
11251
464k
    }
11252
11253
0
    return(0);
11254
464k
}
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
13.6k
{
11497
13.6k
    xmlXPathCompExprPtr comp;
11498
13.6k
    int oldDepth;
11499
11500
13.6k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11501
0
  return(-1);
11502
11503
13.6k
    if (ctxt->valueTab == NULL) {
11504
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11505
0
        int valueMax = 1;
11506
#else
11507
        int valueMax = 10;
11508
#endif
11509
11510
  /* Allocate the value stack */
11511
0
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11512
0
  if (ctxt->valueTab == NULL) {
11513
0
      xmlXPathPErrMemory(ctxt);
11514
0
      return(-1);
11515
0
  }
11516
0
  ctxt->valueNr = 0;
11517
0
  ctxt->valueMax = valueMax;
11518
0
  ctxt->value = NULL;
11519
0
    }
11520
#ifdef XPATH_STREAMING
11521
    if (ctxt->comp->stream) {
11522
  int res;
11523
11524
  if (toBool) {
11525
      /*
11526
      * Evaluation to boolean result.
11527
      */
11528
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
11529
      if (res != -1)
11530
    return(res);
11531
  } else {
11532
      xmlXPathObjectPtr resObj = NULL;
11533
11534
      /*
11535
      * Evaluation to a sequence.
11536
      */
11537
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
11538
11539
      if ((res != -1) && (resObj != NULL)) {
11540
    xmlXPathValuePush(ctxt, resObj);
11541
    return(0);
11542
      }
11543
      if (resObj != NULL)
11544
    xmlXPathReleaseObject(ctxt->context, resObj);
11545
  }
11546
  /*
11547
  * QUESTION TODO: This falls back to normal XPath evaluation
11548
  * if res == -1. Is this intended?
11549
  */
11550
    }
11551
#endif
11552
13.6k
    comp = ctxt->comp;
11553
13.6k
    if (comp->last < 0) {
11554
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11555
0
  return(-1);
11556
0
    }
11557
13.6k
    oldDepth = ctxt->context->depth;
11558
13.6k
    if (toBool)
11559
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11560
0
      &comp->steps[comp->last], 0));
11561
13.6k
    else
11562
13.6k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11563
13.6k
    ctxt->context->depth = oldDepth;
11564
11565
13.6k
    return(0);
11566
13.6k
}
11567
11568
/************************************************************************
11569
 *                  *
11570
 *      Public interfaces       *
11571
 *                  *
11572
 ************************************************************************/
11573
11574
/**
11575
 * Evaluate a predicate result for the current node.
11576
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11577
 * the result to a boolean. If the result is a number, the result will
11578
 * be converted to true if the number is equal to the position of the
11579
 * context node in the context node list (as returned by the position
11580
 * function) and will be converted to false otherwise; if the result
11581
 * is not a number, then the result will be converted as if by a call
11582
 * to the boolean function.
11583
 *
11584
 * @param ctxt  the XPath context
11585
 * @param res  the Predicate Expression evaluation result
11586
 * @returns 1 if predicate is true, 0 otherwise
11587
 */
11588
int
11589
0
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11590
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
11591
0
    switch (res->type) {
11592
0
        case XPATH_BOOLEAN:
11593
0
      return(res->boolval);
11594
0
        case XPATH_NUMBER:
11595
0
      return(res->floatval == ctxt->proximityPosition);
11596
0
        case XPATH_NODESET:
11597
0
        case XPATH_XSLT_TREE:
11598
0
      if (res->nodesetval == NULL)
11599
0
    return(0);
11600
0
      return(res->nodesetval->nodeNr != 0);
11601
0
        case XPATH_STRING:
11602
0
      return((res->stringval != NULL) &&
11603
0
             (xmlStrlen(res->stringval) != 0));
11604
0
        default:
11605
0
      break;
11606
0
    }
11607
0
    return(0);
11608
0
}
11609
11610
/**
11611
 * Evaluate a predicate result for the current node.
11612
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11613
 * the result to a boolean. If the result is a number, the result will
11614
 * be converted to true if the number is equal to the position of the
11615
 * context node in the context node list (as returned by the position
11616
 * function) and will be converted to false otherwise; if the result
11617
 * is not a number, then the result will be converted as if by a call
11618
 * to the boolean function.
11619
 *
11620
 * @param ctxt  the XPath Parser context
11621
 * @param res  the Predicate Expression evaluation result
11622
 * @returns 1 if predicate is true, 0 otherwise
11623
 */
11624
int
11625
xmlXPathEvaluatePredicateResult(xmlXPathParserContext *ctxt,
11626
254k
                                xmlXPathObject *res) {
11627
254k
    if ((ctxt == NULL) || (res == NULL)) return(0);
11628
254k
    switch (res->type) {
11629
0
        case XPATH_BOOLEAN:
11630
0
      return(res->boolval);
11631
102k
        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
102k
      return(res->floatval == ctxt->context->proximityPosition);
11637
0
#endif
11638
146k
        case XPATH_NODESET:
11639
146k
        case XPATH_XSLT_TREE:
11640
146k
      if (res->nodesetval == NULL)
11641
0
    return(0);
11642
146k
      return(res->nodesetval->nodeNr != 0);
11643
4.38k
        case XPATH_STRING:
11644
4.38k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11645
0
        default:
11646
0
      break;
11647
254k
    }
11648
0
    return(0);
11649
254k
}
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
875k
{
11741
875k
    xmlXPathCompExprPtr comp = pctxt->comp;
11742
875k
    xmlXPathContextPtr ctxt;
11743
11744
    /*
11745
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11746
    * internal representation.
11747
    */
11748
11749
875k
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11750
240k
        (op->ch1 != -1) &&
11751
240k
        (op->ch2 == -1 /* no predicate */))
11752
233k
    {
11753
233k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11754
11755
233k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11756
18.6k
            ((xmlXPathAxisVal) prevop->value ==
11757
18.6k
                AXIS_DESCENDANT_OR_SELF) &&
11758
10.6k
            (prevop->ch2 == -1) &&
11759
10.6k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11760
10.6k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11761
10.6k
        {
11762
            /*
11763
            * This is a "descendant-or-self::node()" without predicates.
11764
            * Try to eliminate it.
11765
            */
11766
11767
10.6k
            switch ((xmlXPathAxisVal) op->value) {
11768
2.64k
                case AXIS_CHILD:
11769
2.64k
                case AXIS_DESCENDANT:
11770
                    /*
11771
                    * Convert "descendant-or-self::node()/child::" or
11772
                    * "descendant-or-self::node()/descendant::" to
11773
                    * "descendant::"
11774
                    */
11775
2.64k
                    op->ch1   = prevop->ch1;
11776
2.64k
                    op->value = AXIS_DESCENDANT;
11777
2.64k
                    break;
11778
0
                case AXIS_SELF:
11779
2.35k
                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
2.35k
                    op->ch1   = prevop->ch1;
11786
2.35k
                    op->value = AXIS_DESCENDANT_OR_SELF;
11787
2.35k
                    break;
11788
5.63k
                default:
11789
5.63k
                    break;
11790
10.6k
            }
11791
10.6k
  }
11792
233k
    }
11793
11794
    /* OP_VALUE has invalid ch1. */
11795
875k
    if (op->op == XPATH_OP_VALUE)
11796
58.3k
        return;
11797
11798
    /* Recurse */
11799
816k
    ctxt = pctxt->context;
11800
816k
    if (ctxt != NULL) {
11801
816k
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11802
335
            return;
11803
816k
        ctxt->depth += 1;
11804
816k
    }
11805
816k
    if (op->ch1 != -1)
11806
570k
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11807
816k
    if (op->ch2 != -1)
11808
291k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11809
816k
    if (ctxt != NULL)
11810
816k
        ctxt->depth -= 1;
11811
816k
}
11812
11813
/**
11814
 * Compile an XPath expression
11815
 *
11816
 * @param ctxt  an XPath context
11817
 * @param str  the XPath expression
11818
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11819
 *         the caller has to free the object.
11820
 */
11821
xmlXPathCompExpr *
11822
0
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11823
0
    xmlXPathParserContextPtr pctxt;
11824
0
    xmlXPathContextPtr tmpctxt = NULL;
11825
0
    xmlXPathCompExprPtr comp;
11826
0
    int oldDepth = 0;
11827
11828
0
    if (str == NULL)
11829
0
        return(NULL);
11830
11831
#ifdef XPATH_STREAMING
11832
    comp = xmlXPathTryStreamCompile(ctxt, str);
11833
    if (comp != NULL)
11834
        return(comp);
11835
#endif
11836
11837
0
    xmlInitParser();
11838
11839
    /*
11840
     * We need an xmlXPathContext for the depth check.
11841
     */
11842
0
    if (ctxt == NULL) {
11843
0
        tmpctxt = xmlXPathNewContext(NULL);
11844
0
        if (tmpctxt == NULL)
11845
0
            return(NULL);
11846
0
        ctxt = tmpctxt;
11847
0
    }
11848
11849
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
11850
0
    if (pctxt == NULL) {
11851
0
        if (tmpctxt != NULL)
11852
0
            xmlXPathFreeContext(tmpctxt);
11853
0
        return NULL;
11854
0
    }
11855
11856
0
    oldDepth = ctxt->depth;
11857
0
    xmlXPathCompileExpr(pctxt, 1);
11858
0
    ctxt->depth = oldDepth;
11859
11860
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
11861
0
    {
11862
0
        xmlXPathFreeParserContext(pctxt);
11863
0
        if (tmpctxt != NULL)
11864
0
            xmlXPathFreeContext(tmpctxt);
11865
0
        return(NULL);
11866
0
    }
11867
11868
0
    if (*pctxt->cur != 0) {
11869
  /*
11870
   * aleksey: in some cases this line prints *second* error message
11871
   * (see bug #78858) and probably this should be fixed.
11872
   * However, we are not sure that all error messages are printed
11873
   * out in other places. It's not critical so we leave it as-is for now
11874
   */
11875
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11876
0
  comp = NULL;
11877
0
    } else {
11878
0
  comp = pctxt->comp;
11879
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11880
0
            if (ctxt != NULL)
11881
0
                oldDepth = ctxt->depth;
11882
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11883
0
            if (ctxt != NULL)
11884
0
                ctxt->depth = oldDepth;
11885
0
  }
11886
0
  pctxt->comp = NULL;
11887
0
    }
11888
0
    xmlXPathFreeParserContext(pctxt);
11889
0
    if (tmpctxt != NULL)
11890
0
        xmlXPathFreeContext(tmpctxt);
11891
11892
0
    if (comp != NULL) {
11893
0
  comp->expr = xmlStrdup(str);
11894
0
    }
11895
0
    return(comp);
11896
0
}
11897
11898
/**
11899
 * Compile an XPath expression
11900
 *
11901
 * @param str  the XPath expression
11902
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11903
 *         the caller has to free the object.
11904
 */
11905
xmlXPathCompExpr *
11906
0
xmlXPathCompile(const xmlChar *str) {
11907
0
    return(xmlXPathCtxtCompile(NULL, str));
11908
0
}
11909
11910
/**
11911
 * Evaluate the Precompiled XPath expression in the given context.
11912
 * The caller has to free `resObj`.
11913
 *
11914
 * @param comp  the compiled XPath expression
11915
 * @param ctxt  the XPath context
11916
 * @param resObjPtr  the resulting XPath object or NULL
11917
 * @param toBool  1 if only a boolean result is requested
11918
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11919
 *         the caller has to free the object.
11920
 */
11921
static int
11922
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
11923
           xmlXPathContextPtr ctxt,
11924
           xmlXPathObjectPtr *resObjPtr,
11925
           int toBool)
11926
0
{
11927
0
    xmlXPathParserContextPtr pctxt;
11928
0
    xmlXPathObjectPtr resObj = NULL;
11929
0
    int res;
11930
11931
0
    if (comp == NULL)
11932
0
  return(-1);
11933
0
    xmlInitParser();
11934
11935
0
    xmlResetError(&ctxt->lastError);
11936
11937
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11938
0
    if (pctxt == NULL)
11939
0
        return(-1);
11940
0
    res = xmlXPathRunEval(pctxt, toBool);
11941
11942
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11943
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11944
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11945
0
        else if (!toBool)
11946
0
            resObj = xmlXPathValuePop(pctxt);
11947
0
    }
11948
11949
0
    if (resObjPtr)
11950
0
        *resObjPtr = resObj;
11951
0
    else
11952
0
        xmlXPathReleaseObject(ctxt, resObj);
11953
11954
0
    pctxt->comp = NULL;
11955
0
    xmlXPathFreeParserContext(pctxt);
11956
11957
0
    return(res);
11958
0
}
11959
11960
/**
11961
 * Evaluate the Precompiled XPath expression in the given context.
11962
 *
11963
 * @param comp  the compiled XPath expression
11964
 * @param ctx  the XPath context
11965
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11966
 *         the caller has to free the object.
11967
 */
11968
xmlXPathObject *
11969
xmlXPathCompiledEval(xmlXPathCompExpr *comp, xmlXPathContext *ctx)
11970
0
{
11971
0
    xmlXPathObjectPtr res = NULL;
11972
11973
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11974
0
    return(res);
11975
0
}
11976
11977
/**
11978
 * Applies the XPath boolean() function on the result of the given
11979
 * compiled expression.
11980
 *
11981
 * @param comp  the compiled XPath expression
11982
 * @param ctxt  the XPath context
11983
 * @returns 1 if the expression evaluated to true, 0 if to false and
11984
 *         -1 in API and internal errors.
11985
 */
11986
int
11987
xmlXPathCompiledEvalToBoolean(xmlXPathCompExpr *comp,
11988
            xmlXPathContext *ctxt)
11989
0
{
11990
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
11991
0
}
11992
11993
/**
11994
 * Parse and evaluate an XPath expression in the given context,
11995
 * then push the result on the context stack
11996
 *
11997
 * @deprecated Internal function, don't use.
11998
 *
11999
 * @param ctxt  the XPath Parser context
12000
 */
12001
void
12002
16.1k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
12003
#ifdef XPATH_STREAMING
12004
    xmlXPathCompExprPtr comp;
12005
#endif
12006
16.1k
    int oldDepth = 0;
12007
12008
16.1k
    if ((ctxt == NULL) || (ctxt->context == NULL))
12009
0
        return;
12010
16.1k
    if (ctxt->context->lastError.code != 0)
12011
206
        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
15.9k
    {
12027
15.9k
        if (ctxt->context != NULL)
12028
15.9k
            oldDepth = ctxt->context->depth;
12029
15.9k
  xmlXPathCompileExpr(ctxt, 1);
12030
15.9k
        if (ctxt->context != NULL)
12031
15.9k
            ctxt->context->depth = oldDepth;
12032
15.9k
        CHECK_ERROR;
12033
12034
        /* Check for trailing characters. */
12035
14.0k
        if (*ctxt->cur != 0)
12036
13.6k
            XP_ERROR(XPATH_EXPR_ERROR);
12037
12038
13.6k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12039
13.6k
            if (ctxt->context != NULL)
12040
13.6k
                oldDepth = ctxt->context->depth;
12041
13.6k
      xmlXPathOptimizeExpression(ctxt,
12042
13.6k
    &ctxt->comp->steps[ctxt->comp->last]);
12043
13.6k
            if (ctxt->context != NULL)
12044
13.6k
                ctxt->context->depth = oldDepth;
12045
13.6k
        }
12046
13.6k
    }
12047
12048
0
    xmlXPathRunEval(ctxt, 0);
12049
13.6k
}
12050
12051
/**
12052
 * Evaluate the XPath Location Path in the given context.
12053
 *
12054
 * @param str  the XPath expression
12055
 * @param ctx  the XPath context
12056
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12057
 *         the caller has to free the object.
12058
 */
12059
xmlXPathObject *
12060
0
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12061
0
    xmlXPathParserContextPtr ctxt;
12062
0
    xmlXPathObjectPtr res;
12063
12064
0
    if (ctx == NULL)
12065
0
        return(NULL);
12066
12067
0
    xmlInitParser();
12068
12069
0
    xmlResetError(&ctx->lastError);
12070
12071
0
    ctxt = xmlXPathNewParserContext(str, ctx);
12072
0
    if (ctxt == NULL)
12073
0
        return NULL;
12074
0
    xmlXPathEvalExpr(ctxt);
12075
12076
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12077
0
  res = NULL;
12078
0
    } else if (ctxt->valueNr != 1) {
12079
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12080
0
  res = NULL;
12081
0
    } else {
12082
0
  res = xmlXPathValuePop(ctxt);
12083
0
    }
12084
12085
0
    xmlXPathFreeParserContext(ctxt);
12086
0
    return(res);
12087
0
}
12088
12089
/**
12090
 * Sets 'node' as the context node. The node must be in the same
12091
 * document as that associated with the context.
12092
 *
12093
 * @param node  the node to to use as the context node
12094
 * @param ctx  the XPath context
12095
 * @returns -1 in case of error or 0 if successful
12096
 */
12097
int
12098
0
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12099
0
    if ((node == NULL) || (ctx == NULL))
12100
0
        return(-1);
12101
12102
0
    if (node->doc == ctx->doc) {
12103
0
        ctx->node = node;
12104
0
  return(0);
12105
0
    }
12106
0
    return(-1);
12107
0
}
12108
12109
/**
12110
 * Evaluate the XPath Location Path in the given context. The node 'node'
12111
 * is set as the context node. The context node is not restored.
12112
 *
12113
 * @param node  the node to to use as the context node
12114
 * @param str  the XPath expression
12115
 * @param ctx  the XPath context
12116
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12117
 *         the caller has to free the object.
12118
 */
12119
xmlXPathObject *
12120
0
xmlXPathNodeEval(xmlNode *node, const xmlChar *str, xmlXPathContext *ctx) {
12121
0
    if (str == NULL)
12122
0
        return(NULL);
12123
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
12124
0
        return(NULL);
12125
0
    return(xmlXPathEval(str, ctx));
12126
0
}
12127
12128
/**
12129
 * Alias for #xmlXPathEval.
12130
 *
12131
 * @param str  the XPath expression
12132
 * @param ctxt  the XPath context
12133
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12134
 *         the caller has to free the object.
12135
 */
12136
xmlXPathObject *
12137
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12138
0
    return(xmlXPathEval(str, ctxt));
12139
0
}
12140
12141
/**
12142
 * Registers all default XPath functions in this context
12143
 *
12144
 * @deprecated No-op since 2.14.0.
12145
 *
12146
 * @param ctxt  the XPath context
12147
 */
12148
void
12149
xmlXPathRegisterAllFunctions(xmlXPathContext *ctxt ATTRIBUTE_UNUSED)
12150
0
{
12151
0
}
12152
12153
#endif /* LIBXML_XPATH_ENABLED */