Coverage Report

Created: 2026-09-18 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxml2/xpath.c
Line
Count
Source
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: Daniel Veillard
14
 */
15
16
/* To avoid EBCDIC trouble when parsing on zOS */
17
#if defined(__MVS__)
18
#pragma convert("ISO8859-1")
19
#endif
20
21
#define IN_LIBXML
22
#include "libxml.h"
23
24
#include <limits.h>
25
#include <string.h>
26
#include <stddef.h>
27
#include <math.h>
28
#include <float.h>
29
#include <ctype.h>
30
31
#include <libxml/xmlmemory.h>
32
#include <libxml/tree.h>
33
#include <libxml/xpath.h>
34
#include <libxml/xpathInternals.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/hash.h>
37
#ifdef LIBXML_DEBUG_ENABLED
38
#include <libxml/debugXML.h>
39
#endif
40
#include <libxml/xmlerror.h>
41
#include <libxml/threads.h>
42
#ifdef LIBXML_PATTERN_ENABLED
43
#include <libxml/pattern.h>
44
#endif
45
46
#include "private/buf.h"
47
#include "private/error.h"
48
#include "private/memory.h"
49
#include "private/parser.h"
50
#include "private/xpath.h"
51
52
/* Disabled for now */
53
#if 0
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
#endif
58
59
/**
60
 * Use the Timsort algorithm provided in timsort.h to sort
61
 * nodeset as this is a great improvement over the old Shell sort
62
 * used in #xmlXPathNodeSetSort
63
 */
64
#define WITH_TIM_SORT
65
66
/*
67
* If defined, this will use xmlXPathCmpNodesExt() instead of
68
* xmlXPathCmpNodes(). The new function is optimized comparison of
69
* non-element nodes; actually it will speed up comparison only if
70
* xmlXPathOrderDocElems() was called in order to index the elements of
71
* a tree in document order; Libxslt does such an indexing, thus it will
72
* benefit from this optimization.
73
*/
74
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
75
76
/*
77
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
78
* in a way, that it stop evaluation at the first node.
79
*/
80
#define XP_OPTIMIZED_FILTER_FIRST
81
82
/*
83
 * when compiling an XPath expression we arbitrary limit the maximum
84
 * number of step operation in the compiled expression. 1000000 is
85
 * an insanely large value which should never be reached under normal
86
 * circumstances
87
 */
88
53.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
1.74k
#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.68M
#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
51.0M
#define XPATH_MAX_RECURSION_DEPTH 500
113
#elif defined(_WIN32)
114
/* Windows typically limits stack size to 1MB. */
115
#define XPATH_MAX_RECURSION_DEPTH 1000
116
#else
117
#define XPATH_MAX_RECURSION_DEPTH 5000
118
#endif
119
120
/*
121
 * TODO:
122
 * There are a few spots where some tests are done which depend upon ascii
123
 * data.  These should be enhanced for full UTF8 support (see particularly
124
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
125
 */
126
127
#if defined(LIBXML_XPATH_ENABLED)
128
129
static void
130
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
131
132
static const struct {
133
    const char *name;
134
    xmlXPathFunction func;
135
} xmlXPathStandardFunctions[] = {
136
    { "boolean", xmlXPathBooleanFunction },
137
    { "ceiling", xmlXPathCeilingFunction },
138
    { "count", xmlXPathCountFunction },
139
    { "concat", xmlXPathConcatFunction },
140
    { "contains", xmlXPathContainsFunction },
141
    { "id", xmlXPathIdFunction },
142
    { "false", xmlXPathFalseFunction },
143
    { "floor", xmlXPathFloorFunction },
144
    { "last", xmlXPathLastFunction },
145
    { "lang", xmlXPathLangFunction },
146
    { "local-name", xmlXPathLocalNameFunction },
147
    { "not", xmlXPathNotFunction },
148
    { "name", xmlXPathNameFunction },
149
    { "namespace-uri", xmlXPathNamespaceURIFunction },
150
    { "normalize-space", xmlXPathNormalizeFunction },
151
    { "number", xmlXPathNumberFunction },
152
    { "position", xmlXPathPositionFunction },
153
    { "round", xmlXPathRoundFunction },
154
    { "string", xmlXPathStringFunction },
155
    { "string-length", xmlXPathStringLengthFunction },
156
    { "starts-with", xmlXPathStartsWithFunction },
157
    { "substring", xmlXPathSubstringFunction },
158
    { "substring-before", xmlXPathSubstringBeforeFunction },
159
    { "substring-after", xmlXPathSubstringAfterFunction },
160
    { "sum", xmlXPathSumFunction },
161
    { "true", xmlXPathTrueFunction },
162
    { "translate", xmlXPathTranslateFunction }
163
};
164
165
#define NUM_STANDARD_FUNCTIONS \
166
28
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
8.78k
#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
7.15k
xmlXPathSFComputeHash(const xmlChar *name) {
187
7.15k
    unsigned hashValue = 5381;
188
7.15k
    const xmlChar *ptr;
189
190
36.0k
    for (ptr = name; *ptr; ptr++)
191
28.8k
        hashValue = hashValue * 33 + *ptr;
192
193
7.15k
    return(hashValue);
194
7.15k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
1
xmlInitXPathInternal(void) {
202
1
    size_t i;
203
204
1
#if defined(NAN) && defined(INFINITY)
205
1
    xmlXPathNAN = NAN;
206
1
    xmlXPathPINF = INFINITY;
207
1
    xmlXPathNINF = -INFINITY;
208
#else
209
    /* MSVC doesn't allow division by zero in constant expressions. */
210
    double zero = 0.0;
211
    xmlXPathNAN = 0.0 / zero;
212
    xmlXPathPINF = 1.0 / zero;
213
    xmlXPathNINF = -xmlXPathPINF;
214
#endif
215
216
    /*
217
     * Initialize hash table for standard functions
218
     */
219
220
65
    for (i = 0; i < SF_HASH_SIZE; i++)
221
64
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
28
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
27
        const char *name = xmlXPathStandardFunctions[i].name;
225
27
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
34
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
7
            bucketIndex += 1;
229
7
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
7
        }
232
233
27
        xmlXPathSFHash[bucketIndex] = i;
234
27
    }
235
1
}
236
237
/************************************************************************
238
 *                  *
239
 *      Floating point stuff        *
240
 *                  *
241
 ************************************************************************/
242
243
/**
244
 * Checks whether a double is a NaN.
245
 *
246
 * @param val  a double value
247
 * @returns 1 if the value is a NaN, 0 otherwise
248
 */
249
int
250
254k
xmlXPathIsNaN(double val) {
251
254k
#ifdef isnan
252
254k
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
254k
}
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
47.9k
xmlXPathIsInf(double val) {
266
47.9k
#ifdef isinf
267
47.9k
    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
47.9k
}
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
30.5M
#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
19.6M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
19.6M
    int depth1, depth2;
311
19.6M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
19.6M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
19.6M
    xmlNodePtr cur, root;
314
19.6M
    XML_INTPTR_T l1, l2;
315
316
19.6M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
19.6M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
19.6M
    switch (node1->type) {
326
18.9M
  case XML_ELEMENT_NODE:
327
18.9M
      if (node2->type == XML_ELEMENT_NODE) {
328
18.5M
    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
18.5M
        goto turtle_comparison;
340
18.5M
      }
341
384k
      break;
342
384k
  case XML_ATTRIBUTE_NODE:
343
26.1k
      precedence1 = 1; /* element is owner */
344
26.1k
      miscNode1 = node1;
345
26.1k
      node1 = node1->parent;
346
26.1k
      misc = 1;
347
26.1k
      break;
348
532k
  case XML_TEXT_NODE:
349
534k
  case XML_CDATA_SECTION_NODE:
350
534k
  case XML_COMMENT_NODE:
351
684k
  case XML_PI_NODE: {
352
684k
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
684k
      if (node1->prev != NULL) {
357
437M
    do {
358
437M
        node1 = node1->prev;
359
437M
        if (node1->type == XML_ELEMENT_NODE) {
360
535k
      precedence1 = 3; /* element in prev-sibl axis */
361
535k
      break;
362
535k
        }
363
436M
        if (node1->prev == NULL) {
364
111k
      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
111k
      node1 = node1->parent;
370
111k
      break;
371
111k
        }
372
436M
    } while (1);
373
647k
      } else {
374
36.8k
    precedence1 = 2; /* element is parent */
375
36.8k
    node1 = node1->parent;
376
36.8k
      }
377
684k
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
684k
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
684k
    node1 = miscNode1;
383
684k
    precedence1 = 0;
384
684k
      } else
385
0
    misc = 1;
386
684k
  }
387
684k
      break;
388
0
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
0
      return(1);
393
2.25k
  default:
394
2.25k
      break;
395
19.6M
    }
396
1.09M
    switch (node2->type) {
397
236k
  case XML_ELEMENT_NODE:
398
236k
      break;
399
38.4k
  case XML_ATTRIBUTE_NODE:
400
38.4k
      precedence2 = 1; /* element is owner */
401
38.4k
      miscNode2 = node2;
402
38.4k
      node2 = node2->parent;
403
38.4k
      misc = 1;
404
38.4k
      break;
405
624k
  case XML_TEXT_NODE:
406
627k
  case XML_CDATA_SECTION_NODE:
407
627k
  case XML_COMMENT_NODE:
408
817k
  case XML_PI_NODE: {
409
817k
      miscNode2 = node2;
410
817k
      if (node2->prev != NULL) {
411
576M
    do {
412
576M
        node2 = node2->prev;
413
576M
        if (node2->type == XML_ELEMENT_NODE) {
414
408k
      precedence2 = 3; /* element in prev-sibl axis */
415
408k
      break;
416
408k
        }
417
575M
        if (node2->prev == NULL) {
418
153k
      precedence2 = 2; /* element is parent */
419
153k
      node2 = node2->parent;
420
153k
      break;
421
153k
        }
422
575M
    } while (1);
423
562k
      } else {
424
255k
    precedence2 = 2; /* element is parent */
425
255k
    node2 = node2->parent;
426
255k
      }
427
817k
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
816k
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
817k
      {
430
817k
    node2 = miscNode2;
431
817k
    precedence2 = 0;
432
817k
      } else
433
0
    misc = 1;
434
817k
  }
435
817k
      break;
436
0
  case XML_NAMESPACE_DECL:
437
0
      return(1);
438
4.41k
  default:
439
4.41k
      break;
440
1.09M
    }
441
1.09M
    if (misc) {
442
50.2k
  if (node1 == node2) {
443
9.98k
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
7.42k
    cur = miscNode2->prev;
449
7.91k
    while (cur != NULL) {
450
7.53k
        if (cur == miscNode1)
451
7.03k
      return(1);
452
495
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
495
        cur = cur->prev;
455
495
    }
456
384
    return (-1);
457
7.42k
      } 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
2.56k
    if (precedence1 < precedence2)
464
1.93k
        return(1);
465
621
    else
466
621
        return(-1);
467
2.56k
      }
468
9.98k
  }
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
40.3k
  if ((precedence2 == 3) && (precedence1 > 1)) {
479
0
      cur = node1->parent;
480
0
      while (cur) {
481
0
    if (cur == node2)
482
0
        return(1);
483
0
    cur = cur->parent;
484
0
      }
485
0
  }
486
40.3k
  if ((precedence1 == 3) && (precedence2 > 1)) {
487
0
      cur = node2->parent;
488
0
      while (cur) {
489
0
    if (cur == node1)
490
0
        return(-1);
491
0
    cur = cur->parent;
492
0
      }
493
0
  }
494
40.3k
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
1.08M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
400k
  (node2->type == XML_ELEMENT_NODE) &&
501
22.6k
  (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
19.6M
turtle_comparison:
514
515
19.6M
    if (node1 == node2->prev)
516
3.06M
  return(1);
517
16.5M
    if (node1 == node2->next)
518
735k
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
117M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
103M
  if (cur->parent == node1)
524
1.87M
      return(1);
525
101M
  depth2++;
526
101M
    }
527
13.9M
    root = cur;
528
95.5M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
82.4M
  if (cur->parent == node2)
530
930k
      return(-1);
531
81.5M
  depth1++;
532
81.5M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
13.0M
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
18.5M
    while (depth1 > depth2) {
543
5.49M
  depth1--;
544
5.49M
  node1 = node1->parent;
545
5.49M
    }
546
25.2M
    while (depth2 > depth1) {
547
12.1M
  depth2--;
548
12.1M
  node2 = node2->parent;
549
12.1M
    }
550
14.6M
    while (node1->parent != node2->parent) {
551
1.55M
  node1 = node1->parent;
552
1.55M
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
1.55M
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
1.55M
    }
557
    /*
558
     * Find who's first.
559
     */
560
13.0M
    if (node1 == node2->prev)
561
826k
  return(1);
562
12.2M
    if (node1 == node2->next)
563
1.61M
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
10.6M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
10.5M
  (node2->type == XML_ELEMENT_NODE) &&
569
10.4M
  (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
499M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
493M
  if (cur == node2)
583
4.05M
      return(1);
584
6.55M
    return(-1); /* assume there is no sibling list corruption */
585
10.6M
}
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
2.35M
#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
19.6M
    {
607
19.6M
        int res = xmlXPathCmpNodesExt(x, y);
608
19.6M
        return res == -2 ? res : -res;
609
19.6M
    }
610
#else
611
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
612
    {
613
        int res = xmlXPathCmpNodes(x, y);
614
        return res == -2 ? res : -res;
615
    }
616
#endif
617
19.6M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
618
#include "timsort.h"
619
#endif /* WITH_TIM_SORT */
620
621
/************************************************************************
622
 *                  *
623
 *      Error handling routines       *
624
 *                  *
625
 ************************************************************************/
626
627
/**
628
 * Macro to raise an XPath error and return NULL.
629
 *
630
 * @param X  the error code
631
 */
632
#define XP_ERRORNULL(X)             \
633
307
    { xmlXPathErr(ctxt, X); return(NULL); }
634
635
/*
636
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
637
 */
638
static const char* const xmlXPathErrorMessages[] = {
639
    "Ok",
640
    "Number encoding",
641
    "Unfinished literal",
642
    "Start of literal",
643
    "Expected $ for variable reference",
644
    "Undefined variable",
645
    "Invalid predicate",
646
    "Invalid expression",
647
    "Missing closing curly brace",
648
    "Unregistered function",
649
    "Invalid operand",
650
    "Invalid type",
651
    "Invalid number of arguments",
652
    "Invalid context size",
653
    "Invalid context position",
654
    "Memory allocation error",
655
    "Syntax error",
656
    "Resource error",
657
    "Sub resource error",
658
    "Undefined namespace prefix",
659
    "Encoding error",
660
    "Char out of XML range",
661
    "Invalid or incomplete context",
662
    "Stack usage error",
663
    "Forbidden variable",
664
    "Operation limit exceeded",
665
    "Recursion limit exceeded",
666
    "?? Unknown error ??" /* Must be last in the list! */
667
};
668
13.4k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
13.4k
       sizeof(xmlXPathErrorMessages[0])) - 1)
670
/**
671
 * Handle a memory allocation failure.
672
 *
673
 * @param ctxt  an XPath context
674
 */
675
void
676
xmlXPathErrMemory(xmlXPathContext *ctxt)
677
41
{
678
41
    if (ctxt == NULL)
679
0
        return;
680
41
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
41
                        &ctxt->lastError);
682
41
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
41
{
692
41
    if (ctxt == NULL)
693
0
        return;
694
41
    ctxt->error = XPATH_MEMORY_ERROR;
695
41
    xmlXPathErrMemory(ctxt->context);
696
41
}
697
698
/**
699
 * Handle an XPath error
700
 *
701
 * @param ctxt  a XPath parser context
702
 * @param code  the error code
703
 * @param fmt  format string for error message
704
 * @param ...  extra args
705
 */
706
static void
707
13.4k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
13.4k
    va_list ap;
709
13.4k
    xmlStructuredErrorFunc schannel = NULL;
710
13.4k
    xmlGenericErrorFunc channel = NULL;
711
13.4k
    void *data = NULL;
712
13.4k
    xmlNodePtr node = NULL;
713
13.4k
    int res;
714
715
13.4k
    if (ctxt == NULL)
716
0
        return;
717
13.4k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
13.4k
    if (ctxt->error != 0)
721
9.76k
        return;
722
723
3.64k
    ctxt->error = code;
724
725
3.64k
    if (ctxt->context != NULL) {
726
3.64k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
3.64k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
3.64k
        xmlResetError(err);
734
735
3.64k
        err->domain = XML_FROM_XPATH;
736
3.64k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
3.64k
        err->level = XML_ERR_ERROR;
738
3.64k
        if (ctxt->base != NULL) {
739
3.64k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
3.64k
            if (err->str1 == NULL) {
741
0
                xmlXPathPErrMemory(ctxt);
742
0
                return;
743
0
            }
744
3.64k
        }
745
3.64k
        err->int1 = ctxt->cur - ctxt->base;
746
3.64k
        err->node = ctxt->context->debugNode;
747
748
3.64k
        schannel = ctxt->context->error;
749
3.64k
        data = ctxt->context->userData;
750
3.64k
        node = ctxt->context->debugNode;
751
3.64k
    }
752
753
3.64k
    if (schannel == NULL) {
754
3.64k
        channel = xmlGenericError;
755
3.64k
        data = xmlGenericErrorContext;
756
3.64k
    }
757
758
3.64k
    va_start(ap, fmt);
759
3.64k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
3.64k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
3.64k
                         XML_ERR_ERROR, NULL, 0,
762
3.64k
                         (const char *) ctxt->base, NULL, NULL,
763
3.64k
                         ctxt->cur - ctxt->base, 0,
764
3.64k
                         fmt, ap);
765
3.64k
    va_end(ap);
766
3.64k
    if (res < 0)
767
0
        xmlXPathPErrMemory(ctxt);
768
3.64k
}
769
770
/**
771
 * Handle an XPath error
772
 *
773
 * @param ctxt  a XPath parser context
774
 * @param code  the error code
775
 */
776
void
777
13.0k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
13.0k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
13.0k
}
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
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
0
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
0
    if ((opCount > xpctxt->opLimit) ||
807
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
0
        xpctxt->opCount = xpctxt->opLimit;
809
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
0
        return(-1);
811
0
    }
812
813
0
    xpctxt->opCount += opCount;
814
0
    return(0);
815
0
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
119M
    ((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
8.21k
xmlXPathNewCompExpr(void) {
941
8.21k
    xmlXPathCompExprPtr cur;
942
943
8.21k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
8.21k
    if (cur == NULL)
945
0
  return(NULL);
946
8.21k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
8.21k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
8.21k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
8.21k
    cur->nbStep = 0;
953
8.21k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
8.21k
                                     sizeof(xmlXPathStepOp));
955
8.21k
    if (cur->steps == NULL) {
956
0
  xmlFree(cur);
957
0
  return(NULL);
958
0
    }
959
8.21k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
8.21k
    cur->last = -1;
961
8.21k
    return(cur);
962
8.21k
}
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
8.21k
{
972
8.21k
    xmlXPathStepOpPtr op;
973
8.21k
    int i;
974
975
8.21k
    if (comp == NULL)
976
0
        return;
977
8.21k
    if (comp->dict == NULL) {
978
15.3M
  for (i = 0; i < comp->nbStep; i++) {
979
15.3M
      op = &comp->steps[i];
980
15.3M
      if (op->value4 != NULL) {
981
133k
    if (op->op == XPATH_OP_VALUE)
982
122k
        xmlXPathFreeObject(op->value4);
983
11.3k
    else
984
11.3k
        xmlFree(op->value4);
985
133k
      }
986
15.3M
      if (op->value5 != NULL)
987
105k
    xmlFree(op->value5);
988
15.3M
  }
989
8.21k
    } 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
8.21k
    if (comp->steps != NULL) {
1000
8.21k
        xmlFree(comp->steps);
1001
8.21k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
8.21k
    if (comp->expr != NULL) {
1008
0
        xmlFree(comp->expr);
1009
0
    }
1010
1011
8.21k
    xmlFree(comp);
1012
8.21k
}
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
15.3M
   int value2, int value3, void *value4, void *value5) {
1032
15.3M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
15.3M
    if (comp->nbStep >= comp->maxStep) {
1034
53.1k
  xmlXPathStepOp *real;
1035
53.1k
        int newSize;
1036
1037
53.1k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
53.1k
                                  10, XPATH_MAX_STEPS);
1039
53.1k
        if (newSize < 0) {
1040
41
      xmlXPathPErrMemory(ctxt);
1041
41
      return(-1);
1042
41
        }
1043
53.0k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
53.0k
  if (real == NULL) {
1045
0
      xmlXPathPErrMemory(ctxt);
1046
0
      return(-1);
1047
0
  }
1048
53.0k
  comp->steps = real;
1049
53.0k
  comp->maxStep = newSize;
1050
53.0k
    }
1051
15.3M
    comp->last = comp->nbStep;
1052
15.3M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
15.3M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
15.3M
    comp->steps[comp->nbStep].op = op;
1055
15.3M
    comp->steps[comp->nbStep].value = value;
1056
15.3M
    comp->steps[comp->nbStep].value2 = value2;
1057
15.3M
    comp->steps[comp->nbStep].value3 = value3;
1058
15.3M
    if ((comp->dict != NULL) &&
1059
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
0
   (op == XPATH_OP_COLLECT))) {
1061
0
        if (value4 != NULL) {
1062
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
0
      xmlFree(value4);
1065
0
  } else
1066
0
      comp->steps[comp->nbStep].value4 = NULL;
1067
0
        if (value5 != NULL) {
1068
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
0
      xmlFree(value5);
1071
0
  } else
1072
0
      comp->steps[comp->nbStep].value5 = NULL;
1073
15.3M
    } else {
1074
15.3M
  comp->steps[comp->nbStep].value4 = value4;
1075
15.3M
  comp->steps[comp->nbStep].value5 = value5;
1076
15.3M
    }
1077
15.3M
    comp->steps[comp->nbStep].cache = NULL;
1078
15.3M
    return(comp->nbStep++);
1079
15.3M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
4.97M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
4.97M
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
174k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
174k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
4.98M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
4.98M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
95.9k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
95.9k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
5.08M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
5.08M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
5.08M
      (val), (val2), 0 ,NULL ,NULL)
1097
1098
/************************************************************************
1099
 *                  *
1100
 *    XPath object cache structures       *
1101
 *                  *
1102
 ************************************************************************/
1103
1104
/* #define XP_DEFAULT_CACHE_ON */
1105
1106
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1107
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1108
struct _xmlXPathContextCache {
1109
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1110
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1111
    int numNodeset;
1112
    int maxNodeset;
1113
    int numMisc;
1114
    int maxMisc;
1115
};
1116
1117
/************************************************************************
1118
 *                  *
1119
 *    Debugging related functions       *
1120
 *                  *
1121
 ************************************************************************/
1122
1123
#ifdef LIBXML_DEBUG_ENABLED
1124
static void
1125
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1126
0
    int i;
1127
0
    char shift[100];
1128
1129
0
    for (i = 0;((i < depth) && (i < 25));i++)
1130
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
0
    if (cur == NULL) {
1133
0
  fprintf(output, "%s", shift);
1134
0
  fprintf(output, "Node is NULL !\n");
1135
0
  return;
1136
1137
0
    }
1138
1139
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1140
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1141
0
  fprintf(output, "%s", shift);
1142
0
  fprintf(output, " /\n");
1143
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1144
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1145
0
    else
1146
0
  xmlDebugDumpOneNode(output, cur, depth);
1147
0
}
1148
static void
1149
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1150
0
    xmlNodePtr tmp;
1151
0
    int i;
1152
0
    char shift[100];
1153
1154
0
    for (i = 0;((i < depth) && (i < 25));i++)
1155
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1156
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1157
0
    if (cur == NULL) {
1158
0
  fprintf(output, "%s", shift);
1159
0
  fprintf(output, "Node is NULL !\n");
1160
0
  return;
1161
1162
0
    }
1163
1164
0
    while (cur != NULL) {
1165
0
  tmp = cur;
1166
0
  cur = cur->next;
1167
0
  xmlDebugDumpOneNode(output, tmp, depth);
1168
0
    }
1169
0
}
1170
1171
static void
1172
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1173
0
    int i;
1174
0
    char shift[100];
1175
1176
0
    for (i = 0;((i < depth) && (i < 25));i++)
1177
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1178
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1179
1180
0
    if (cur == NULL) {
1181
0
  fprintf(output, "%s", shift);
1182
0
  fprintf(output, "NodeSet is NULL !\n");
1183
0
  return;
1184
1185
0
    }
1186
1187
0
    if (cur != NULL) {
1188
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1189
0
  for (i = 0;i < cur->nodeNr;i++) {
1190
0
      fprintf(output, "%s", shift);
1191
0
      fprintf(output, "%d", i + 1);
1192
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1193
0
  }
1194
0
    }
1195
0
}
1196
1197
static void
1198
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1199
0
    int i;
1200
0
    char shift[100];
1201
1202
0
    for (i = 0;((i < depth) && (i < 25));i++)
1203
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1204
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1205
1206
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1207
0
  fprintf(output, "%s", shift);
1208
0
  fprintf(output, "Value Tree is NULL !\n");
1209
0
  return;
1210
1211
0
    }
1212
1213
0
    fprintf(output, "%s", shift);
1214
0
    fprintf(output, "%d", i + 1);
1215
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1216
0
}
1217
1218
/**
1219
 * Dump the content of the object for debugging purposes
1220
 *
1221
 * @param output  the FILE * to dump the output
1222
 * @param cur  the object to inspect
1223
 * @param depth  indentation level
1224
 */
1225
void
1226
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1227
0
    int i;
1228
0
    char shift[100];
1229
1230
0
    if (output == NULL) return;
1231
1232
0
    for (i = 0;((i < depth) && (i < 25));i++)
1233
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
0
    fprintf(output, "%s", shift);
1238
1239
0
    if (cur == NULL) {
1240
0
        fprintf(output, "Object is empty (NULL)\n");
1241
0
  return;
1242
0
    }
1243
0
    switch(cur->type) {
1244
0
        case XPATH_UNDEFINED:
1245
0
      fprintf(output, "Object is uninitialized\n");
1246
0
      break;
1247
0
        case XPATH_NODESET:
1248
0
      fprintf(output, "Object is a Node Set :\n");
1249
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
0
      break;
1251
0
  case XPATH_XSLT_TREE:
1252
0
      fprintf(output, "Object is an XSLT value tree :\n");
1253
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
0
      break;
1255
0
        case XPATH_BOOLEAN:
1256
0
      fprintf(output, "Object is a Boolean : ");
1257
0
      if (cur->boolval) fprintf(output, "true\n");
1258
0
      else fprintf(output, "false\n");
1259
0
      break;
1260
0
        case XPATH_NUMBER:
1261
0
      switch (xmlXPathIsInf(cur->floatval)) {
1262
0
      case 1:
1263
0
    fprintf(output, "Object is a number : Infinity\n");
1264
0
    break;
1265
0
      case -1:
1266
0
    fprintf(output, "Object is a number : -Infinity\n");
1267
0
    break;
1268
0
      default:
1269
0
    if (xmlXPathIsNaN(cur->floatval)) {
1270
0
        fprintf(output, "Object is a number : NaN\n");
1271
0
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
0
        fprintf(output, "Object is a number : 0\n");
1274
0
    } else {
1275
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
0
    }
1277
0
      }
1278
0
      break;
1279
0
        case XPATH_STRING:
1280
0
      fprintf(output, "Object is a string : ");
1281
0
      xmlDebugDumpString(output, cur->stringval);
1282
0
      fprintf(output, "\n");
1283
0
      break;
1284
0
  case XPATH_USERS:
1285
0
      fprintf(output, "Object is user defined\n");
1286
0
      break;
1287
0
    }
1288
0
}
1289
1290
static void
1291
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1292
0
                       xmlXPathStepOpPtr op, int depth) {
1293
0
    int i;
1294
0
    char shift[100];
1295
1296
0
    for (i = 0;((i < depth) && (i < 25));i++)
1297
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1298
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300
0
    fprintf(output, "%s", shift);
1301
0
    if (op == NULL) {
1302
0
  fprintf(output, "Step is NULL\n");
1303
0
  return;
1304
0
    }
1305
0
    switch (op->op) {
1306
0
        case XPATH_OP_END:
1307
0
      fprintf(output, "END"); break;
1308
0
        case XPATH_OP_AND:
1309
0
      fprintf(output, "AND"); break;
1310
0
        case XPATH_OP_OR:
1311
0
      fprintf(output, "OR"); break;
1312
0
        case XPATH_OP_EQUAL:
1313
0
       if (op->value)
1314
0
     fprintf(output, "EQUAL =");
1315
0
       else
1316
0
     fprintf(output, "EQUAL !=");
1317
0
       break;
1318
0
        case XPATH_OP_CMP:
1319
0
       if (op->value)
1320
0
     fprintf(output, "CMP <");
1321
0
       else
1322
0
     fprintf(output, "CMP >");
1323
0
       if (!op->value2)
1324
0
     fprintf(output, "=");
1325
0
       break;
1326
0
        case XPATH_OP_PLUS:
1327
0
       if (op->value == 0)
1328
0
     fprintf(output, "PLUS -");
1329
0
       else if (op->value == 1)
1330
0
     fprintf(output, "PLUS +");
1331
0
       else if (op->value == 2)
1332
0
     fprintf(output, "PLUS unary -");
1333
0
       else if (op->value == 3)
1334
0
     fprintf(output, "PLUS unary - -");
1335
0
       break;
1336
0
        case XPATH_OP_MULT:
1337
0
       if (op->value == 0)
1338
0
     fprintf(output, "MULT *");
1339
0
       else if (op->value == 1)
1340
0
     fprintf(output, "MULT div");
1341
0
       else
1342
0
     fprintf(output, "MULT mod");
1343
0
       break;
1344
0
        case XPATH_OP_UNION:
1345
0
       fprintf(output, "UNION"); break;
1346
0
        case XPATH_OP_ROOT:
1347
0
       fprintf(output, "ROOT"); break;
1348
0
        case XPATH_OP_NODE:
1349
0
       fprintf(output, "NODE"); break;
1350
0
        case XPATH_OP_SORT:
1351
0
       fprintf(output, "SORT"); break;
1352
0
        case XPATH_OP_COLLECT: {
1353
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1354
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1355
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1356
0
      const xmlChar *prefix = op->value4;
1357
0
      const xmlChar *name = op->value5;
1358
1359
0
      fprintf(output, "COLLECT ");
1360
0
      switch (axis) {
1361
0
    case AXIS_ANCESTOR:
1362
0
        fprintf(output, " 'ancestors' "); break;
1363
0
    case AXIS_ANCESTOR_OR_SELF:
1364
0
        fprintf(output, " 'ancestors-or-self' "); break;
1365
0
    case AXIS_ATTRIBUTE:
1366
0
        fprintf(output, " 'attributes' "); break;
1367
0
    case AXIS_CHILD:
1368
0
        fprintf(output, " 'child' "); break;
1369
0
    case AXIS_DESCENDANT:
1370
0
        fprintf(output, " 'descendant' "); break;
1371
0
    case AXIS_DESCENDANT_OR_SELF:
1372
0
        fprintf(output, " 'descendant-or-self' "); break;
1373
0
    case AXIS_FOLLOWING:
1374
0
        fprintf(output, " 'following' "); break;
1375
0
    case AXIS_FOLLOWING_SIBLING:
1376
0
        fprintf(output, " 'following-siblings' "); break;
1377
0
    case AXIS_NAMESPACE:
1378
0
        fprintf(output, " 'namespace' "); break;
1379
0
    case AXIS_PARENT:
1380
0
        fprintf(output, " 'parent' "); break;
1381
0
    case AXIS_PRECEDING:
1382
0
        fprintf(output, " 'preceding' "); break;
1383
0
    case AXIS_PRECEDING_SIBLING:
1384
0
        fprintf(output, " 'preceding-sibling' "); break;
1385
0
    case AXIS_SELF:
1386
0
        fprintf(output, " 'self' "); break;
1387
0
      }
1388
0
      switch (test) {
1389
0
                case NODE_TEST_NONE:
1390
0
        fprintf(output, "'none' "); break;
1391
0
                case NODE_TEST_TYPE:
1392
0
        fprintf(output, "'type' "); break;
1393
0
                case NODE_TEST_PI:
1394
0
        fprintf(output, "'PI' "); break;
1395
0
                case NODE_TEST_ALL:
1396
0
        fprintf(output, "'all' "); break;
1397
0
                case NODE_TEST_NS:
1398
0
        fprintf(output, "'namespace' "); break;
1399
0
                case NODE_TEST_NAME:
1400
0
        fprintf(output, "'name' "); break;
1401
0
      }
1402
0
      switch (type) {
1403
0
                case NODE_TYPE_NODE:
1404
0
        fprintf(output, "'node' "); break;
1405
0
                case NODE_TYPE_COMMENT:
1406
0
        fprintf(output, "'comment' "); break;
1407
0
                case NODE_TYPE_TEXT:
1408
0
        fprintf(output, "'text' "); break;
1409
0
                case NODE_TYPE_PI:
1410
0
        fprintf(output, "'PI' "); break;
1411
0
      }
1412
0
      if (prefix != NULL)
1413
0
    fprintf(output, "%s:", prefix);
1414
0
      if (name != NULL)
1415
0
    fprintf(output, "%s", (const char *) name);
1416
0
      break;
1417
1418
0
        }
1419
0
  case XPATH_OP_VALUE: {
1420
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1421
1422
0
      fprintf(output, "ELEM ");
1423
0
      xmlXPathDebugDumpObject(output, object, 0);
1424
0
      goto finish;
1425
0
  }
1426
0
  case XPATH_OP_VARIABLE: {
1427
0
      const xmlChar *prefix = op->value5;
1428
0
      const xmlChar *name = op->value4;
1429
1430
0
      if (prefix != NULL)
1431
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1432
0
      else
1433
0
    fprintf(output, "VARIABLE %s", name);
1434
0
      break;
1435
0
  }
1436
0
  case XPATH_OP_FUNCTION: {
1437
0
      int nbargs = op->value;
1438
0
      const xmlChar *prefix = op->value5;
1439
0
      const xmlChar *name = op->value4;
1440
1441
0
      if (prefix != NULL)
1442
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1443
0
      prefix, name, nbargs);
1444
0
      else
1445
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1446
0
      break;
1447
0
  }
1448
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1449
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1450
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1451
0
  default:
1452
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1453
0
    }
1454
0
    fprintf(output, "\n");
1455
0
finish:
1456
    /* OP_VALUE has invalid ch1. */
1457
0
    if (op->op == XPATH_OP_VALUE)
1458
0
        return;
1459
1460
0
    if (op->ch1 >= 0)
1461
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1462
0
    if (op->ch2 >= 0)
1463
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1464
0
}
1465
1466
/**
1467
 * Dumps the tree of the compiled XPath expression.
1468
 *
1469
 * @param output  the FILE * for the output
1470
 * @param comp  the precompiled XPath expression
1471
 * @param depth  the indentation level.
1472
 */
1473
void
1474
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExpr *comp,
1475
0
                    int depth) {
1476
0
    int i;
1477
0
    char shift[100];
1478
1479
0
    if ((output == NULL) || (comp == NULL)) return;
1480
1481
0
    for (i = 0;((i < depth) && (i < 25));i++)
1482
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1483
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1484
1485
0
    fprintf(output, "%s", shift);
1486
1487
#ifdef XPATH_STREAMING
1488
    if (comp->stream) {
1489
        fprintf(output, "Streaming Expression\n");
1490
    } else
1491
#endif
1492
0
    {
1493
0
        fprintf(output, "Compiled Expression : %d elements\n",
1494
0
                comp->nbStep);
1495
0
        i = comp->last;
1496
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1497
0
    }
1498
0
}
1499
1500
#endif /* LIBXML_DEBUG_ENABLED */
1501
1502
/************************************************************************
1503
 *                  *
1504
 *      XPath object caching        *
1505
 *                  *
1506
 ************************************************************************/
1507
1508
/**
1509
 * Create a new object cache
1510
 *
1511
 * @returns the xmlXPathCache just allocated.
1512
 */
1513
static xmlXPathContextCachePtr
1514
xmlXPathNewCache(void)
1515
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
16.8M
{
1621
16.8M
    xmlXPathObjectPtr ret;
1622
16.8M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
16.8M
    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
16.8M
    ret = xmlXPathWrapNodeSet(val);
1640
16.8M
    if (ret == NULL)
1641
0
        xmlXPathPErrMemory(pctxt);
1642
16.8M
    return(ret);
1643
16.8M
}
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
14.8k
{
1656
14.8k
    xmlXPathObjectPtr ret;
1657
14.8k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
14.8k
    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
14.8k
    ret = xmlXPathWrapString(val);
1673
14.8k
    if (ret == NULL)
1674
0
        xmlXPathPErrMemory(pctxt);
1675
14.8k
    return(ret);
1676
14.8k
}
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
17.1M
{
1690
17.1M
    xmlXPathObjectPtr ret;
1691
17.1M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
17.1M
    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
17.1M
    ret = xmlXPathNewNodeSet(val);
1741
17.1M
    if (ret == NULL)
1742
0
        xmlXPathPErrMemory(pctxt);
1743
17.1M
    return(ret);
1744
17.1M
}
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
61.3k
{
1757
61.3k
    xmlXPathObjectPtr ret;
1758
61.3k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
61.3k
    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
61.3k
    ret = xmlXPathNewString(val);
1784
61.3k
    if (ret == NULL)
1785
0
        xmlXPathPErrMemory(pctxt);
1786
61.3k
    return(ret);
1787
61.3k
}
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
802
{
1800
802
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
802
}
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
9.72M
{
1814
9.72M
    xmlXPathObjectPtr ret;
1815
9.72M
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
9.72M
    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
9.72M
    ret = xmlXPathNewBoolean(val);
1832
9.72M
    if (ret == NULL)
1833
0
        xmlXPathPErrMemory(pctxt);
1834
9.72M
    return(ret);
1835
9.72M
}
1836
1837
/**
1838
 * This is the cached version of #xmlXPathNewFloat.
1839
 * Acquires an xmlXPathObject of type double and of value `val`
1840
 *
1841
 * @param pctxt  the XPath context
1842
 * @param val  the double value
1843
 * @returns the created or reused object.
1844
 */
1845
static xmlXPathObjectPtr
1846
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1847
2.92M
{
1848
2.92M
    xmlXPathObjectPtr ret;
1849
2.92M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
2.92M
    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
2.92M
    ret = xmlXPathNewFloat(val);
1866
2.92M
    if (ret == NULL)
1867
0
        xmlXPathPErrMemory(pctxt);
1868
2.92M
    return(ret);
1869
2.92M
}
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
204k
{
1882
204k
    xmlXPathObjectPtr ret;
1883
204k
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
204k
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
204k
    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
204k
    ret = xmlXPathObjectCopy(val);
1911
204k
    if (ret == NULL)
1912
0
        xmlXPathPErrMemory(pctxt);
1913
204k
    return(ret);
1914
204k
}
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
6.53M
                             xmlXPathObjectPtr val) {
1932
6.53M
    double ret = 0.0;
1933
1934
6.53M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
6.53M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
6.41M
    case XPATH_NODESET:
1941
6.41M
    case XPATH_XSLT_TREE: {
1942
6.41M
        xmlChar *str;
1943
1944
6.41M
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
6.41M
        if (str == NULL) {
1946
0
            xmlXPathPErrMemory(ctxt);
1947
0
            ret = xmlXPathNAN;
1948
6.41M
        } else {
1949
6.41M
      ret = xmlXPathCastStringToNumber(str);
1950
6.41M
            xmlFree(str);
1951
6.41M
        }
1952
6.41M
  break;
1953
6.41M
    }
1954
52.7k
    case XPATH_STRING:
1955
52.7k
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
52.7k
  break;
1957
37.8k
    case XPATH_NUMBER:
1958
37.8k
  ret = val->floatval;
1959
37.8k
  break;
1960
26.7k
    case XPATH_BOOLEAN:
1961
26.7k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
26.7k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
6.53M
    }
1968
6.53M
    return(ret);
1969
6.53M
}
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
48.0M
{
1980
48.0M
    xmlXPathObjectPtr ret;
1981
1982
48.0M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
9.52k
        return (NULL);
1984
1985
48.0M
    ctxt->valueNr--;
1986
48.0M
    if (ctxt->valueNr > 0)
1987
47.9M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
74.5k
    else
1989
74.5k
        ctxt->value = NULL;
1990
48.0M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
48.0M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
48.0M
    return (ret);
1993
48.0M
}
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
48.0M
{
2008
48.0M
    if (ctxt == NULL) return(-1);
2009
48.0M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
0
        xmlXPathPErrMemory(ctxt);
2014
0
        return(-1);
2015
0
    }
2016
48.0M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
1.74k
        xmlXPathObjectPtr *tmp;
2018
1.74k
        int newSize;
2019
2020
1.74k
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
1.74k
                                  10, XPATH_MAX_STACK_DEPTH);
2022
1.74k
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
1.74k
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
1.74k
        if (tmp == NULL) {
2029
0
            xmlXPathPErrMemory(ctxt);
2030
0
            xmlXPathFreeObject(value);
2031
0
            return (-1);
2032
0
        }
2033
1.74k
  ctxt->valueTab = tmp;
2034
1.74k
        ctxt->valueMax = newSize;
2035
1.74k
    }
2036
48.0M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
48.0M
    ctxt->value = value;
2038
48.0M
    return (ctxt->valueNr++);
2039
48.0M
}
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
123M
#define CUR (*ctxt->cur)
2194
53.1k
#define SKIP(val) ctxt->cur += (val)
2195
1.33M
#define NXT(val) ctxt->cur[(val)]
2196
2.65M
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
62.1M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
52.7M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2203
2204
2205
#ifndef DBL_DIG
2206
#define DBL_DIG 16
2207
#endif
2208
#ifndef DBL_EPSILON
2209
#define DBL_EPSILON 1E-9
2210
#endif
2211
2212
384
#define UPPER_DOUBLE 1E9
2213
15
#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
370
#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
754
{
2230
754
    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
754
    default:
2240
754
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
754
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
754
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
385
                   (number == (int) number)) {
2248
370
      char work[30];
2249
370
      char *ptr, *cur;
2250
370
      int value = (int) number;
2251
2252
370
            ptr = &buffer[0];
2253
370
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
370
      } else {
2256
370
    snprintf(work, 29, "%d", value);
2257
370
    cur = &work[0];
2258
1.63k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
1.26k
        *ptr++ = *cur++;
2260
1.26k
    }
2261
370
      }
2262
370
      if (ptr - buffer < buffersize) {
2263
370
    *ptr = 0;
2264
370
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
384
  } 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
384
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
384
      int integer_place, fraction_place;
2280
384
      char *ptr;
2281
384
      char *after_fraction;
2282
384
      double absolute_value;
2283
384
      int size;
2284
2285
384
      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
384
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
15
      (absolute_value < LOWER_DOUBLE)) &&
2294
370
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
370
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
370
    fraction_place = DBL_DIG - 1;
2298
370
    size = snprintf(work, sizeof(work),"%*.*e",
2299
370
       integer_place, fraction_place, number);
2300
1.85k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
370
      }
2303
14
      else {
2304
    /* Use regular notation */
2305
14
    if (absolute_value > 0.0) {
2306
14
        integer_place = (int)log10(absolute_value);
2307
14
        if (integer_place > 0)
2308
13
            fraction_place = DBL_DIG - integer_place - 1;
2309
1
        else
2310
1
            fraction_place = DBL_DIG - integer_place;
2311
14
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
14
    size = snprintf(work, sizeof(work), "%0.*f",
2315
14
        fraction_place, number);
2316
14
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
665
      while (work[0] == ' ') {
2320
5.90k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
281
    size--;
2322
281
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
384
      after_fraction = work + size;
2326
384
      ptr = after_fraction;
2327
1.12k
      while (*(--ptr) == '0')
2328
739
    ;
2329
384
      if (*ptr != '.')
2330
353
          ptr++;
2331
1.86k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
384
      size = strlen(work) + 1;
2335
384
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
384
      memmove(buffer, work, size);
2340
384
  }
2341
754
  break;
2342
754
    }
2343
754
}
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
43.3k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
43.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
43.3k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
43.3k
#endif /* WITH_TIM_SORT */
2591
43.3k
}
2592
2593
53.4M
#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
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
0
    xmlNsPtr cur;
2606
2607
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
0
    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
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
0
    if (cur == NULL)
2617
0
  return(NULL);
2618
0
    memset(cur, 0, sizeof(xmlNs));
2619
0
    cur->type = XML_NAMESPACE_DECL;
2620
0
    if (ns->href != NULL) {
2621
0
  cur->href = xmlStrdup(ns->href);
2622
0
        if (cur->href == NULL) {
2623
0
            xmlFree(cur);
2624
0
            return(NULL);
2625
0
        }
2626
0
    }
2627
0
    if (ns->prefix != NULL) {
2628
0
  cur->prefix = xmlStrdup(ns->prefix);
2629
0
        if (cur->prefix == NULL) {
2630
0
            xmlFree((xmlChar *) cur->href);
2631
0
            xmlFree(cur);
2632
0
            return(NULL);
2633
0
        }
2634
0
    }
2635
0
    cur->next = (xmlNsPtr) node;
2636
0
    return((xmlNodePtr) cur);
2637
0
}
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
0
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
0
  if (ns->href != NULL)
2653
0
      xmlFree((xmlChar *)ns->href);
2654
0
  if (ns->prefix != NULL)
2655
0
      xmlFree((xmlChar *)ns->prefix);
2656
0
  xmlFree(ns);
2657
0
    }
2658
0
}
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
34.0M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
34.0M
    xmlNodeSetPtr ret;
2669
2670
34.0M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
34.0M
    if (ret == NULL)
2672
0
  return(NULL);
2673
34.0M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
34.0M
    if (val != NULL) {
2675
17.1M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
17.1M
               sizeof(xmlNodePtr));
2677
17.1M
  if (ret->nodeTab == NULL) {
2678
0
      xmlFree(ret);
2679
0
      return(NULL);
2680
0
  }
2681
17.1M
  memset(ret->nodeTab, 0 ,
2682
17.1M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
17.1M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
17.1M
  if (val->type == XML_NAMESPACE_DECL) {
2685
0
      xmlNsPtr ns = (xmlNsPtr) val;
2686
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
0
            if (nsNode == NULL) {
2689
0
                xmlXPathFreeNodeSet(ret);
2690
0
                return(NULL);
2691
0
            }
2692
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
0
  } else
2694
17.1M
      ret->nodeTab[ret->nodeNr++] = val;
2695
17.1M
    }
2696
34.0M
    return(ret);
2697
34.0M
}
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
25.8M
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
25.8M
    int i;
2709
2710
25.8M
    if ((cur == NULL) || (val == NULL)) return(0);
2711
25.8M
    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
25.8M
    } else {
2726
413M
  for (i = 0; i < cur->nodeNr; i++) {
2727
396M
      if (cur->nodeTab[i] == val)
2728
9.45M
    return(1);
2729
396M
  }
2730
25.8M
    }
2731
16.4M
    return(0);
2732
25.8M
}
2733
2734
static int
2735
1.68M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
1.68M
    xmlNodePtr *temp;
2737
1.68M
    int newSize;
2738
2739
1.68M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
1.68M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
1.68M
    if (newSize < 0)
2742
0
        return(-1);
2743
1.68M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
1.68M
    if (temp == NULL)
2745
0
        return(-1);
2746
1.68M
    cur->nodeMax = newSize;
2747
1.68M
    cur->nodeTab = temp;
2748
2749
1.68M
    return(0);
2750
1.68M
}
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
0
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
0
    int i;
2763
0
    xmlNodePtr nsNode;
2764
2765
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
0
        (ns->type != XML_NAMESPACE_DECL) ||
2767
0
  (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
0
    for (i = 0;i < cur->nodeNr;i++) {
2775
0
        if ((cur->nodeTab[i] != NULL) &&
2776
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
0
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
0
    if (cur->nodeNr >= cur->nodeMax) {
2786
0
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
0
            return(-1);
2788
0
    }
2789
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
0
    if(nsNode == NULL)
2791
0
        return(-1);
2792
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
0
    return(0);
2794
0
}
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
62.0k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
62.0k
    int i;
2806
2807
62.0k
    if ((cur == NULL) || (val == NULL)) return(-1);
2808
2809
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2810
    /*
2811
     * prevent duplicates
2812
     */
2813
122M
    for (i = 0;i < cur->nodeNr;i++)
2814
122M
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
60.6k
    if (cur->nodeNr >= cur->nodeMax) {
2820
29.1k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
0
            return(-1);
2822
29.1k
    }
2823
2824
60.6k
    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
60.6k
  cur->nodeTab[cur->nodeNr++] = val;
2833
60.6k
    return(0);
2834
60.6k
}
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
19.4M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
19.4M
    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
19.4M
    if (cur->nodeNr >= cur->nodeMax) {
2853
1.39M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
0
            return(-1);
2855
1.39M
    }
2856
2857
19.4M
    if (val->type == XML_NAMESPACE_DECL) {
2858
0
  xmlNsPtr ns = (xmlNsPtr) val;
2859
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
0
        if (nsNode == NULL)
2862
0
            return(-1);
2863
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
0
    } else
2865
19.4M
  cur->nodeTab[cur->nodeNr++] = val;
2866
19.4M
    return(0);
2867
19.4M
}
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
26.2k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
26.2k
    int i, j, initNr, skip;
2882
26.2k
    xmlNodePtr n1, n2;
2883
2884
26.2k
    if (val1 == NULL) {
2885
0
  val1 = xmlXPathNodeSetCreate(NULL);
2886
0
        if (val1 == NULL)
2887
0
            return (NULL);
2888
0
    }
2889
26.2k
    if (val2 == NULL)
2890
0
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
26.2k
    initNr = val1->nodeNr;
2894
2895
324k
    for (i = 0;i < val2->nodeNr;i++) {
2896
298k
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
298k
  skip = 0;
2901
101M
  for (j = 0; j < initNr; j++) {
2902
101M
      n1 = val1->nodeTab[j];
2903
101M
      if (n1 == n2) {
2904
43.4k
    skip = 1;
2905
43.4k
    break;
2906
101M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
0
           (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
101M
  }
2917
298k
  if (skip)
2918
43.4k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
255k
        if (val1->nodeNr >= val1->nodeMax) {
2924
8.70k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
0
                goto error;
2926
8.70k
        }
2927
255k
  if (n2->type == XML_NAMESPACE_DECL) {
2928
0
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
0
            if (nsNode == NULL)
2932
0
                goto error;
2933
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
0
  } else
2935
255k
      val1->nodeTab[val1->nodeNr++] = n2;
2936
255k
    }
2937
2938
26.2k
    return(val1);
2939
2940
0
error:
2941
0
    xmlXPathFreeNodeSet(val1);
2942
0
    return(NULL);
2943
26.2k
}
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
554k
{
2959
554k
    {
2960
554k
  int i, j, initNbSet1;
2961
554k
  xmlNodePtr n1, n2;
2962
2963
554k
  initNbSet1 = set1->nodeNr;
2964
2.09M
  for (i = 0;i < set2->nodeNr;i++) {
2965
1.54M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
2.25G
      for (j = 0; j < initNbSet1; j++) {
2970
2.25G
    n1 = set1->nodeTab[j];
2971
2.25G
    if (n1 == n2) {
2972
1.33M
        goto skip_node;
2973
2.25G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
0
        (n2->type == XML_NAMESPACE_DECL))
2975
0
    {
2976
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
0
      ((xmlNsPtr) n2)->prefix)))
2979
0
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
0
      goto skip_node;
2985
0
        }
2986
0
    }
2987
2.25G
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
206k
            if (set1->nodeNr >= set1->nodeMax) {
2992
11.5k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
0
                    goto error;
2994
11.5k
            }
2995
206k
      set1->nodeTab[set1->nodeNr++] = n2;
2996
1.54M
skip_node:
2997
1.54M
            set2->nodeTab[i] = NULL;
2998
1.54M
  }
2999
554k
    }
3000
554k
    set2->nodeNr = 0;
3001
554k
    return(set1);
3002
3003
0
error:
3004
0
    xmlXPathFreeNodeSet(set1);
3005
0
    xmlXPathNodeSetClear(set2, 1);
3006
0
    return(NULL);
3007
554k
}
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
444k
{
3022
444k
    {
3023
444k
  int i;
3024
444k
  xmlNodePtr n2;
3025
3026
4.49M
  for (i = 0;i < set2->nodeNr;i++) {
3027
4.04M
      n2 = set2->nodeTab[i];
3028
4.04M
            if (set1->nodeNr >= set1->nodeMax) {
3029
238k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
0
                    goto error;
3031
238k
            }
3032
4.04M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
4.04M
            set2->nodeTab[i] = NULL;
3034
4.04M
  }
3035
444k
    }
3036
444k
    set2->nodeNr = 0;
3037
444k
    return(set1);
3038
3039
0
error:
3040
0
    xmlXPathFreeNodeSet(set1);
3041
0
    xmlXPathNodeSetClear(set2, 1);
3042
0
    return(NULL);
3043
444k
}
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
34.0M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
34.0M
    if (obj == NULL) return;
3103
34.0M
    if (obj->nodeTab != NULL) {
3104
17.6M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
52.8M
  for (i = 0;i < obj->nodeNr;i++)
3108
35.2M
      if ((obj->nodeTab[i] != NULL) &&
3109
35.2M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
17.6M
  xmlFree(obj->nodeTab);
3112
17.6M
    }
3113
34.0M
    xmlFree(obj);
3114
34.0M
}
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
86.3k
{
3128
86.3k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
86.3k
    else if ((hasNsNodes)) {
3131
737
  int i;
3132
737
  xmlNodePtr node;
3133
3134
32.1k
  for (i = pos; i < set->nodeNr; i++) {
3135
31.3k
      node = set->nodeTab[i];
3136
31.3k
      if ((node != NULL) &&
3137
31.3k
    (node->type == XML_NAMESPACE_DECL))
3138
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
31.3k
  }
3140
737
    }
3141
86.3k
    set->nodeNr = pos;
3142
86.3k
}
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
85.6k
{
3155
85.6k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
85.6k
}
3157
3158
/**
3159
 * Move the last node to the first position and clear temporary XPath objects
3160
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3161
 * to 1.
3162
 *
3163
 * @param set  the node set to be cleared
3164
 */
3165
static void
3166
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3167
0
{
3168
0
    int i;
3169
0
    xmlNodePtr node;
3170
3171
0
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
0
        node = set->nodeTab[i];
3175
0
        if ((node != NULL) &&
3176
0
            (node->type == XML_NAMESPACE_DECL))
3177
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
0
    }
3179
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
0
    set->nodeNr = 1;
3181
0
}
3182
3183
/**
3184
 * Create a new xmlXPathObject of type NodeSet and initialize
3185
 * it with the single Node `val`
3186
 *
3187
 * @param val  the NodePtr value
3188
 * @returns the newly created object.
3189
 */
3190
xmlXPathObject *
3191
17.1M
xmlXPathNewNodeSet(xmlNode *val) {
3192
17.1M
    xmlXPathObjectPtr ret;
3193
3194
17.1M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
17.1M
    if (ret == NULL)
3196
0
  return(NULL);
3197
17.1M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
17.1M
    ret->type = XPATH_NODESET;
3199
17.1M
    ret->boolval = 0;
3200
17.1M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
17.1M
    if (ret->nodesetval == NULL) {
3202
0
        xmlFree(ret);
3203
0
        return(NULL);
3204
0
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
17.1M
    return(ret);
3207
17.1M
}
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
16.8M
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
16.8M
    xmlXPathObjectPtr ret;
3269
3270
16.8M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
16.8M
    if (ret == NULL) {
3272
0
        xmlXPathFreeNodeSet(val);
3273
0
  return(NULL);
3274
0
    }
3275
16.8M
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
16.8M
    ret->type = XPATH_NODESET;
3277
16.8M
    ret->nodesetval = val;
3278
16.8M
    return(ret);
3279
16.8M
}
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
8.21k
         xmlXPathFunction f) {
3676
8.21k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
8.21k
}
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
8.21k
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
8.21k
    int ret;
3692
8.21k
    void *payload;
3693
3694
8.21k
    if (ctxt == NULL)
3695
0
  return(-1);
3696
8.21k
    if (name == NULL)
3697
0
  return(-1);
3698
3699
8.21k
    if (ctxt->funcHash == NULL)
3700
8.21k
  ctxt->funcHash = xmlHashCreate(0);
3701
8.21k
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
8.21k
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
8.21k
    memcpy(&payload, &f, sizeof(f));
3708
8.21k
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
8.21k
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
8.21k
    return(0);
3715
8.21k
}
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
7.12k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
7.12k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
7.12k
}
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
7.12k
       const xmlChar *ns_uri) {
3759
7.12k
    xmlXPathFunction ret;
3760
7.12k
    void *payload;
3761
3762
7.12k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
7.12k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
7.12k
    if (ns_uri == NULL) {
3768
7.12k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
8.68k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
8.41k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
8.41k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
8.41k
                       (char *) name) == 0)
3775
6.85k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
1.56k
            bucketIndex += 1;
3778
1.56k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
1.56k
        }
3781
7.12k
    }
3782
3783
269
    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
269
    if (ctxt->funcHash == NULL)
3793
0
  return(NULL);
3794
3795
269
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
269
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
269
    return(ret);
3799
269
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
8.21k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
8.21k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
8.21k
    xmlHashFree(ctxt->funcHash, NULL);
3812
8.21k
    ctxt->funcHash = NULL;
3813
8.21k
}
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
10
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
10
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
10
    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
10
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
10
}
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
11
       const xmlChar *ns_uri) {
3917
11
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
11
    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
11
    if (ctxt->varHash == NULL)
3929
11
  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
8.21k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
8.21k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
8.21k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
8.21k
    ctxt->varHash = NULL;
3948
8.21k
}
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
788
         const xmlChar *ns_uri) {
3962
788
    xmlChar *copy;
3963
3964
788
    if (ctxt == NULL)
3965
0
  return(-1);
3966
788
    if (prefix == NULL)
3967
0
  return(-1);
3968
788
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
788
    if (ctxt->nsHash == NULL)
3972
189
  ctxt->nsHash = xmlHashCreate(10);
3973
788
    if (ctxt->nsHash == NULL) {
3974
0
        xmlXPathErrMemory(ctxt);
3975
0
  return(-1);
3976
0
    }
3977
788
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
788
    copy = xmlStrdup(ns_uri);
3982
788
    if (copy == NULL) {
3983
0
        xmlXPathErrMemory(ctxt);
3984
0
        return(-1);
3985
0
    }
3986
788
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
788
                           xmlHashDefaultDeallocator) < 0) {
3988
0
        xmlXPathErrMemory(ctxt);
3989
0
        xmlFree(copy);
3990
0
        return(-1);
3991
0
    }
3992
3993
788
    return(0);
3994
788
}
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
2.93k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
2.93k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
2.93k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
2.93k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
2.59k
  return(XML_XML_NAMESPACE);
4013
4014
337
    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
337
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
337
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
8.21k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
8.21k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
8.21k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
8.21k
    ctxt->nsHash = NULL;
4039
8.21k
}
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
2.92M
xmlXPathNewFloat(double val) {
4057
2.92M
    xmlXPathObjectPtr ret;
4058
4059
2.92M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
2.92M
    if (ret == NULL)
4061
0
  return(NULL);
4062
2.92M
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
2.92M
    ret->type = XPATH_NUMBER;
4064
2.92M
    ret->floatval = val;
4065
2.92M
    return(ret);
4066
2.92M
}
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
9.72M
xmlXPathNewBoolean(int val) {
4076
9.72M
    xmlXPathObjectPtr ret;
4077
4078
9.72M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
9.72M
    if (ret == NULL)
4080
0
  return(NULL);
4081
9.72M
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
9.72M
    ret->type = XPATH_BOOLEAN;
4083
9.72M
    ret->boolval = (val != 0);
4084
9.72M
    return(ret);
4085
9.72M
}
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
61.4k
xmlXPathNewString(const xmlChar *val) {
4095
61.4k
    xmlXPathObjectPtr ret;
4096
4097
61.4k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
61.4k
    if (ret == NULL)
4099
0
  return(NULL);
4100
61.4k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
61.4k
    ret->type = XPATH_STRING;
4102
61.4k
    if (val == NULL)
4103
0
        val = BAD_CAST "";
4104
61.4k
    ret->stringval = xmlStrdup(val);
4105
61.4k
    if (ret->stringval == NULL) {
4106
0
        xmlFree(ret);
4107
0
        return(NULL);
4108
0
    }
4109
61.4k
    return(ret);
4110
61.4k
}
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
14.8k
xmlXPathWrapString (xmlChar *val) {
4122
14.8k
    xmlXPathObjectPtr ret;
4123
4124
14.8k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
14.8k
    if (ret == NULL) {
4126
0
        xmlFree(val);
4127
0
  return(NULL);
4128
0
    }
4129
14.8k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
14.8k
    ret->type = XPATH_STRING;
4131
14.8k
    ret->stringval = val;
4132
14.8k
    return(ret);
4133
14.8k
}
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
204k
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
204k
    xmlXPathObjectPtr ret;
4185
4186
204k
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
204k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
204k
    if (ret == NULL)
4191
0
  return(NULL);
4192
204k
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
204k
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
184k
  case XPATH_NUMBER:
4196
184k
      break;
4197
20.3k
  case XPATH_STRING:
4198
20.3k
      ret->stringval = xmlStrdup(val->stringval);
4199
20.3k
            if (ret->stringval == NULL) {
4200
0
                xmlFree(ret);
4201
0
                return(NULL);
4202
0
            }
4203
20.3k
      break;
4204
20.3k
  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
204k
    }
4222
204k
    return(ret);
4223
204k
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
46.9M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
46.9M
    if (obj == NULL) return;
4233
46.9M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
33.9M
        if (obj->nodesetval != NULL)
4235
33.9M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
33.9M
    } else if (obj->type == XPATH_STRING) {
4237
96.6k
  if (obj->stringval != NULL)
4238
96.6k
      xmlFree(obj->stringval);
4239
96.6k
    }
4240
46.9M
    xmlFree(obj);
4241
46.9M
}
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
46.0M
{
4258
46.0M
    if (obj == NULL)
4259
0
  return;
4260
46.0M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
46.0M
   xmlXPathFreeObject(obj);
4262
46.0M
    } 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
46.0M
}
4339
4340
4341
/************************************************************************
4342
 *                  *
4343
 *      Type Casting Routines       *
4344
 *                  *
4345
 ************************************************************************/
4346
4347
/**
4348
 * Converts a boolean to its string value.
4349
 *
4350
 * @param val  a boolean
4351
 * @returns a newly allocated string.
4352
 */
4353
xmlChar *
4354
1.97k
xmlXPathCastBooleanToString (int val) {
4355
1.97k
    xmlChar *ret;
4356
1.97k
    if (val)
4357
646
  ret = xmlStrdup((const xmlChar *) "true");
4358
1.32k
    else
4359
1.32k
  ret = xmlStrdup((const xmlChar *) "false");
4360
1.97k
    return(ret);
4361
1.97k
}
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
2.24k
xmlXPathCastNumberToString (double val) {
4371
2.24k
    xmlChar *ret;
4372
2.24k
    switch (xmlXPathIsInf(val)) {
4373
10
    case 1:
4374
10
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
10
  break;
4376
1
    case -1:
4377
1
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
1
  break;
4379
2.23k
    default:
4380
2.23k
  if (xmlXPathIsNaN(val)) {
4381
1.25k
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
1.25k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
227
      ret = xmlStrdup((const xmlChar *) "0");
4385
754
  } else {
4386
      /* could be improved */
4387
754
      char buf[100];
4388
754
      xmlXPathFormatNumber(val, buf, 99);
4389
754
      buf[99] = 0;
4390
754
      ret = xmlStrdup((const xmlChar *) buf);
4391
754
  }
4392
2.24k
    }
4393
2.24k
    return(ret);
4394
2.24k
}
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
363k
xmlXPathCastNodeToString (xmlNode *node) {
4404
363k
    return(xmlNodeGetContent(node));
4405
363k
}
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
6.42M
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
6.42M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
6.12M
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
306k
    if (ns->nodeNr > 1)
4419
35.8k
  xmlXPathNodeSetSort(ns);
4420
306k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
6.42M
}
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
18.8k
xmlXPathCastToString(xmlXPathObject *val) {
4432
18.8k
    xmlChar *ret = NULL;
4433
4434
18.8k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
18.8k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
12.7k
        case XPATH_NODESET:
4441
12.7k
        case XPATH_XSLT_TREE:
4442
12.7k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
12.7k
      break;
4444
1.88k
  case XPATH_STRING:
4445
1.88k
      return(xmlStrdup(val->stringval));
4446
1.97k
        case XPATH_BOOLEAN:
4447
1.97k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
1.97k
      break;
4449
2.24k
  case XPATH_NUMBER: {
4450
2.24k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
2.24k
      break;
4452
12.7k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
18.8k
    }
4458
17.0k
    return(ret);
4459
18.8k
}
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
26.7k
xmlXPathCastBooleanToNumber(int val) {
4508
26.7k
    if (val)
4509
3.60k
  return(1.0);
4510
23.1k
    return(0.0);
4511
26.7k
}
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
6.47M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
6.47M
    return(xmlXPathStringEvalNumber(val));
4522
6.47M
}
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
8.18k
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
8.18k
    xmlChar *strval;
4534
8.18k
    double ret;
4535
4536
8.18k
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
8.18k
    strval = xmlXPathCastNodeToString(node);
4539
8.18k
    if (strval == NULL) {
4540
0
        xmlXPathPErrMemory(ctxt);
4541
0
  return(xmlXPathNAN);
4542
0
    }
4543
8.18k
    ret = xmlXPathCastStringToNumber(strval);
4544
8.18k
    xmlFree(strval);
4545
4546
8.18k
    return(ret);
4547
8.18k
}
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
140k
xmlXPathCastNumberToBoolean (double val) {
4618
140k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
127k
   return(0);
4620
12.5k
     return(1);
4621
140k
}
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
684
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
684
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
404
  return(0);
4633
280
    return(1);
4634
684
}
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
8.37k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
8.37k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
6.36k
  return(0);
4646
2.00k
    return(1);
4647
8.37k
}
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
79.8k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
79.8k
    int ret = 0;
4658
4659
79.8k
    if (val == NULL)
4660
0
  return(0);
4661
79.8k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
8.37k
    case XPATH_NODESET:
4666
8.37k
    case XPATH_XSLT_TREE:
4667
8.37k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
8.37k
  break;
4669
684
    case XPATH_STRING:
4670
684
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
684
  break;
4672
70.8k
    case XPATH_NUMBER:
4673
70.8k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
70.8k
  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
79.8k
    }
4683
79.8k
    return(ret);
4684
79.8k
}
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
8.21k
xmlXPathNewContext(xmlDoc *doc) {
4721
8.21k
    xmlXPathContextPtr ret;
4722
4723
8.21k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
8.21k
    if (ret == NULL)
4725
0
  return(NULL);
4726
8.21k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
8.21k
    ret->doc = doc;
4728
8.21k
    ret->node = NULL;
4729
4730
8.21k
    ret->varHash = NULL;
4731
4732
8.21k
    ret->nb_types = 0;
4733
8.21k
    ret->max_types = 0;
4734
8.21k
    ret->types = NULL;
4735
4736
8.21k
    ret->nb_axis = 0;
4737
8.21k
    ret->max_axis = 0;
4738
8.21k
    ret->axis = NULL;
4739
4740
8.21k
    ret->nsHash = NULL;
4741
8.21k
    ret->user = NULL;
4742
4743
8.21k
    ret->contextSize = -1;
4744
8.21k
    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
8.21k
    return(ret);
4754
8.21k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
8.21k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
8.21k
    if (ctxt == NULL) return;
4764
4765
8.21k
    if (ctxt->cache != NULL)
4766
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
8.21k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
8.21k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
8.21k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
8.21k
    xmlResetError(&ctxt->lastError);
4771
8.21k
    xmlFree(ctxt);
4772
8.21k
}
4773
4774
/**
4775
 * Register a callback function that will be called on errors and
4776
 * warnings. If handler is NULL, the error handler will be deactivated.
4777
 *
4778
 * @since 2.13.0
4779
 * @param ctxt  the XPath context
4780
 * @param handler  error handler
4781
 * @param data  user data which will be passed to the handler
4782
 */
4783
void
4784
xmlXPathSetErrorHandler(xmlXPathContext *ctxt,
4785
0
                        xmlStructuredErrorFunc handler, void *data) {
4786
0
    if (ctxt == NULL)
4787
0
        return;
4788
4789
0
    ctxt->error = handler;
4790
0
    ctxt->userData = data;
4791
0
}
4792
4793
/************************************************************************
4794
 *                  *
4795
 *    Routines to handle XPath parser contexts    *
4796
 *                  *
4797
 ************************************************************************/
4798
4799
/**
4800
 * Create a new xmlXPathParserContext
4801
 *
4802
 * @param str  the XPath expression
4803
 * @param ctxt  the XPath context
4804
 * @returns the xmlXPathParserContext just allocated.
4805
 */
4806
xmlXPathParserContext *
4807
8.21k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
8.21k
    xmlXPathParserContextPtr ret;
4809
4810
8.21k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
8.21k
    if (ret == NULL) {
4812
0
        xmlXPathErrMemory(ctxt);
4813
0
  return(NULL);
4814
0
    }
4815
8.21k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
8.21k
    ret->cur = ret->base = str;
4817
8.21k
    ret->context = ctxt;
4818
4819
8.21k
    ret->comp = xmlXPathNewCompExpr();
4820
8.21k
    if (ret->comp == NULL) {
4821
0
        xmlXPathErrMemory(ctxt);
4822
0
  xmlFree(ret->valueTab);
4823
0
  xmlFree(ret);
4824
0
  return(NULL);
4825
0
    }
4826
8.21k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
8.21k
    return(ret);
4832
8.21k
}
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
8.21k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
8.21k
    int i;
4881
4882
8.21k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
8.21k
    if (ctxt->valueTab != NULL) {
4886
39.5k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
31.3k
            if (ctxt->context)
4888
31.3k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
31.3k
        }
4892
8.21k
        xmlFree(ctxt->valueTab);
4893
8.21k
    }
4894
8.21k
    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
8.21k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
8.21k
    }
4903
8.21k
    xmlFree(ctxt);
4904
8.21k
}
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
33.7k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
33.7k
    int len = 2;
4922
33.7k
    const xmlChar * string = NULL;
4923
33.7k
    xmlNodePtr tmp = NULL;
4924
33.7k
    unsigned int ret = 0;
4925
4926
33.7k
    if (node == NULL)
4927
0
  return(0);
4928
4929
33.7k
    if (node->type == XML_DOCUMENT_NODE) {
4930
2.02k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
2.02k
  if (tmp == NULL)
4932
0
      node = node->children;
4933
2.02k
  else
4934
2.02k
      node = tmp;
4935
4936
2.02k
  if (node == NULL)
4937
0
      return(0);
4938
2.02k
    }
4939
4940
33.7k
    switch (node->type) {
4941
239
  case XML_COMMENT_NODE:
4942
1.43k
  case XML_PI_NODE:
4943
1.72k
  case XML_CDATA_SECTION_NODE:
4944
4.69k
  case XML_TEXT_NODE:
4945
4.69k
      string = node->content;
4946
4.69k
      if (string == NULL)
4947
652
    return(0);
4948
4.04k
      if (string[0] == 0)
4949
388
    return(0);
4950
3.65k
      return(string[0] + (string[1] << 8));
4951
0
  case XML_NAMESPACE_DECL:
4952
0
      string = ((xmlNsPtr)node)->href;
4953
0
      if (string == NULL)
4954
0
    return(0);
4955
0
      if (string[0] == 0)
4956
0
    return(0);
4957
0
      return(string[0] + (string[1] << 8));
4958
11.6k
  case XML_ATTRIBUTE_NODE:
4959
11.6k
      tmp = ((xmlAttrPtr) node)->children;
4960
11.6k
      break;
4961
17.4k
  case XML_ELEMENT_NODE:
4962
17.4k
      tmp = node->children;
4963
17.4k
      break;
4964
0
  default:
4965
0
      return(0);
4966
33.7k
    }
4967
61.0k
    while (tmp != NULL) {
4968
50.0k
  switch (tmp->type) {
4969
0
      case XML_CDATA_SECTION_NODE:
4970
19.8k
      case XML_TEXT_NODE:
4971
19.8k
    string = tmp->content;
4972
19.8k
    break;
4973
30.1k
      default:
4974
30.1k
                string = NULL;
4975
30.1k
    break;
4976
50.0k
  }
4977
50.0k
  if ((string != NULL) && (string[0] != 0)) {
4978
19.5k
      if (len == 1) {
4979
842
    return(ret + (string[0] << 8));
4980
842
      }
4981
18.7k
      if (string[1] == 0) {
4982
1.54k
    len = 1;
4983
1.54k
    ret = string[0];
4984
17.1k
      } else {
4985
17.1k
    return(string[0] + (string[1] << 8));
4986
17.1k
      }
4987
18.7k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
32.0k
        if ((tmp->children != NULL) &&
4992
26.7k
            (tmp->type != XML_DTD_NODE) &&
4993
26.7k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
26.7k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
26.7k
            tmp = tmp->children;
4996
26.7k
            continue;
4997
26.7k
  }
4998
5.21k
  if (tmp == node)
4999
0
      break;
5000
5001
5.21k
  if (tmp->next != NULL) {
5002
1.57k
      tmp = tmp->next;
5003
1.57k
      continue;
5004
1.57k
  }
5005
5006
24.4k
  do {
5007
24.4k
      tmp = tmp->parent;
5008
24.4k
      if (tmp == NULL)
5009
0
    break;
5010
24.4k
      if (tmp == node) {
5011
2.34k
    tmp = NULL;
5012
2.34k
    break;
5013
2.34k
      }
5014
22.1k
      if (tmp->next != NULL) {
5015
1.29k
    tmp = tmp->next;
5016
1.29k
    break;
5017
1.29k
      }
5018
22.1k
  } while (tmp != NULL);
5019
3.63k
    }
5020
11.0k
    return(ret);
5021
29.0k
}
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.66k
xmlXPathStringHash(const xmlChar * string) {
5032
1.66k
    if (string == NULL)
5033
0
  return(0);
5034
1.66k
    if (string[0] == 0)
5035
1.33k
  return(0);
5036
329
    return(string[0] + (string[1] << 8));
5037
1.66k
}
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
2.54M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
2.54M
    int i, ret = 0;
5063
2.54M
    xmlNodeSetPtr ns;
5064
2.54M
    xmlChar *str2;
5065
5066
2.54M
    if ((f == NULL) || (arg == NULL) ||
5067
2.54M
  ((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
2.54M
    ns = arg->nodesetval;
5073
2.54M
    if (ns != NULL) {
5074
2.55M
  for (i = 0;i < ns->nodeNr;i++) {
5075
13.5k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
13.5k
       if (str2 != NULL) {
5077
13.5k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
13.5k
     xmlFree(str2);
5079
13.5k
     xmlXPathNumberFunction(ctxt, 1);
5080
13.5k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
13.5k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
13.5k
     if (ret)
5083
197
         break;
5084
13.5k
       } else {
5085
0
                 xmlXPathPErrMemory(ctxt);
5086
0
             }
5087
13.5k
  }
5088
2.54M
    }
5089
2.54M
    xmlXPathReleaseObject(ctxt->context, arg);
5090
2.54M
    xmlXPathReleaseObject(ctxt->context, f);
5091
2.54M
    return(ret);
5092
2.54M
}
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.16k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
1.16k
    int i, ret = 0;
5117
1.16k
    xmlNodeSetPtr ns;
5118
1.16k
    xmlChar *str2;
5119
5120
1.16k
    if ((s == NULL) || (arg == NULL) ||
5121
1.16k
  ((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.16k
    ns = arg->nodesetval;
5127
1.16k
    if (ns != NULL) {
5128
1.96k
  for (i = 0;i < ns->nodeNr;i++) {
5129
829
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
829
       if (str2 != NULL) {
5131
829
     xmlXPathValuePush(ctxt,
5132
829
         xmlXPathCacheNewString(ctxt, str2));
5133
829
     xmlFree(str2);
5134
829
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
829
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
829
     if (ret)
5137
24
         break;
5138
829
       } else {
5139
0
                 xmlXPathPErrMemory(ctxt);
5140
0
             }
5141
829
  }
5142
1.16k
    }
5143
1.16k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
1.16k
    xmlXPathReleaseObject(ctxt->context, s);
5145
1.16k
    return(ret);
5146
1.16k
}
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
400k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
400k
    int i, j, init = 0;
5180
400k
    double val1;
5181
400k
    double *values2;
5182
400k
    int ret = 0;
5183
400k
    xmlNodeSetPtr ns1;
5184
400k
    xmlNodeSetPtr ns2;
5185
5186
400k
    if ((arg1 == NULL) ||
5187
400k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
400k
    if ((arg2 == NULL) ||
5192
400k
  ((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
400k
    ns1 = arg1->nodesetval;
5199
400k
    ns2 = arg2->nodesetval;
5200
5201
400k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
398k
  xmlXPathFreeObject(arg1);
5203
398k
  xmlXPathFreeObject(arg2);
5204
398k
  return(0);
5205
398k
    }
5206
1.81k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
492
  xmlXPathFreeObject(arg1);
5208
492
  xmlXPathFreeObject(arg2);
5209
492
  return(0);
5210
492
    }
5211
5212
1.32k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
1.32k
    if (values2 == NULL) {
5214
0
        xmlXPathPErrMemory(ctxt);
5215
0
  xmlXPathFreeObject(arg1);
5216
0
  xmlXPathFreeObject(arg2);
5217
0
  return(0);
5218
0
    }
5219
6.32k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
5.31k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
5.31k
  if (xmlXPathIsNaN(val1))
5222
4.63k
      continue;
5223
5.65k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
5.28k
      if (init == 0) {
5225
2.87k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
2.87k
                                                          ns2->nodeTab[j]);
5227
2.87k
      }
5228
5.28k
      if (xmlXPathIsNaN(values2[j]))
5229
3.89k
    continue;
5230
1.38k
      if (inf && strict)
5231
596
    ret = (val1 < values2[j]);
5232
793
      else if (inf && !strict)
5233
118
    ret = (val1 <= values2[j]);
5234
675
      else if (!inf && strict)
5235
426
    ret = (val1 > values2[j]);
5236
249
      else if (!inf && !strict)
5237
249
    ret = (val1 >= values2[j]);
5238
1.38k
      if (ret)
5239
303
    break;
5240
1.38k
  }
5241
674
  if (ret)
5242
303
      break;
5243
371
  init = 1;
5244
371
    }
5245
1.32k
    xmlFree(values2);
5246
1.32k
    xmlXPathFreeObject(arg1);
5247
1.32k
    xmlXPathFreeObject(arg2);
5248
1.32k
    return(ret);
5249
1.32k
}
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
2.55M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
2.55M
    if ((val == NULL) || (arg == NULL) ||
5274
2.55M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
2.55M
    switch(val->type) {
5278
2.54M
        case XPATH_NUMBER:
5279
2.54M
      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.16k
        case XPATH_STRING:
5284
1.16k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
5.30k
        case XPATH_BOOLEAN:
5286
5.30k
      xmlXPathValuePush(ctxt, arg);
5287
5.30k
      xmlXPathBooleanFunction(ctxt, 1);
5288
5.30k
      xmlXPathValuePush(ctxt, val);
5289
5.30k
      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
2.55M
    }
5295
0
    return(0);
5296
2.55M
}
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
3.15k
{
5315
3.15k
    int i;
5316
3.15k
    xmlNodeSetPtr ns;
5317
3.15k
    xmlChar *str2;
5318
3.15k
    unsigned int hash;
5319
5320
3.15k
    if ((str == NULL) || (arg == NULL) ||
5321
3.15k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
3.15k
    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
3.15k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
1.49k
        return (0);
5330
1.66k
    hash = xmlXPathStringHash(str);
5331
9.62k
    for (i = 0; i < ns->nodeNr; i++) {
5332
9.14k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
1.58k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
1.58k
            if (str2 == NULL) {
5335
0
                xmlXPathPErrMemory(ctxt);
5336
0
                return(0);
5337
0
            }
5338
1.58k
            if (xmlStrEqual(str, str2)) {
5339
1.34k
                xmlFree(str2);
5340
1.34k
    if (neq)
5341
310
        continue;
5342
1.03k
                return (1);
5343
1.34k
            } else if (neq) {
5344
12
    xmlFree(str2);
5345
12
    return (1);
5346
12
      }
5347
233
            xmlFree(str2);
5348
7.55k
        } else if (neq)
5349
142
      return (1);
5350
9.14k
    }
5351
478
    return (0);
5352
1.66k
}
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
116k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
116k
  int i, ret=0;
5372
116k
  xmlNodeSetPtr ns;
5373
116k
  xmlChar *str2;
5374
116k
  xmlXPathObjectPtr val;
5375
116k
  double v;
5376
5377
116k
    if ((arg == NULL) ||
5378
116k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
116k
    ns = arg->nodesetval;
5382
116k
    if (ns != NULL) {
5383
141k
  for (i=0;i<ns->nodeNr;i++) {
5384
25.8k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
25.8k
      if (str2 != NULL) {
5386
25.8k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
25.8k
    xmlFree(str2);
5388
25.8k
    xmlXPathNumberFunction(ctxt, 1);
5389
25.8k
                CHECK_ERROR0;
5390
25.8k
    val = xmlXPathValuePop(ctxt);
5391
25.8k
    v = val->floatval;
5392
25.8k
    xmlXPathReleaseObject(ctxt->context, val);
5393
25.8k
    if (!xmlXPathIsNaN(v)) {
5394
2.50k
        if ((!neq) && (v==f)) {
5395
284
      ret = 1;
5396
284
      break;
5397
2.21k
        } else if ((neq) && (v!=f)) {
5398
23
      ret = 1;
5399
23
      break;
5400
23
        }
5401
23.3k
    } else { /* NaN is unequal to any value */
5402
23.3k
        if (neq)
5403
2.61k
      ret = 1;
5404
23.3k
    }
5405
25.8k
      } else {
5406
0
                xmlXPathPErrMemory(ctxt);
5407
0
            }
5408
25.8k
  }
5409
116k
    }
5410
5411
116k
    return(ret);
5412
116k
}
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
3.18M
                      xmlXPathObjectPtr arg2, int neq) {
5434
3.18M
    int i, j;
5435
3.18M
    unsigned int *hashs1;
5436
3.18M
    unsigned int *hashs2;
5437
3.18M
    xmlChar **values1;
5438
3.18M
    xmlChar **values2;
5439
3.18M
    int ret = 0;
5440
3.18M
    xmlNodeSetPtr ns1;
5441
3.18M
    xmlNodeSetPtr ns2;
5442
5443
3.18M
    if ((arg1 == NULL) ||
5444
3.18M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
3.18M
    if ((arg2 == NULL) ||
5447
3.18M
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
3.18M
    ns1 = arg1->nodesetval;
5451
3.18M
    ns2 = arg2->nodesetval;
5452
5453
3.18M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
3.18M
  return(0);
5455
5.24k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
2.42k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
2.81k
    if (neq == 0)
5462
14.0k
  for (i = 0;i < ns1->nodeNr;i++)
5463
14.7M
      for (j = 0;j < ns2->nodeNr;j++)
5464
14.7M
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
460
        return(1);
5466
5467
2.35k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
2.35k
    if (values1 == NULL) {
5469
0
        xmlXPathPErrMemory(ctxt);
5470
0
  return(0);
5471
0
    }
5472
2.35k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
2.35k
    if (hashs1 == NULL) {
5474
0
        xmlXPathPErrMemory(ctxt);
5475
0
  xmlFree(values1);
5476
0
  return(0);
5477
0
    }
5478
2.35k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
2.35k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
2.35k
    if (values2 == NULL) {
5481
0
        xmlXPathPErrMemory(ctxt);
5482
0
  xmlFree(hashs1);
5483
0
  xmlFree(values1);
5484
0
  return(0);
5485
0
    }
5486
2.35k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
2.35k
    if (hashs2 == NULL) {
5488
0
        xmlXPathPErrMemory(ctxt);
5489
0
  xmlFree(hashs1);
5490
0
  xmlFree(values1);
5491
0
  xmlFree(values2);
5492
0
  return(0);
5493
0
    }
5494
2.35k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
12.4k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
11.4k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
14.7M
  for (j = 0;j < ns2->nodeNr;j++) {
5498
14.7M
      if (i == 0)
5499
13.2k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
14.7M
      if (hashs1[i] != hashs2[j]) {
5501
14.7M
    if (neq) {
5502
73
        ret = 1;
5503
73
        break;
5504
73
    }
5505
14.7M
      }
5506
2.61k
      else {
5507
2.61k
    if (values1[i] == NULL) {
5508
1.89k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
1.89k
                    if (values1[i] == NULL)
5510
0
                        xmlXPathPErrMemory(ctxt);
5511
1.89k
                }
5512
2.61k
    if (values2[j] == NULL) {
5513
2.37k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
2.37k
                    if (values2[j] == NULL)
5515
0
                        xmlXPathPErrMemory(ctxt);
5516
2.37k
                }
5517
2.61k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
2.61k
    if (ret)
5519
1.24k
        break;
5520
2.61k
      }
5521
14.7M
  }
5522
11.4k
  if (ret)
5523
1.31k
      break;
5524
11.4k
    }
5525
13.9k
    for (i = 0;i < ns1->nodeNr;i++)
5526
11.5k
  if (values1[i] != NULL)
5527
1.89k
      xmlFree(values1[i]);
5528
16.9k
    for (j = 0;j < ns2->nodeNr;j++)
5529
14.6k
  if (values2[j] != NULL)
5530
2.37k
      xmlFree(values2[j]);
5531
2.35k
    xmlFree(values1);
5532
2.35k
    xmlFree(values2);
5533
2.35k
    xmlFree(hashs1);
5534
2.35k
    xmlFree(hashs2);
5535
2.35k
    return(ret);
5536
2.35k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
3.00M
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
3.00M
    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
3.00M
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
2.98M
        case XPATH_BOOLEAN:
5550
2.98M
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
2.92M
    case XPATH_BOOLEAN:
5554
2.92M
        ret = (arg1->boolval == arg2->boolval);
5555
2.92M
        break;
5556
63.2k
    case XPATH_NUMBER:
5557
63.2k
        ret = (arg1->boolval ==
5558
63.2k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
63.2k
        break;
5560
2.56k
    case XPATH_STRING:
5561
2.56k
        if ((arg2->stringval == NULL) ||
5562
2.56k
      (arg2->stringval[0] == 0)) ret = 0;
5563
2.31k
        else
5564
2.31k
      ret = 1;
5565
2.56k
        ret = (arg1->boolval == ret);
5566
2.56k
        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
2.98M
      }
5574
2.98M
      break;
5575
2.98M
        case XPATH_NUMBER:
5576
12.2k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
5.92k
    case XPATH_BOOLEAN:
5580
5.92k
        ret = (arg2->boolval==
5581
5.92k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
5.92k
        break;
5583
387
    case XPATH_STRING:
5584
387
        xmlXPathValuePush(ctxt, arg2);
5585
387
        xmlXPathNumberFunction(ctxt, 1);
5586
387
        arg2 = xmlXPathValuePop(ctxt);
5587
387
                    if (ctxt->error)
5588
0
                        break;
5589
                    /* Falls through. */
5590
6.33k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
6.33k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
3.79k
          xmlXPathIsNaN(arg2->floatval)) {
5594
3.22k
            ret = 0;
5595
3.22k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
520
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
273
          ret = 1;
5598
247
      else
5599
247
          ret = 0;
5600
2.58k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
771
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
231
          ret = 1;
5603
540
      else
5604
540
          ret = 0;
5605
1.81k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
251
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
251
      else
5609
251
          ret = 0;
5610
1.56k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
185
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
185
      else
5614
185
          ret = 0;
5615
1.37k
        } else {
5616
1.37k
            ret = (arg1->floatval == arg2->floatval);
5617
1.37k
        }
5618
6.33k
        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
12.2k
      }
5626
12.2k
      break;
5627
12.2k
        case XPATH_STRING:
5628
1.12k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
341
    case XPATH_BOOLEAN:
5632
341
        if ((arg1->stringval == NULL) ||
5633
341
      (arg1->stringval[0] == 0)) ret = 0;
5634
230
        else
5635
230
      ret = 1;
5636
341
        ret = (arg2->boolval == ret);
5637
341
        break;
5638
304
    case XPATH_STRING:
5639
304
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
304
        break;
5641
476
    case XPATH_NUMBER:
5642
476
        xmlXPathValuePush(ctxt, arg1);
5643
476
        xmlXPathNumberFunction(ctxt, 1);
5644
476
        arg1 = xmlXPathValuePop(ctxt);
5645
476
                    if (ctxt->error)
5646
0
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
476
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
445
          xmlXPathIsNaN(arg2->floatval)) {
5650
445
            ret = 0;
5651
445
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
2
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
1
          ret = 1;
5654
1
      else
5655
1
          ret = 0;
5656
29
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
2
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
1
          ret = 1;
5659
1
      else
5660
1
          ret = 0;
5661
27
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
3
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
3
      else
5665
3
          ret = 0;
5666
24
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
0
      else
5670
0
          ret = 0;
5671
24
        } else {
5672
24
            ret = (arg1->floatval == arg2->floatval);
5673
24
        }
5674
476
        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.12k
      }
5682
1.12k
      break;
5683
1.12k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
3.00M
    }
5690
3.00M
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
3.00M
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
3.00M
    return(ret);
5693
3.00M
}
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
6.64M
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
6.64M
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
6.64M
    int ret = 0;
5705
5706
6.64M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
6.64M
    arg2 = xmlXPathValuePop(ctxt);
5708
6.64M
    arg1 = xmlXPathValuePop(ctxt);
5709
6.64M
    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
6.64M
    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
6.64M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
3.64M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
3.64M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
419k
    argtmp = arg2;
5732
419k
    arg2 = arg1;
5733
419k
    arg1 = argtmp;
5734
419k
  }
5735
3.64M
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
3.17M
      case XPATH_NODESET:
5739
3.17M
      case XPATH_XSLT_TREE:
5740
3.17M
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
3.17M
    break;
5742
350k
      case XPATH_BOOLEAN:
5743
350k
    if ((arg1->nodesetval == NULL) ||
5744
350k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
2.63k
    else
5746
2.63k
        ret = 1;
5747
350k
    ret = (ret == arg2->boolval);
5748
350k
    break;
5749
115k
      case XPATH_NUMBER:
5750
115k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
115k
    break;
5752
2.84k
      case XPATH_STRING:
5753
2.84k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
2.84k
                                                 arg2->stringval, 0);
5755
2.84k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
3.64M
  }
5760
3.64M
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
3.64M
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
3.64M
  return(ret);
5763
3.64M
    }
5764
5765
2.99M
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
6.64M
}
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
13.2k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
13.2k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
13.2k
    int ret = 0;
5778
5779
13.2k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
13.2k
    arg2 = xmlXPathValuePop(ctxt);
5781
13.2k
    arg1 = xmlXPathValuePop(ctxt);
5782
13.2k
    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
13.2k
    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
13.2k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
12.0k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
12.0k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
2.42k
    argtmp = arg2;
5805
2.42k
    arg2 = arg1;
5806
2.42k
    arg1 = argtmp;
5807
2.42k
  }
5808
12.0k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
8.16k
      case XPATH_NODESET:
5812
8.16k
      case XPATH_XSLT_TREE:
5813
8.16k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
8.16k
    break;
5815
3.21k
      case XPATH_BOOLEAN:
5816
3.21k
    if ((arg1->nodesetval == NULL) ||
5817
3.21k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
552
    else
5819
552
        ret = 1;
5820
3.21k
    ret = (ret != arg2->boolval);
5821
3.21k
    break;
5822
342
      case XPATH_NUMBER:
5823
342
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
342
    break;
5825
314
      case XPATH_STRING:
5826
314
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
314
                                                 arg2->stringval, 1);
5828
314
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
12.0k
  }
5833
12.0k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
12.0k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
12.0k
  return(ret);
5836
12.0k
    }
5837
5838
1.25k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
13.2k
}
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
2.99M
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
2.99M
    int ret = 0, arg1i = 0, arg2i = 0;
5866
2.99M
    xmlXPathObjectPtr arg1, arg2;
5867
5868
2.99M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
2.99M
    arg2 = xmlXPathValuePop(ctxt);
5870
2.99M
    arg1 = xmlXPathValuePop(ctxt);
5871
2.99M
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
0
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
0
  else
5875
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
2.99M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
2.95M
      (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
2.95M
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
408k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
400k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
2.55M
  } else {
5890
2.55M
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
2.54M
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
2.54M
                                arg1, arg2);
5893
2.54M
      } else {
5894
8.38k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
8.38k
                                arg2, arg1);
5896
8.38k
      }
5897
2.55M
  }
5898
2.95M
  return(ret);
5899
2.95M
    }
5900
5901
42.5k
    if (arg1->type != XPATH_NUMBER) {
5902
11.5k
  xmlXPathValuePush(ctxt, arg1);
5903
11.5k
  xmlXPathNumberFunction(ctxt, 1);
5904
11.5k
  arg1 = xmlXPathValuePop(ctxt);
5905
11.5k
    }
5906
42.5k
    if (arg2->type != XPATH_NUMBER) {
5907
6.16k
  xmlXPathValuePush(ctxt, arg2);
5908
6.16k
  xmlXPathNumberFunction(ctxt, 1);
5909
6.16k
  arg2 = xmlXPathValuePop(ctxt);
5910
6.16k
    }
5911
42.5k
    if (ctxt->error)
5912
0
        goto error;
5913
    /*
5914
     * Add tests for infinity and nan
5915
     * => feedback on 3.4 for Inf and NaN
5916
     */
5917
    /* Hand check NaN and Infinity comparisons */
5918
42.5k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
25.5k
  ret=0;
5920
25.5k
    } else {
5921
17.0k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
17.0k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
17.0k
  if (inf && strict) {
5924
6.28k
      if ((arg1i == -1 && arg2i != -1) ||
5925
6.01k
    (arg2i == 1 && arg1i != 1)) {
5926
629
    ret = 1;
5927
5.65k
      } else if (arg1i == 0 && arg2i == 0) {
5928
4.23k
    ret = (arg1->floatval < arg2->floatval);
5929
4.23k
      } else {
5930
1.42k
    ret = 0;
5931
1.42k
      }
5932
6.28k
  }
5933
10.7k
  else if (inf && !strict) {
5934
3.44k
      if (arg1i == -1 || arg2i == 1) {
5935
857
    ret = 1;
5936
2.58k
      } else if (arg1i == 0 && arg2i == 0) {
5937
817
    ret = (arg1->floatval <= arg2->floatval);
5938
1.76k
      } else {
5939
1.76k
    ret = 0;
5940
1.76k
      }
5941
3.44k
  }
5942
7.28k
  else if (!inf && strict) {
5943
5.48k
      if ((arg1i == 1 && arg2i != 1) ||
5944
5.13k
    (arg2i == -1 && arg1i != -1)) {
5945
881
    ret = 1;
5946
4.60k
      } else if (arg1i == 0 && arg2i == 0) {
5947
2.18k
    ret = (arg1->floatval > arg2->floatval);
5948
2.42k
      } else {
5949
2.42k
    ret = 0;
5950
2.42k
      }
5951
5.48k
  }
5952
1.80k
  else if (!inf && !strict) {
5953
1.80k
      if (arg1i == 1 || arg2i == -1) {
5954
544
    ret = 1;
5955
1.26k
      } else if (arg1i == 0 && arg2i == 0) {
5956
679
    ret = (arg1->floatval >= arg2->floatval);
5957
679
      } else {
5958
581
    ret = 0;
5959
581
      }
5960
1.80k
  }
5961
17.0k
    }
5962
42.5k
error:
5963
42.5k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
42.5k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
42.5k
    return(ret);
5966
42.5k
}
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
20.8k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
20.8k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
20.8k
    CAST_TO_NUMBER;
5979
20.8k
    CHECK_TYPE(XPATH_NUMBER);
5980
20.8k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
20.8k
}
5982
5983
/**
5984
 * Implement the add operation on XPath objects:
5985
 * The numeric operators convert their operands to numbers as if
5986
 * by calling the number function.
5987
 *
5988
 * @param ctxt  the XPath Parser context
5989
 */
5990
void
5991
2.58M
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
2.58M
    xmlXPathObjectPtr arg;
5993
2.58M
    double val;
5994
5995
2.58M
    arg = xmlXPathValuePop(ctxt);
5996
2.58M
    if (arg == NULL)
5997
2.58M
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
2.58M
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
2.58M
    xmlXPathReleaseObject(ctxt->context, arg);
6000
2.58M
    CAST_TO_NUMBER;
6001
2.58M
    CHECK_TYPE(XPATH_NUMBER);
6002
2.58M
    ctxt->value->floatval += val;
6003
2.58M
}
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
37.4k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
37.4k
    xmlXPathObjectPtr arg;
6015
37.4k
    double val;
6016
6017
37.4k
    arg = xmlXPathValuePop(ctxt);
6018
37.4k
    if (arg == NULL)
6019
37.4k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
37.4k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
37.4k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
37.4k
    CAST_TO_NUMBER;
6023
37.4k
    CHECK_TYPE(XPATH_NUMBER);
6024
37.4k
    ctxt->value->floatval -= val;
6025
37.4k
}
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
1.08M
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
1.08M
    xmlXPathObjectPtr arg;
6037
1.08M
    double val;
6038
6039
1.08M
    arg = xmlXPathValuePop(ctxt);
6040
1.08M
    if (arg == NULL)
6041
1.08M
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
1.08M
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
1.08M
    xmlXPathReleaseObject(ctxt->context, arg);
6044
1.08M
    CAST_TO_NUMBER;
6045
1.08M
    CHECK_TYPE(XPATH_NUMBER);
6046
1.08M
    ctxt->value->floatval *= val;
6047
1.08M
}
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.01k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
1.01k
    xmlXPathObjectPtr arg;
6060
1.01k
    double val;
6061
6062
1.01k
    arg = xmlXPathValuePop(ctxt);
6063
1.01k
    if (arg == NULL)
6064
1.01k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
1.01k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
1.01k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
1.01k
    CAST_TO_NUMBER;
6068
1.01k
    CHECK_TYPE(XPATH_NUMBER);
6069
1.01k
    ctxt->value->floatval /= val;
6070
1.01k
}
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
799
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
799
    xmlXPathObjectPtr arg;
6082
799
    double arg1, arg2;
6083
6084
799
    arg = xmlXPathValuePop(ctxt);
6085
799
    if (arg == NULL)
6086
799
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
799
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
799
    xmlXPathReleaseObject(ctxt->context, arg);
6089
799
    CAST_TO_NUMBER;
6090
799
    CHECK_TYPE(XPATH_NUMBER);
6091
799
    arg1 = ctxt->value->floatval;
6092
799
    if (arg2 == 0)
6093
327
  ctxt->value->floatval = xmlXPathNAN;
6094
472
    else {
6095
472
  ctxt->value->floatval = fmod(arg1, arg2);
6096
472
    }
6097
799
}
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
184
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
184
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
184
    if (cur == NULL)
6141
92
        return(ctxt->context->node);
6142
92
    return(NULL);
6143
184
}
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
459k
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
459k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
459k
    if (cur == NULL) {
6157
229k
  if (ctxt->context->node == NULL) return(NULL);
6158
229k
  switch (ctxt->context->node->type) {
6159
97.0k
            case XML_ELEMENT_NODE:
6160
172k
            case XML_TEXT_NODE:
6161
172k
            case XML_CDATA_SECTION_NODE:
6162
172k
            case XML_ENTITY_REF_NODE:
6163
172k
            case XML_ENTITY_NODE:
6164
228k
            case XML_PI_NODE:
6165
228k
            case XML_COMMENT_NODE:
6166
228k
            case XML_NOTATION_NODE:
6167
228k
            case XML_DTD_NODE:
6168
228k
    return(ctxt->context->node->children);
6169
883
            case XML_DOCUMENT_NODE:
6170
883
            case XML_DOCUMENT_TYPE_NODE:
6171
883
            case XML_DOCUMENT_FRAG_NODE:
6172
883
            case XML_HTML_DOCUMENT_NODE:
6173
883
    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
283
            case XML_ATTRIBUTE_NODE:
6178
283
      case XML_NAMESPACE_DECL:
6179
283
      case XML_XINCLUDE_START:
6180
283
      case XML_XINCLUDE_END:
6181
283
    return(NULL);
6182
229k
  }
6183
0
  return(NULL);
6184
229k
    }
6185
230k
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
230k
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
230k
    return(cur->next);
6189
230k
}
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
42.3M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
42.3M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
42.3M
    if (cur == NULL) {
6203
21.6M
  cur = ctxt->context->node;
6204
21.6M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
21.6M
  switch (cur->type) {
6209
17.3M
            case XML_ELEMENT_NODE:
6210
17.3M
      case XML_DOCUMENT_FRAG_NODE:
6211
17.3M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
17.3M
            case XML_ENTITY_NODE:
6213
17.3M
    cur = cur->children;
6214
17.3M
    if (cur != NULL) {
6215
1.72M
        if (cur->type == XML_ELEMENT_NODE)
6216
734k
      return(cur);
6217
1.05M
        do {
6218
1.05M
      cur = cur->next;
6219
1.05M
        } while ((cur != NULL) &&
6220
413k
      (cur->type != XML_ELEMENT_NODE));
6221
990k
        return(cur);
6222
1.72M
    }
6223
15.6M
    return(NULL);
6224
3.56M
            case XML_DOCUMENT_NODE:
6225
3.56M
            case XML_HTML_DOCUMENT_NODE:
6226
3.56M
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
712k
      default:
6228
712k
    return(NULL);
6229
21.6M
  }
6230
0
  return(NULL);
6231
21.6M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
20.7M
    switch (cur->type) {
6236
20.7M
  case XML_ELEMENT_NODE:
6237
20.7M
  case XML_TEXT_NODE:
6238
20.7M
  case XML_ENTITY_REF_NODE:
6239
20.7M
  case XML_ENTITY_NODE:
6240
20.7M
  case XML_CDATA_SECTION_NODE:
6241
20.7M
  case XML_PI_NODE:
6242
20.7M
  case XML_COMMENT_NODE:
6243
20.7M
  case XML_XINCLUDE_END:
6244
20.7M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
20.7M
    }
6249
20.7M
    if (cur->next != NULL) {
6250
16.8M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
14.8M
      return(cur->next);
6252
1.95M
  cur = cur->next;
6253
2.50M
  do {
6254
2.50M
      cur = cur->next;
6255
2.50M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
1.95M
  return(cur);
6257
16.8M
    }
6258
3.92M
    return(NULL);
6259
20.7M
}
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
22.1M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
22.1M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
22.1M
    if (cur == NULL) {
6274
765k
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
765k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
764k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
313
      return(NULL);
6279
6280
764k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
28.2k
      return(ctxt->context->doc->children);
6282
736k
        return(ctxt->context->node->children);
6283
764k
    }
6284
6285
21.3M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
21.3M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
7.69M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
7.69M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
7.69M
      if (cur->type != XML_DTD_NODE)
6297
7.69M
    return(cur);
6298
7.69M
  }
6299
7.69M
    }
6300
6301
13.7M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
13.7M
    while (cur->next != NULL) {
6304
10.2M
  cur = cur->next;
6305
10.2M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
10.2M
      (cur->type != XML_DTD_NODE))
6307
10.2M
      return(cur);
6308
10.2M
    }
6309
6310
7.75M
    do {
6311
7.75M
        cur = cur->parent;
6312
7.75M
  if (cur == NULL) break;
6313
7.75M
  if (cur == ctxt->context->node) return(NULL);
6314
7.64M
  if (cur->next != NULL) {
6315
3.35M
      cur = cur->next;
6316
3.35M
      return(cur);
6317
3.35M
  }
6318
7.64M
    } while (cur != NULL);
6319
0
    return(cur);
6320
3.47M
}
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
6.55M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
6.55M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
6.55M
    if (cur == NULL)
6337
60.9k
        return(ctxt->context->node);
6338
6339
6.48M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
6.48M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
6.48M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
1.01k
        return(NULL);
6344
6345
6.48M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
6.48M
}
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
1.02M
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
1.02M
    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
1.02M
    if (cur == NULL) {
6365
514k
  if (ctxt->context->node == NULL) return(NULL);
6366
514k
  switch (ctxt->context->node->type) {
6367
178k
            case XML_ELEMENT_NODE:
6368
502k
            case XML_TEXT_NODE:
6369
503k
            case XML_CDATA_SECTION_NODE:
6370
503k
            case XML_ENTITY_REF_NODE:
6371
503k
            case XML_ENTITY_NODE:
6372
510k
            case XML_PI_NODE:
6373
511k
            case XML_COMMENT_NODE:
6374
511k
            case XML_NOTATION_NODE:
6375
511k
            case XML_DTD_NODE:
6376
511k
      case XML_ELEMENT_DECL:
6377
511k
      case XML_ATTRIBUTE_DECL:
6378
511k
      case XML_XINCLUDE_START:
6379
511k
      case XML_XINCLUDE_END:
6380
511k
      case XML_ENTITY_DECL:
6381
511k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
511k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
509k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
509k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
509k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
511k
    return(ctxt->context->node->parent);
6389
353
            case XML_ATTRIBUTE_NODE: {
6390
353
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
353
    return(att->parent);
6393
511k
      }
6394
2.37k
            case XML_DOCUMENT_NODE:
6395
2.37k
            case XML_DOCUMENT_TYPE_NODE:
6396
2.37k
            case XML_DOCUMENT_FRAG_NODE:
6397
2.37k
            case XML_HTML_DOCUMENT_NODE:
6398
2.37k
                return(NULL);
6399
0
      case XML_NAMESPACE_DECL: {
6400
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
0
    if ((ns->next != NULL) &&
6403
0
        (ns->next->type != XML_NAMESPACE_DECL))
6404
0
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
0
      }
6407
514k
  }
6408
514k
    }
6409
511k
    return(NULL);
6410
1.02M
}
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
0
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
0
    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
0
    if (cur == NULL) {
6433
0
  if (ctxt->context->node == NULL) return(NULL);
6434
0
  switch (ctxt->context->node->type) {
6435
0
            case XML_ELEMENT_NODE:
6436
0
            case XML_TEXT_NODE:
6437
0
            case XML_CDATA_SECTION_NODE:
6438
0
            case XML_ENTITY_REF_NODE:
6439
0
            case XML_ENTITY_NODE:
6440
0
            case XML_PI_NODE:
6441
0
            case XML_COMMENT_NODE:
6442
0
      case XML_DTD_NODE:
6443
0
      case XML_ELEMENT_DECL:
6444
0
      case XML_ATTRIBUTE_DECL:
6445
0
      case XML_ENTITY_DECL:
6446
0
            case XML_NOTATION_NODE:
6447
0
      case XML_XINCLUDE_START:
6448
0
      case XML_XINCLUDE_END:
6449
0
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
0
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
0
    return(ctxt->context->node->parent);
6457
0
            case XML_ATTRIBUTE_NODE: {
6458
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
0
    return(tmp->parent);
6461
0
      }
6462
0
            case XML_DOCUMENT_NODE:
6463
0
            case XML_DOCUMENT_TYPE_NODE:
6464
0
            case XML_DOCUMENT_FRAG_NODE:
6465
0
            case XML_HTML_DOCUMENT_NODE:
6466
0
                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
0
  }
6477
0
  return(NULL);
6478
0
    }
6479
0
    if (cur == ctxt->context->doc->children)
6480
0
  return((xmlNodePtr) ctxt->context->doc);
6481
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
0
  return(NULL);
6483
0
    switch (cur->type) {
6484
0
  case XML_ELEMENT_NODE:
6485
0
  case XML_TEXT_NODE:
6486
0
  case XML_CDATA_SECTION_NODE:
6487
0
  case XML_ENTITY_REF_NODE:
6488
0
  case XML_ENTITY_NODE:
6489
0
  case XML_PI_NODE:
6490
0
  case XML_COMMENT_NODE:
6491
0
  case XML_NOTATION_NODE:
6492
0
  case XML_DTD_NODE:
6493
0
        case XML_ELEMENT_DECL:
6494
0
        case XML_ATTRIBUTE_DECL:
6495
0
        case XML_ENTITY_DECL:
6496
0
  case XML_XINCLUDE_START:
6497
0
  case XML_XINCLUDE_END:
6498
0
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
0
    ((cur->parent->name[0] == ' ') ||
6502
0
     (xmlStrEqual(cur->parent->name,
6503
0
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
0
      return(cur->parent);
6506
0
  case XML_ATTRIBUTE_NODE: {
6507
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
0
      return(att->parent);
6510
0
  }
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
0
    }
6526
0
    return(NULL);
6527
0
}
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
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
0
    if (cur == NULL)
6544
0
        return(ctxt->context->node);
6545
0
    return(xmlXPathNextAncestor(ctxt, cur));
6546
0
}
6547
6548
/**
6549
 * Traversal function for the "following-sibling" direction
6550
 * The following-sibling axis contains the following siblings of the context
6551
 * node in document order.
6552
 *
6553
 * @param ctxt  the XPath Parser context
6554
 * @param cur  the current node in the traversal
6555
 * @returns the next element following that axis
6556
 */
6557
xmlNode *
6558
1.42k
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
1.42k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
1.42k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
1.42k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
0
        return(NULL);
6563
6564
1.42k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6565
0
        return(NULL);
6566
6567
1.42k
    if (cur == NULL)
6568
276
        cur = ctxt->context->node;
6569
6570
1.42k
    if (cur->type == XML_DOCUMENT_NODE)
6571
71
        return(NULL);
6572
6573
1.35k
    return(cur->next);
6574
1.42k
}
6575
6576
/**
6577
 * Traversal function for the "preceding-sibling" direction
6578
 * The preceding-sibling axis contains the preceding siblings of the context
6579
 * node in reverse document order; the first preceding sibling is first on the
6580
 * axis; the sibling preceding that node is the second on the axis and so on.
6581
 *
6582
 * @param ctxt  the XPath Parser context
6583
 * @param cur  the current node in the traversal
6584
 * @returns the next element following that axis
6585
 */
6586
xmlNode *
6587
0
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6588
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6590
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6591
0
        return(NULL);
6592
6593
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6594
0
        return(NULL);
6595
6596
0
    if (cur == NULL) {
6597
0
        cur = ctxt->context->node;
6598
0
    } else if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6599
0
        cur = cur->prev;
6600
0
        if (cur == NULL)
6601
0
            cur = ctxt->context->node;
6602
0
    }
6603
6604
0
    if (cur->type == XML_DOCUMENT_NODE)
6605
0
        return(NULL);
6606
6607
0
    return(cur->prev);
6608
0
}
6609
6610
/**
6611
 * Traversal function for the "following" direction
6612
 * The following axis contains all nodes in the same document as the context
6613
 * node that are after the context node in document order, excluding any
6614
 * descendants and excluding attribute nodes and namespace nodes; the nodes
6615
 * are ordered in document order
6616
 *
6617
 * @param ctxt  the XPath Parser context
6618
 * @param cur  the current node in the traversal
6619
 * @returns the next element following that axis
6620
 */
6621
xmlNode *
6622
206
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6623
206
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6624
206
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6625
148
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6626
16
        return(cur->children);
6627
6628
190
    if (cur == NULL) {
6629
58
        cur = ctxt->context->node;
6630
58
        if (cur->type == XML_ATTRIBUTE_NODE) {
6631
0
            cur = cur->parent;
6632
58
        } 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
58
    }
6641
6642
    /* ERROR */
6643
190
    if (cur == NULL)
6644
0
        return(NULL);
6645
6646
190
    if (cur->type == XML_DOCUMENT_NODE)
6647
10
        return(NULL);
6648
6649
180
    if (cur->next != NULL)
6650
100
        return(cur->next);
6651
6652
122
    do {
6653
122
        cur = cur->parent;
6654
122
        if (cur == NULL)
6655
0
            break;
6656
122
        if (cur == (xmlNodePtr) ctxt->context->doc)
6657
48
            return(NULL);
6658
74
        if (cur->next != NULL && cur->type != XML_DOCUMENT_NODE)
6659
32
            return(cur->next);
6660
74
    } while (cur != NULL);
6661
6662
0
    return(cur);
6663
80
}
6664
6665
/*
6666
 * @param ancestor  the ancestor node
6667
 * @param node  the current node
6668
 *
6669
 * Check that `ancestor` is a `node`'s ancestor
6670
 *
6671
 * @returns 1 if `ancestor` is a `node`'s ancestor, 0 otherwise.
6672
 */
6673
static int
6674
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6675
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
6676
0
    if (node->type == XML_NAMESPACE_DECL)
6677
0
        return(0);
6678
0
    if (ancestor->type == XML_NAMESPACE_DECL)
6679
0
        return(0);
6680
    /* nodes need to be in the same document */
6681
0
    if (ancestor->doc != node->doc) return(0);
6682
    /* avoid searching if ancestor or node is the root node */
6683
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
6684
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
6685
0
    while (node->parent != NULL) {
6686
0
        if (node->parent == ancestor)
6687
0
            return(1);
6688
0
  node = node->parent;
6689
0
    }
6690
0
    return(0);
6691
0
}
6692
6693
/**
6694
 * Traversal function for the "preceding" direction
6695
 * the preceding axis contains all nodes in the same document as the context
6696
 * node that are before the context node in document order, excluding any
6697
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6698
 * ordered in reverse document order
6699
 *
6700
 * @param ctxt  the XPath Parser context
6701
 * @param cur  the current node in the traversal
6702
 * @returns the next element following that axis
6703
 */
6704
xmlNode *
6705
xmlXPathNextPreceding(xmlXPathParserContext *ctxt, xmlNode *cur)
6706
0
{
6707
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6708
0
    if (cur == NULL) {
6709
0
        cur = ctxt->context->node;
6710
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6711
0
            cur = cur->parent;
6712
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6713
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6714
6715
0
            if ((ns->next == NULL) ||
6716
0
                (ns->next->type == XML_NAMESPACE_DECL))
6717
0
                return (NULL);
6718
0
            cur = (xmlNodePtr) ns->next;
6719
0
        }
6720
0
    }
6721
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6722
0
  return (NULL);
6723
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6724
0
  cur = cur->prev;
6725
0
    do {
6726
0
        if (cur->prev != NULL) {
6727
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6728
0
            return (cur);
6729
0
        }
6730
6731
0
        cur = cur->parent;
6732
0
        if (cur == NULL)
6733
0
            return (NULL);
6734
0
        if (cur == ctxt->context->doc->children)
6735
0
            return (NULL);
6736
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6737
0
    return (cur);
6738
0
}
6739
6740
/**
6741
 * Traversal function for the "preceding" direction
6742
 * the preceding axis contains all nodes in the same document as the context
6743
 * node that are before the context node in document order, excluding any
6744
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6745
 * ordered in reverse document order
6746
 * This is a faster implementation but internal only since it requires a
6747
 * state kept in the parser context: ctxt->ancestor.
6748
 *
6749
 * @param ctxt  the XPath Parser context
6750
 * @param cur  the current node in the traversal
6751
 * @returns the next element following that axis
6752
 */
6753
static xmlNodePtr
6754
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6755
                              xmlNodePtr cur)
6756
0
{
6757
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6758
0
    if (cur == NULL) {
6759
0
        cur = ctxt->context->node;
6760
0
        if (cur == NULL)
6761
0
            return (NULL);
6762
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6763
0
            cur = cur->parent;
6764
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6765
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6766
6767
0
            if ((ns->next == NULL) ||
6768
0
                (ns->next->type == XML_NAMESPACE_DECL))
6769
0
                return (NULL);
6770
0
            cur = (xmlNodePtr) ns->next;
6771
0
        }
6772
0
        ctxt->ancestor = cur->parent;
6773
0
    }
6774
6775
0
    if (cur->type == XML_NAMESPACE_DECL || cur->type == XML_DOCUMENT_NODE)
6776
0
        return(NULL);
6777
6778
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6779
0
  cur = cur->prev;
6780
6781
0
    while (cur->prev == NULL) {
6782
0
        cur = cur->parent;
6783
0
        if (cur == NULL)
6784
0
            return (NULL);
6785
0
        if (cur == ctxt->context->doc->children)
6786
0
            return (NULL);
6787
0
        if (cur != ctxt->ancestor)
6788
0
            return (cur);
6789
0
        ctxt->ancestor = cur->parent;
6790
0
    }
6791
6792
0
    if (cur->type == XML_DOCUMENT_NODE)
6793
0
        return(NULL);
6794
6795
0
    cur = cur->prev;
6796
0
    while (cur->last != NULL)
6797
0
        cur = cur->last;
6798
0
    return (cur);
6799
0
}
6800
6801
/**
6802
 * Traversal function for the "namespace" direction
6803
 * the namespace axis contains the namespace nodes of the context node;
6804
 * the order of nodes on this axis is implementation-defined; the axis will
6805
 * be empty unless the context node is an element
6806
 *
6807
 * We keep the XML namespace node at the end of the list.
6808
 *
6809
 * @param ctxt  the XPath Parser context
6810
 * @param cur  the current attribute in the traversal
6811
 * @returns the next element following that axis
6812
 */
6813
xmlNode *
6814
0
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6815
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6816
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6817
0
    if (cur == NULL) {
6818
0
        if (ctxt->context->tmpNsList != NULL)
6819
0
      xmlFree(ctxt->context->tmpNsList);
6820
0
  ctxt->context->tmpNsNr = 0;
6821
0
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6822
0
                             &ctxt->context->tmpNsList) < 0) {
6823
0
            xmlXPathPErrMemory(ctxt);
6824
0
            return(NULL);
6825
0
        }
6826
0
        if (ctxt->context->tmpNsList != NULL) {
6827
0
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6828
0
                ctxt->context->tmpNsNr++;
6829
0
            }
6830
0
        }
6831
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
6832
0
    }
6833
0
    if (ctxt->context->tmpNsNr > 0) {
6834
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6835
0
    } else {
6836
0
  if (ctxt->context->tmpNsList != NULL)
6837
0
      xmlFree(ctxt->context->tmpNsList);
6838
0
  ctxt->context->tmpNsList = NULL;
6839
0
  return(NULL);
6840
0
    }
6841
0
}
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
346k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6853
346k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854
346k
    if (ctxt->context->node == NULL)
6855
0
  return(NULL);
6856
346k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6857
140k
  return(NULL);
6858
206k
    if (cur == NULL) {
6859
138k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6860
0
      return(NULL);
6861
138k
        return((xmlNodePtr)ctxt->context->node->properties);
6862
138k
    }
6863
67.7k
    return((xmlNodePtr)cur->next);
6864
206k
}
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
3.68M
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6888
3.68M
    if ((ctxt == NULL) || (ctxt->context == NULL))
6889
0
  return;
6890
3.68M
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6891
3.68M
                                            (xmlNodePtr) ctxt->context->doc));
6892
3.68M
}
6893
6894
/************************************************************************
6895
 *                  *
6896
 *    The explicit core function library      *
6897
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6898
 *                  *
6899
 ************************************************************************/
6900
6901
6902
/**
6903
 * Implement the last() XPath function
6904
 *    number last()
6905
 * The last function returns the number of nodes in the context node list.
6906
 *
6907
 * @param ctxt  the XPath Parser context
6908
 * @param nargs  the number of arguments
6909
 */
6910
void
6911
0
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6912
0
    CHECK_ARITY(0);
6913
0
    if (ctxt->context->contextSize >= 0) {
6914
0
  xmlXPathValuePush(ctxt,
6915
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6916
0
    } else {
6917
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6918
0
    }
6919
0
}
6920
6921
/**
6922
 * Implement the position() XPath function
6923
 *    number position()
6924
 * The position function returns the position of the context node in the
6925
 * context node list. The first position is 1, and so the last position
6926
 * will be equal to last().
6927
 *
6928
 * @param ctxt  the XPath Parser context
6929
 * @param nargs  the number of arguments
6930
 */
6931
void
6932
0
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6933
0
    CHECK_ARITY(0);
6934
0
    if (ctxt->context->proximityPosition >= 0) {
6935
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6936
0
            (double) ctxt->context->proximityPosition));
6937
0
    } else {
6938
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6939
0
    }
6940
0
}
6941
6942
/**
6943
 * Implement the count() XPath function
6944
 *    number count(node-set)
6945
 *
6946
 * @param ctxt  the XPath Parser context
6947
 * @param nargs  the number of arguments
6948
 */
6949
void
6950
14
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6951
14
    xmlXPathObjectPtr cur;
6952
6953
40
    CHECK_ARITY(1);
6954
40
    if ((ctxt->value == NULL) ||
6955
13
  ((ctxt->value->type != XPATH_NODESET) &&
6956
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
6957
12
  XP_ERROR(XPATH_INVALID_TYPE);
6958
12
    cur = xmlXPathValuePop(ctxt);
6959
6960
12
    if ((cur == NULL) || (cur->nodesetval == NULL))
6961
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6962
12
    else
6963
12
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6964
12
      (double) cur->nodesetval->nodeNr));
6965
12
    xmlXPathReleaseObject(ctxt->context, cur);
6966
12
}
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
13.3k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6977
13.3k
    xmlNodeSetPtr ret;
6978
13.3k
    const xmlChar *cur = ids;
6979
13.3k
    xmlChar *ID;
6980
13.3k
    xmlAttrPtr attr;
6981
13.3k
    xmlNodePtr elem = NULL;
6982
6983
13.3k
    if (ids == NULL) return(NULL);
6984
6985
13.3k
    ret = xmlXPathNodeSetCreate(NULL);
6986
13.3k
    if (ret == NULL)
6987
0
        return(ret);
6988
6989
16.5k
    while (IS_BLANK_CH(*cur)) cur++;
6990
55.1k
    while (*cur != 0) {
6991
465k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6992
423k
      cur++;
6993
6994
41.8k
        ID = xmlStrndup(ids, cur - ids);
6995
41.8k
  if (ID == NULL) {
6996
0
            xmlXPathFreeNodeSet(ret);
6997
0
            return(NULL);
6998
0
        }
6999
        /*
7000
         * We used to check the fact that the value passed
7001
         * was an NCName, but this generated much troubles for
7002
         * me and Aleksey Sanin, people blatantly violated that
7003
         * constraint, like Visa3D spec.
7004
         * if (xmlValidateNCName(ID, 1) == 0)
7005
         */
7006
41.8k
        attr = xmlGetID(doc, ID);
7007
41.8k
        xmlFree(ID);
7008
41.8k
        if (attr != NULL) {
7009
3.34k
            if (attr->type == XML_ATTRIBUTE_NODE)
7010
3.34k
                elem = attr->parent;
7011
0
            else if (attr->type == XML_ELEMENT_NODE)
7012
0
                elem = (xmlNodePtr) attr;
7013
0
            else
7014
0
                elem = NULL;
7015
3.34k
            if (elem != NULL) {
7016
3.34k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7017
0
                    xmlXPathFreeNodeSet(ret);
7018
0
                    return(NULL);
7019
0
                }
7020
3.34k
            }
7021
3.34k
        }
7022
7023
253k
  while (IS_BLANK_CH(*cur)) cur++;
7024
41.8k
  ids = cur;
7025
41.8k
    }
7026
13.3k
    return(ret);
7027
13.3k
}
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
9.27k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7048
9.27k
    xmlChar *tokens;
7049
9.27k
    xmlNodeSetPtr ret;
7050
9.27k
    xmlXPathObjectPtr obj;
7051
7052
24.8k
    CHECK_ARITY(1);
7053
24.8k
    obj = xmlXPathValuePop(ctxt);
7054
24.8k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7055
7.79k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7056
2.78k
  xmlNodeSetPtr ns;
7057
2.78k
  int i;
7058
7059
2.78k
  ret = xmlXPathNodeSetCreate(NULL);
7060
2.78k
        if (ret == NULL)
7061
0
            xmlXPathPErrMemory(ctxt);
7062
7063
2.78k
  if (obj->nodesetval != NULL) {
7064
11.0k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7065
8.29k
    tokens =
7066
8.29k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7067
8.29k
                if (tokens == NULL)
7068
0
                    xmlXPathPErrMemory(ctxt);
7069
8.29k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7070
8.29k
                if (ns == NULL)
7071
0
                    xmlXPathPErrMemory(ctxt);
7072
8.29k
    ret = xmlXPathNodeSetMerge(ret, ns);
7073
8.29k
                if (ret == NULL)
7074
0
                    xmlXPathPErrMemory(ctxt);
7075
8.29k
    xmlXPathFreeNodeSet(ns);
7076
8.29k
    if (tokens != NULL)
7077
8.29k
        xmlFree(tokens);
7078
8.29k
      }
7079
2.78k
  }
7080
2.78k
  xmlXPathReleaseObject(ctxt->context, obj);
7081
2.78k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7082
2.78k
  return;
7083
2.78k
    }
7084
5.00k
    tokens = xmlXPathCastToString(obj);
7085
5.00k
    if (tokens == NULL)
7086
0
        xmlXPathPErrMemory(ctxt);
7087
5.00k
    xmlXPathReleaseObject(ctxt->context, obj);
7088
5.00k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7089
5.00k
    if (ret == NULL)
7090
0
        xmlXPathPErrMemory(ctxt);
7091
5.00k
    xmlFree(tokens);
7092
5.00k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7093
5.00k
}
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
261
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7109
261
    xmlXPathObjectPtr cur;
7110
7111
261
    if (ctxt == NULL) return;
7112
7113
261
    if (nargs == 0) {
7114
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7115
0
  nargs = 1;
7116
0
    }
7117
7118
783
    CHECK_ARITY(1);
7119
783
    if ((ctxt->value == NULL) ||
7120
261
  ((ctxt->value->type != XPATH_NODESET) &&
7121
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7122
261
  XP_ERROR(XPATH_INVALID_TYPE);
7123
261
    cur = xmlXPathValuePop(ctxt);
7124
7125
261
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7126
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7127
261
    } else {
7128
261
  int i = 0; /* Should be first in document order !!!!! */
7129
261
  switch (cur->nodesetval->nodeTab[i]->type) {
7130
0
  case XML_ELEMENT_NODE:
7131
0
  case XML_ATTRIBUTE_NODE:
7132
1
  case XML_PI_NODE:
7133
1
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7134
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7135
1
      else
7136
1
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7137
1
      cur->nodesetval->nodeTab[i]->name));
7138
1
      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
260
  default:
7144
260
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7145
261
  }
7146
261
    }
7147
261
    xmlXPathReleaseObject(ctxt->context, cur);
7148
261
}
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
2.29k
{
7224
2.29k
    xmlXPathObjectPtr cur;
7225
7226
2.29k
    if (nargs == 0) {
7227
1.70k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7228
1.70k
        nargs = 1;
7229
1.70k
    }
7230
7231
6.88k
    CHECK_ARITY(1);
7232
6.88k
    if ((ctxt->value == NULL) ||
7233
2.29k
        ((ctxt->value->type != XPATH_NODESET) &&
7234
3
         (ctxt->value->type != XPATH_XSLT_TREE)))
7235
2.29k
        XP_ERROR(XPATH_INVALID_TYPE);
7236
2.29k
    cur = xmlXPathValuePop(ctxt);
7237
7238
2.29k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7239
241
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7240
2.05k
    } else {
7241
2.05k
        int i = 0;              /* Should be first in document order !!!!! */
7242
7243
2.05k
        switch (cur->nodesetval->nodeTab[i]->type) {
7244
375
            case XML_ELEMENT_NODE:
7245
1.79k
            case XML_ATTRIBUTE_NODE:
7246
1.79k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7247
0
        xmlXPathValuePush(ctxt,
7248
0
      xmlXPathCacheNewCString(ctxt, ""));
7249
1.79k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7250
1.55k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7251
1.55k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7252
1.55k
          cur->nodesetval->nodeTab[i]->name));
7253
1.55k
    } else {
7254
238
        xmlChar *fullname;
7255
7256
238
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7257
238
             cur->nodesetval->nodeTab[i]->ns->prefix,
7258
238
             NULL, 0);
7259
238
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7260
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7261
238
        if (fullname == NULL)
7262
0
                        xmlXPathPErrMemory(ctxt);
7263
238
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7264
238
                }
7265
1.79k
                break;
7266
261
            default:
7267
261
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7268
261
        cur->nodesetval->nodeTab[i]));
7269
261
                xmlXPathLocalNameFunction(ctxt, 1);
7270
2.05k
        }
7271
2.05k
    }
7272
2.29k
    xmlXPathReleaseObject(ctxt->context, cur);
7273
2.29k
}
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
13.8k
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7313
13.8k
    xmlXPathObjectPtr cur;
7314
13.8k
    xmlChar *stringval;
7315
7316
13.8k
    if (ctxt == NULL) return;
7317
13.8k
    if (nargs == 0) {
7318
1
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7319
1
        if (stringval == NULL)
7320
0
            xmlXPathPErrMemory(ctxt);
7321
1
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7322
1
  return;
7323
1
    }
7324
7325
55.5k
    CHECK_ARITY(1);
7326
55.5k
    cur = xmlXPathValuePop(ctxt);
7327
55.5k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7328
13.8k
    if (cur->type != XPATH_STRING) {
7329
13.8k
        stringval = xmlXPathCastToString(cur);
7330
13.8k
        if (stringval == NULL)
7331
0
            xmlXPathPErrMemory(ctxt);
7332
13.8k
        xmlXPathReleaseObject(ctxt->context, cur);
7333
13.8k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7334
13.8k
    }
7335
13.8k
    xmlXPathValuePush(ctxt, cur);
7336
13.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
0
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7351
0
    xmlXPathObjectPtr cur;
7352
7353
0
    if (nargs == 0) {
7354
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7355
0
      return;
7356
0
  if (ctxt->context->node == NULL) {
7357
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7358
0
  } else {
7359
0
      xmlChar *content;
7360
7361
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7362
0
            if (content == NULL)
7363
0
                xmlXPathPErrMemory(ctxt);
7364
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7365
0
    xmlUTF8Strlen(content)));
7366
0
      xmlFree(content);
7367
0
  }
7368
0
  return;
7369
0
    }
7370
0
    CHECK_ARITY(1);
7371
0
    CAST_TO_STRING;
7372
0
    CHECK_TYPE(XPATH_STRING);
7373
0
    cur = xmlXPathValuePop(ctxt);
7374
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7375
0
  xmlUTF8Strlen(cur->stringval)));
7376
0
    xmlXPathReleaseObject(ctxt->context, cur);
7377
0
}
7378
7379
/**
7380
 * Implement the concat() XPath function
7381
 *    string concat(string, string, string*)
7382
 * The concat function returns the concatenation of its arguments.
7383
 *
7384
 * @param ctxt  the XPath Parser context
7385
 * @param nargs  the number of arguments
7386
 */
7387
void
7388
0
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7389
0
    xmlXPathObjectPtr cur, newobj;
7390
0
    xmlChar *tmp;
7391
7392
0
    if (ctxt == NULL) return;
7393
0
    if (nargs < 2) {
7394
0
  CHECK_ARITY(2);
7395
0
    }
7396
7397
0
    CAST_TO_STRING;
7398
0
    cur = xmlXPathValuePop(ctxt);
7399
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7400
0
  xmlXPathReleaseObject(ctxt->context, cur);
7401
0
  return;
7402
0
    }
7403
0
    nargs--;
7404
7405
0
    while (nargs > 0) {
7406
0
  CAST_TO_STRING;
7407
0
  newobj = xmlXPathValuePop(ctxt);
7408
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7409
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7410
0
      xmlXPathReleaseObject(ctxt->context, cur);
7411
0
      XP_ERROR(XPATH_INVALID_TYPE);
7412
0
  }
7413
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7414
0
        if (tmp == NULL)
7415
0
            xmlXPathPErrMemory(ctxt);
7416
0
  newobj->stringval = cur->stringval;
7417
0
  cur->stringval = tmp;
7418
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7419
0
  nargs--;
7420
0
    }
7421
0
    xmlXPathValuePush(ctxt, cur);
7422
0
}
7423
7424
/**
7425
 * Implement the contains() XPath function
7426
 *    boolean contains(string, string)
7427
 * The contains function returns true if the first argument string
7428
 * contains the second argument string, and otherwise returns false.
7429
 *
7430
 * @param ctxt  the XPath Parser context
7431
 * @param nargs  the number of arguments
7432
 */
7433
void
7434
0
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7435
0
    xmlXPathObjectPtr hay, needle;
7436
7437
0
    CHECK_ARITY(2);
7438
0
    CAST_TO_STRING;
7439
0
    CHECK_TYPE(XPATH_STRING);
7440
0
    needle = xmlXPathValuePop(ctxt);
7441
0
    CAST_TO_STRING;
7442
0
    hay = xmlXPathValuePop(ctxt);
7443
7444
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7445
0
  xmlXPathReleaseObject(ctxt->context, hay);
7446
0
  xmlXPathReleaseObject(ctxt->context, needle);
7447
0
  XP_ERROR(XPATH_INVALID_TYPE);
7448
0
    }
7449
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7450
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7451
0
    else
7452
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7453
0
    xmlXPathReleaseObject(ctxt->context, hay);
7454
0
    xmlXPathReleaseObject(ctxt->context, needle);
7455
0
}
7456
7457
/**
7458
 * Implement the starts-with() XPath function
7459
 *    boolean starts-with(string, string)
7460
 * The starts-with function returns true if the first argument string
7461
 * starts with the second argument string, and otherwise returns false.
7462
 *
7463
 * @param ctxt  the XPath Parser context
7464
 * @param nargs  the number of arguments
7465
 */
7466
void
7467
0
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7468
0
    xmlXPathObjectPtr hay, needle;
7469
0
    int n;
7470
7471
0
    CHECK_ARITY(2);
7472
0
    CAST_TO_STRING;
7473
0
    CHECK_TYPE(XPATH_STRING);
7474
0
    needle = xmlXPathValuePop(ctxt);
7475
0
    CAST_TO_STRING;
7476
0
    hay = xmlXPathValuePop(ctxt);
7477
7478
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7479
0
  xmlXPathReleaseObject(ctxt->context, hay);
7480
0
  xmlXPathReleaseObject(ctxt->context, needle);
7481
0
  XP_ERROR(XPATH_INVALID_TYPE);
7482
0
    }
7483
0
    n = xmlStrlen(needle->stringval);
7484
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7485
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7486
0
    else
7487
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7488
0
    xmlXPathReleaseObject(ctxt->context, hay);
7489
0
    xmlXPathReleaseObject(ctxt->context, needle);
7490
0
}
7491
7492
/**
7493
 * Implement the substring() XPath function
7494
 *    string substring(string, number, number?)
7495
 * The substring function returns the substring of the first argument
7496
 * starting at the position specified in the second argument with
7497
 * length specified in the third argument. For example,
7498
 * substring("12345",2,3) returns "234". If the third argument is not
7499
 * specified, it returns the substring starting at the position specified
7500
 * in the second argument and continuing to the end of the string. For
7501
 * example, substring("12345",2) returns "2345".  More precisely, each
7502
 * character in the string (see [3.6 Strings]) is considered to have a
7503
 * numeric position: the position of the first character is 1, the position
7504
 * of the second character is 2 and so on. The returned substring contains
7505
 * those characters for which the position of the character is greater than
7506
 * or equal to the second argument and, if the third argument is specified,
7507
 * less than the sum of the second and third arguments; the comparisons
7508
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7509
 *  - substring("12345", 1.5, 2.6) returns "234"
7510
 *  - substring("12345", 0, 3) returns "12"
7511
 *  - substring("12345", 0 div 0, 3) returns ""
7512
 *  - substring("12345", 1, 0 div 0) returns ""
7513
 *  - substring("12345", -42, 1 div 0) returns "12345"
7514
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
7515
 *
7516
 * @param ctxt  the XPath Parser context
7517
 * @param nargs  the number of arguments
7518
 */
7519
void
7520
463
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7521
463
    xmlXPathObjectPtr str, start, len;
7522
463
    double le=0, in;
7523
463
    int i = 1, j = INT_MAX;
7524
7525
463
    if (nargs < 2) {
7526
2
  CHECK_ARITY(2);
7527
2
    }
7528
461
    if (nargs > 3) {
7529
3
  CHECK_ARITY(3);
7530
3
    }
7531
    /*
7532
     * take care of possible last (position) argument
7533
    */
7534
458
    if (nargs == 3) {
7535
164
  CAST_TO_NUMBER;
7536
164
  CHECK_TYPE(XPATH_NUMBER);
7537
164
  len = xmlXPathValuePop(ctxt);
7538
164
  le = len->floatval;
7539
164
  xmlXPathReleaseObject(ctxt->context, len);
7540
164
    }
7541
7542
458
    CAST_TO_NUMBER;
7543
458
    CHECK_TYPE(XPATH_NUMBER);
7544
458
    start = xmlXPathValuePop(ctxt);
7545
458
    in = start->floatval;
7546
458
    xmlXPathReleaseObject(ctxt->context, start);
7547
458
    CAST_TO_STRING;
7548
458
    CHECK_TYPE(XPATH_STRING);
7549
458
    str = xmlXPathValuePop(ctxt);
7550
7551
458
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7552
178
        i = INT_MAX;
7553
280
    } else if (in >= 1.0) {
7554
193
        i = (int)in;
7555
193
        if (in - floor(in) >= 0.5)
7556
2
            i += 1;
7557
193
    }
7558
7559
458
    if (nargs == 3) {
7560
164
        double rin, rle, end;
7561
7562
164
        rin = floor(in);
7563
164
        if (in - rin >= 0.5)
7564
1
            rin += 1.0;
7565
7566
164
        rle = floor(le);
7567
164
        if (le - rle >= 0.5)
7568
1
            rle += 1.0;
7569
7570
164
        end = rin + rle;
7571
164
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7572
128
            j = 1;
7573
128
        } else if (end < INT_MAX) {
7574
23
            j = (int)end;
7575
23
        }
7576
164
    }
7577
7578
458
    i -= 1;
7579
458
    j -= 1;
7580
7581
458
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7582
157
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7583
157
        if (ret == NULL)
7584
0
            xmlXPathPErrMemory(ctxt);
7585
157
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7586
157
  xmlFree(ret);
7587
301
    } else {
7588
301
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7589
301
    }
7590
7591
458
    xmlXPathReleaseObject(ctxt->context, str);
7592
458
}
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
296
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7608
296
    xmlXPathObjectPtr str = NULL;
7609
296
    xmlXPathObjectPtr find = NULL;
7610
296
    const xmlChar *point;
7611
296
    xmlChar *result;
7612
7613
872
    CHECK_ARITY(2);
7614
872
    CAST_TO_STRING;
7615
872
    find = xmlXPathValuePop(ctxt);
7616
872
    CAST_TO_STRING;
7617
872
    str = xmlXPathValuePop(ctxt);
7618
872
    if (ctxt->error != 0)
7619
0
        goto error;
7620
7621
288
    point = xmlStrstr(str->stringval, find->stringval);
7622
288
    if (point == NULL) {
7623
119
        result = xmlStrdup(BAD_CAST "");
7624
169
    } else {
7625
169
        result = xmlStrndup(str->stringval, point - str->stringval);
7626
169
    }
7627
288
    if (result == NULL) {
7628
0
        xmlXPathPErrMemory(ctxt);
7629
0
        goto error;
7630
0
    }
7631
288
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7632
7633
288
error:
7634
288
    xmlXPathReleaseObject(ctxt->context, str);
7635
288
    xmlXPathReleaseObject(ctxt->context, find);
7636
288
}
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
233
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7653
233
    xmlXPathObjectPtr str = NULL;
7654
233
    xmlXPathObjectPtr find = NULL;
7655
233
    const xmlChar *point;
7656
233
    xmlChar *result;
7657
7658
695
    CHECK_ARITY(2);
7659
695
    CAST_TO_STRING;
7660
695
    find = xmlXPathValuePop(ctxt);
7661
695
    CAST_TO_STRING;
7662
695
    str = xmlXPathValuePop(ctxt);
7663
695
    if (ctxt->error != 0)
7664
0
        goto error;
7665
7666
231
    point = xmlStrstr(str->stringval, find->stringval);
7667
231
    if (point == NULL) {
7668
174
        result = xmlStrdup(BAD_CAST "");
7669
174
    } else {
7670
57
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7671
57
    }
7672
231
    if (result == NULL) {
7673
0
        xmlXPathPErrMemory(ctxt);
7674
0
        goto error;
7675
0
    }
7676
231
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7677
7678
231
error:
7679
231
    xmlXPathReleaseObject(ctxt->context, str);
7680
231
    xmlXPathReleaseObject(ctxt->context, find);
7681
231
}
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
263
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7763
263
    xmlXPathObjectPtr str = NULL;
7764
263
    xmlXPathObjectPtr from = NULL;
7765
263
    xmlXPathObjectPtr to = NULL;
7766
263
    xmlBufPtr target;
7767
263
    int offset, max;
7768
263
    int ch;
7769
263
    const xmlChar *point;
7770
263
    xmlChar *cptr, *content;
7771
7772
777
    CHECK_ARITY(3);
7773
7774
777
    CAST_TO_STRING;
7775
777
    to = xmlXPathValuePop(ctxt);
7776
777
    CAST_TO_STRING;
7777
777
    from = xmlXPathValuePop(ctxt);
7778
777
    CAST_TO_STRING;
7779
777
    str = xmlXPathValuePop(ctxt);
7780
777
    if (ctxt->error != 0)
7781
0
        goto error;
7782
7783
    /*
7784
     * Account for quadratic runtime
7785
     */
7786
257
    if (ctxt->context->opLimit != 0) {
7787
0
        unsigned long f1 = xmlStrlen(from->stringval);
7788
0
        unsigned long f2 = xmlStrlen(str->stringval);
7789
7790
0
        if ((f1 > 0) && (f2 > 0)) {
7791
0
            unsigned long p;
7792
7793
0
            f1 = f1 / 10 + 1;
7794
0
            f2 = f2 / 10 + 1;
7795
0
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7796
0
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7797
0
                goto error;
7798
0
        }
7799
0
    }
7800
7801
257
    target = xmlBufCreate(50);
7802
257
    if (target == NULL) {
7803
0
        xmlXPathPErrMemory(ctxt);
7804
0
        goto error;
7805
0
    }
7806
7807
257
    max = xmlUTF8Strlen(to->stringval);
7808
1.40M
    for (cptr = str->stringval; (ch=*cptr); ) {
7809
1.40M
        offset = xmlUTF8Strloc(from->stringval, cptr);
7810
1.40M
        if (offset >= 0) {
7811
1.18M
            if (offset < max) {
7812
1.13M
                point = xmlUTF8Strpos(to->stringval, offset);
7813
1.13M
                if (point)
7814
1.13M
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7815
1.13M
            }
7816
1.18M
        } else
7817
221k
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7818
7819
        /* Step to next character in input */
7820
1.40M
        cptr++;
7821
1.40M
        if ( ch & 0x80 ) {
7822
            /* if not simple ascii, verify proper format */
7823
1.32k
            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
3.80k
            while ( (ch <<= 1) & 0x80 )
7829
2.48k
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7830
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7831
0
                    break;
7832
0
                }
7833
1.32k
            if (ch & 0x80) /* must have had error encountered */
7834
0
                break;
7835
1.32k
        }
7836
1.40M
    }
7837
7838
257
    content = xmlBufDetach(target);
7839
257
    if (content == NULL)
7840
0
        xmlXPathPErrMemory(ctxt);
7841
257
    else
7842
257
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7843
257
    xmlBufFree(target);
7844
257
error:
7845
257
    xmlXPathReleaseObject(ctxt->context, str);
7846
257
    xmlXPathReleaseObject(ctxt->context, from);
7847
257
    xmlXPathReleaseObject(ctxt->context, to);
7848
257
}
7849
7850
/**
7851
 * Implement the boolean() XPath function
7852
 *    boolean boolean(object)
7853
 * The boolean function converts its argument to a boolean as follows:
7854
 *    - a number is true if and only if it is neither positive or
7855
 *      negative zero nor NaN
7856
 *    - a node-set is true if and only if it is non-empty
7857
 *    - a string is true if and only if its length is non-zero
7858
 *
7859
 * @param ctxt  the XPath Parser context
7860
 * @param nargs  the number of arguments
7861
 */
7862
void
7863
1.04M
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7864
1.04M
    xmlXPathObjectPtr cur;
7865
7866
3.14M
    CHECK_ARITY(1);
7867
3.14M
    cur = xmlXPathValuePop(ctxt);
7868
3.14M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7869
1.04M
    if (cur->type != XPATH_BOOLEAN) {
7870
79.8k
        int boolval = xmlXPathCastToBoolean(cur);
7871
7872
79.8k
        xmlXPathReleaseObject(ctxt->context, cur);
7873
79.8k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7874
79.8k
    }
7875
1.04M
    xmlXPathValuePush(ctxt, cur);
7876
1.04M
}
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
29
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7889
85
    CHECK_ARITY(1);
7890
85
    CAST_TO_BOOLEAN;
7891
85
    CHECK_TYPE(XPATH_BOOLEAN);
7892
28
    ctxt->value->boolval = ! ctxt->value->boolval;
7893
28
}
7894
7895
/**
7896
 * Implement the true() XPath function
7897
 *    boolean true()
7898
 *
7899
 * @param ctxt  the XPath Parser context
7900
 * @param nargs  the number of arguments
7901
 */
7902
void
7903
0
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7904
0
    CHECK_ARITY(0);
7905
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7906
0
}
7907
7908
/**
7909
 * Implement the false() XPath function
7910
 *    boolean false()
7911
 *
7912
 * @param ctxt  the XPath Parser context
7913
 * @param nargs  the number of arguments
7914
 */
7915
void
7916
0
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7917
0
    CHECK_ARITY(0);
7918
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7919
0
}
7920
7921
/**
7922
 * Implement the lang() XPath function
7923
 *    boolean lang(string)
7924
 * The lang function returns true or false depending on whether the
7925
 * language of the context node as specified by xml:lang attributes
7926
 * is the same as or is a sublanguage of the language specified by
7927
 * the argument string. The language of the context node is determined
7928
 * by the value of the xml:lang attribute on the context node, or, if
7929
 * the context node has no xml:lang attribute, by the value of the
7930
 * xml:lang attribute on the nearest ancestor of the context node that
7931
 * has an xml:lang attribute. If there is no such attribute, then
7932
 * lang returns false. If there is such an attribute, then lang returns
7933
 * true if the attribute value is equal to the argument ignoring case,
7934
 * or if there is some suffix starting with - such that the attribute
7935
 * value is equal to the argument ignoring that suffix of the attribute
7936
 * value and ignoring case.
7937
 *
7938
 * @param ctxt  the XPath Parser context
7939
 * @param nargs  the number of arguments
7940
 */
7941
void
7942
11.8k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7943
11.8k
    xmlXPathObjectPtr val;
7944
11.8k
    xmlNodePtr cur;
7945
11.8k
    xmlChar *theLang = NULL;
7946
11.8k
    const xmlChar *lang;
7947
11.8k
    int ret = 0;
7948
11.8k
    int i;
7949
7950
35.4k
    CHECK_ARITY(1);
7951
35.4k
    CAST_TO_STRING;
7952
35.4k
    CHECK_TYPE(XPATH_STRING);
7953
11.8k
    val = xmlXPathValuePop(ctxt);
7954
11.8k
    lang = val->stringval;
7955
11.8k
    cur = ctxt->context->node;
7956
60.1k
    while (cur != NULL) {
7957
48.3k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7958
48.3k
                                &theLang) < 0)
7959
0
            xmlXPathPErrMemory(ctxt);
7960
48.3k
        if (theLang != NULL)
7961
69
            break;
7962
48.3k
        cur = cur->parent;
7963
48.3k
    }
7964
11.8k
    if ((theLang != NULL) && (lang != NULL)) {
7965
1.48k
        for (i = 0;lang[i] != 0;i++)
7966
1.44k
            if (toupper(lang[i]) != toupper(theLang[i]))
7967
28
                goto not_equal;
7968
41
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7969
30
            ret = 1;
7970
41
    }
7971
11.8k
not_equal:
7972
11.8k
    if (theLang != NULL)
7973
69
  xmlFree((void *)theLang);
7974
7975
11.8k
    xmlXPathReleaseObject(ctxt->context, val);
7976
11.8k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7977
11.8k
}
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
2.82M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7988
2.82M
    xmlXPathObjectPtr cur;
7989
2.82M
    double res;
7990
7991
2.82M
    if (ctxt == NULL) return;
7992
2.82M
    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
11.2M
    CHECK_ARITY(1);
8008
11.2M
    cur = xmlXPathValuePop(ctxt);
8009
11.2M
    if (cur->type != XPATH_NUMBER) {
8010
2.82M
        double floatval;
8011
8012
2.82M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8013
2.82M
        xmlXPathReleaseObject(ctxt->context, cur);
8014
2.82M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8015
2.82M
    }
8016
11.2M
    xmlXPathValuePush(ctxt, cur);
8017
11.2M
}
8018
8019
/**
8020
 * Implement the sum() XPath function
8021
 *    number sum(node-set)
8022
 * The sum function returns the sum of the values of the nodes in
8023
 * the argument node-set.
8024
 *
8025
 * @param ctxt  the XPath Parser context
8026
 * @param nargs  the number of arguments
8027
 */
8028
void
8029
0
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
0
    xmlXPathObjectPtr cur;
8031
0
    int i;
8032
0
    double res = 0.0;
8033
8034
0
    CHECK_ARITY(1);
8035
0
    if ((ctxt->value == NULL) ||
8036
0
  ((ctxt->value->type != XPATH_NODESET) &&
8037
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8038
0
  XP_ERROR(XPATH_INVALID_TYPE);
8039
0
    cur = xmlXPathValuePop(ctxt);
8040
8041
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8042
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8043
0
      res += xmlXPathNodeToNumberInternal(ctxt,
8044
0
                                                cur->nodesetval->nodeTab[i]);
8045
0
  }
8046
0
    }
8047
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8048
0
    xmlXPathReleaseObject(ctxt->context, cur);
8049
0
}
8050
8051
/**
8052
 * Implement the floor() XPath function
8053
 *    number floor(number)
8054
 * The floor function returns the largest (closest to positive infinity)
8055
 * number that is not greater than the argument and that is an integer.
8056
 *
8057
 * @param ctxt  the XPath Parser context
8058
 * @param nargs  the number of arguments
8059
 */
8060
void
8061
3
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8062
7
    CHECK_ARITY(1);
8063
7
    CAST_TO_NUMBER;
8064
7
    CHECK_TYPE(XPATH_NUMBER);
8065
8066
2
    ctxt->value->floatval = floor(ctxt->value->floatval);
8067
2
}
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
142k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8148
142k
    const xmlChar *end;
8149
142k
    xmlChar *ret;
8150
8151
142k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8152
8153
142k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8154
142k
    if (end == NULL) {
8155
1
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8156
0
    }
8157
142k
    if (end == ctxt->cur)
8158
20.2k
        return(NULL);
8159
8160
122k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8161
122k
    if (ret == NULL)
8162
0
        xmlXPathPErrMemory(ctxt);
8163
122k
    ctxt->cur = end;
8164
122k
    return(ret);
8165
142k
}
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
11.3k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8179
11.3k
    xmlChar *ret = NULL;
8180
8181
11.3k
    *prefix = NULL;
8182
11.3k
    ret = xmlXPathParseNCName(ctxt);
8183
11.3k
    if (ret && CUR == ':') {
8184
397
        *prefix = ret;
8185
397
  NEXT;
8186
397
  ret = xmlXPathParseNCName(ctxt);
8187
397
    }
8188
11.3k
    return(ret);
8189
11.3k
}
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
13.9k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8200
13.9k
    const xmlChar *end;
8201
13.9k
    xmlChar *ret;
8202
8203
13.9k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8204
8205
13.9k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8206
13.9k
    if (end == NULL) {
8207
1
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8208
0
    }
8209
13.9k
    if (end == ctxt->cur)
8210
1.90k
        return(NULL);
8211
8212
12.0k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8213
12.0k
    if (ret == NULL)
8214
0
        xmlXPathPErrMemory(ctxt);
8215
12.0k
    ctxt->cur = end;
8216
12.0k
    return(ret);
8217
13.9k
}
8218
8219
154k
#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
6.47M
xmlXPathStringEvalNumber(const xmlChar *str) {
8237
6.47M
    const xmlChar *cur = str;
8238
6.47M
    double ret;
8239
6.47M
    int ok = 0;
8240
6.47M
    int isneg = 0;
8241
6.47M
    int exponent = 0;
8242
6.47M
    int is_exponent_negative = 0;
8243
6.47M
#ifdef __GNUC__
8244
6.47M
    unsigned long tmp = 0;
8245
6.47M
    double temp;
8246
6.47M
#endif
8247
6.47M
    if (cur == NULL) return(0);
8248
9.65M
    while (IS_BLANK_CH(*cur)) cur++;
8249
6.47M
    if (*cur == '-') {
8250
3.11k
  isneg = 1;
8251
3.11k
  cur++;
8252
3.11k
    }
8253
6.47M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8254
6.30M
        return(xmlXPathNAN);
8255
6.30M
    }
8256
8257
169k
#ifdef __GNUC__
8258
    /*
8259
     * tmp/temp is a workaround against a gcc compiler bug
8260
     * http://veillard.com/gcc.bug
8261
     */
8262
169k
    ret = 0;
8263
687k
    while ((*cur >= '0') && (*cur <= '9')) {
8264
517k
  ret = ret * 10;
8265
517k
  tmp = (*cur - '0');
8266
517k
  ok = 1;
8267
517k
  cur++;
8268
517k
  temp = (double) tmp;
8269
517k
  ret = ret + temp;
8270
517k
    }
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
169k
    if (*cur == '.') {
8281
152k
  int v, frac = 0, max;
8282
152k
  double fraction = 0;
8283
8284
152k
        cur++;
8285
152k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8286
1.67k
      return(xmlXPathNAN);
8287
1.67k
  }
8288
6.18M
        while (*cur == '0') {
8289
6.03M
      frac = frac + 1;
8290
6.03M
      cur++;
8291
6.03M
        }
8292
150k
        max = frac + MAX_FRAC;
8293
2.17M
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8294
2.02M
      v = (*cur - '0');
8295
2.02M
      fraction = fraction * 10 + v;
8296
2.02M
      frac = frac + 1;
8297
2.02M
      cur++;
8298
2.02M
  }
8299
150k
  fraction /= pow(10.0, frac);
8300
150k
  ret = ret + fraction;
8301
176k
  while ((*cur >= '0') && (*cur <= '9'))
8302
25.4k
      cur++;
8303
150k
    }
8304
167k
    if ((*cur == 'e') || (*cur == 'E')) {
8305
8.18k
      cur++;
8306
8.18k
      if (*cur == '-') {
8307
6.17k
  is_exponent_negative = 1;
8308
6.17k
  cur++;
8309
6.17k
      } else if (*cur == '+') {
8310
295
        cur++;
8311
295
      }
8312
10.6k
      while ((*cur >= '0') && (*cur <= '9')) {
8313
2.42k
        if (exponent < 1000000)
8314
2.04k
    exponent = exponent * 10 + (*cur - '0');
8315
2.42k
  cur++;
8316
2.42k
      }
8317
8.18k
    }
8318
692k
    while (IS_BLANK_CH(*cur)) cur++;
8319
167k
    if (*cur != 0) return(xmlXPathNAN);
8320
137k
    if (isneg) ret = -ret;
8321
137k
    if (is_exponent_negative) exponent = -exponent;
8322
137k
    ret *= pow(10.0, (double)exponent);
8323
137k
    return(ret);
8324
167k
}
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
103k
{
8338
103k
    double ret = 0.0;
8339
103k
    int ok = 0;
8340
103k
    int exponent = 0;
8341
103k
    int is_exponent_negative = 0;
8342
103k
    xmlXPathObjectPtr num;
8343
103k
#ifdef __GNUC__
8344
103k
    unsigned long tmp = 0;
8345
103k
    double temp;
8346
103k
#endif
8347
8348
103k
    CHECK_ERROR;
8349
103k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8350
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8351
0
    }
8352
103k
#ifdef __GNUC__
8353
    /*
8354
     * tmp/temp is a workaround against a gcc compiler bug
8355
     * http://veillard.com/gcc.bug
8356
     */
8357
103k
    ret = 0;
8358
5.14M
    while ((CUR >= '0') && (CUR <= '9')) {
8359
5.03M
  ret = ret * 10;
8360
5.03M
  tmp = (CUR - '0');
8361
5.03M
        ok = 1;
8362
5.03M
        NEXT;
8363
5.03M
  temp = (double) tmp;
8364
5.03M
  ret = ret + temp;
8365
5.03M
    }
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
103k
    if (CUR == '.') {
8375
3.26k
  int v, frac = 0, max;
8376
3.26k
  double fraction = 0;
8377
8378
3.26k
        NEXT;
8379
3.26k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8380
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8381
0
        }
8382
29.9k
        while (CUR == '0') {
8383
26.6k
            frac = frac + 1;
8384
26.6k
            NEXT;
8385
26.6k
        }
8386
3.26k
        max = frac + MAX_FRAC;
8387
10.4k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8388
7.22k
      v = (CUR - '0');
8389
7.22k
      fraction = fraction * 10 + v;
8390
7.22k
      frac = frac + 1;
8391
7.22k
            NEXT;
8392
7.22k
        }
8393
3.26k
        fraction /= pow(10.0, frac);
8394
3.26k
        ret = ret + fraction;
8395
6.63k
        while ((CUR >= '0') && (CUR <= '9'))
8396
3.37k
            NEXT;
8397
3.26k
    }
8398
103k
    if ((CUR == 'e') || (CUR == 'E')) {
8399
6.44k
        NEXT;
8400
6.44k
        if (CUR == '-') {
8401
75
            is_exponent_negative = 1;
8402
75
            NEXT;
8403
6.37k
        } else if (CUR == '+') {
8404
194
      NEXT;
8405
194
  }
8406
259k
        while ((CUR >= '0') && (CUR <= '9')) {
8407
252k
            if (exponent < 1000000)
8408
79.2k
                exponent = exponent * 10 + (CUR - '0');
8409
252k
            NEXT;
8410
252k
        }
8411
6.44k
        if (is_exponent_negative)
8412
75
            exponent = -exponent;
8413
6.44k
        ret *= pow(10.0, (double) exponent);
8414
6.44k
    }
8415
103k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8416
103k
    if (num == NULL) {
8417
0
  ctxt->error = XPATH_MEMORY_ERROR;
8418
103k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8419
103k
                              NULL) == -1) {
8420
0
        xmlXPathReleaseObject(ctxt->context, num);
8421
0
    }
8422
103k
}
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
18.7k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8435
18.7k
    const xmlChar *q;
8436
18.7k
    xmlChar *ret = NULL;
8437
18.7k
    int quote;
8438
8439
18.7k
    if (CUR == '"') {
8440
1
        quote = '"';
8441
18.7k
    } else if (CUR == '\'') {
8442
18.7k
        quote = '\'';
8443
18.7k
    } else {
8444
1
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8445
0
    }
8446
8447
18.7k
    NEXT;
8448
18.7k
    q = CUR_PTR;
8449
1.32M
    while (CUR != quote) {
8450
1.30M
        int ch;
8451
1.30M
        int len = 4;
8452
8453
1.30M
        if (CUR == 0)
8454
1.30M
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8455
1.30M
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8456
1.30M
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8457
1.30M
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8458
1.30M
        CUR_PTR += len;
8459
1.30M
    }
8460
18.7k
    ret = xmlStrndup(q, CUR_PTR - q);
8461
18.7k
    if (ret == NULL)
8462
0
        xmlXPathPErrMemory(ctxt);
8463
18.7k
    NEXT;
8464
18.7k
    return(ret);
8465
18.7k
}
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
18.7k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8479
18.7k
    xmlChar *ret = NULL;
8480
18.7k
    xmlXPathObjectPtr lit;
8481
8482
18.7k
    ret = xmlXPathParseLiteral(ctxt);
8483
18.7k
    if (ret == NULL)
8484
67
        return;
8485
18.6k
    lit = xmlXPathCacheNewString(ctxt, ret);
8486
18.6k
    if (lit == NULL) {
8487
0
        ctxt->error = XPATH_MEMORY_ERROR;
8488
18.6k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8489
18.6k
                              NULL) == -1) {
8490
0
        xmlXPathReleaseObject(ctxt->context, lit);
8491
0
    }
8492
18.6k
    xmlFree(ret);
8493
18.6k
}
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
884
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8512
884
    xmlChar *name;
8513
884
    xmlChar *prefix;
8514
8515
884
    SKIP_BLANKS;
8516
884
    if (CUR != '$') {
8517
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8518
0
    }
8519
884
    NEXT;
8520
884
    name = xmlXPathParseQName(ctxt, &prefix);
8521
884
    if (name == NULL) {
8522
107
        xmlFree(prefix);
8523
107
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8524
0
    }
8525
777
    ctxt->comp->last = -1;
8526
777
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8527
0
        xmlFree(prefix);
8528
0
        xmlFree(name);
8529
0
    }
8530
777
    SKIP_BLANKS;
8531
777
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8532
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8533
0
    }
8534
777
}
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
10.7k
xmlXPathIsNodeType(const xmlChar *name) {
8549
10.7k
    if (name == NULL)
8550
0
  return(0);
8551
8552
10.7k
    if (xmlStrEqual(name, BAD_CAST "node"))
8553
102
  return(1);
8554
10.6k
    if (xmlStrEqual(name, BAD_CAST "text"))
8555
146
  return(1);
8556
10.5k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8557
19
  return(1);
8558
10.4k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8559
30
  return(1);
8560
10.4k
    return(0);
8561
10.4k
}
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
10.4k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8574
10.4k
    xmlChar *name;
8575
10.4k
    xmlChar *prefix;
8576
10.4k
    int nbargs = 0;
8577
10.4k
    int sort = 1;
8578
8579
10.4k
    name = xmlXPathParseQName(ctxt, &prefix);
8580
10.4k
    if (name == NULL) {
8581
2
  xmlFree(prefix);
8582
2
  XP_ERROR(XPATH_EXPR_ERROR);
8583
0
    }
8584
10.4k
    SKIP_BLANKS;
8585
8586
10.4k
    if (CUR != '(') {
8587
2
  xmlFree(name);
8588
2
  xmlFree(prefix);
8589
2
  XP_ERROR(XPATH_EXPR_ERROR);
8590
0
    }
8591
10.4k
    NEXT;
8592
10.4k
    SKIP_BLANKS;
8593
8594
    /*
8595
    * Optimization for count(): we don't need the node-set to be sorted.
8596
    */
8597
10.4k
    if ((prefix == NULL) && (name[0] == 'c') &&
8598
246
  xmlStrEqual(name, BAD_CAST "count"))
8599
26
    {
8600
26
  sort = 0;
8601
26
    }
8602
10.4k
    ctxt->comp->last = -1;
8603
10.4k
    if (CUR != ')') {
8604
57.0k
  while (CUR != 0) {
8605
57.0k
      int op1 = ctxt->comp->last;
8606
57.0k
      ctxt->comp->last = -1;
8607
57.0k
      xmlXPathCompileExpr(ctxt, sort);
8608
57.0k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8609
969
    xmlFree(name);
8610
969
    xmlFree(prefix);
8611
969
    return;
8612
969
      }
8613
56.0k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8614
56.0k
      nbargs++;
8615
56.0k
      if (CUR == ')') break;
8616
47.4k
      if (CUR != ',') {
8617
525
    xmlFree(name);
8618
525
    xmlFree(prefix);
8619
525
    XP_ERROR(XPATH_EXPR_ERROR);
8620
0
      }
8621
46.9k
      NEXT;
8622
46.9k
      SKIP_BLANKS;
8623
46.9k
  }
8624
10.1k
    }
8625
8.96k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8626
0
        xmlFree(prefix);
8627
0
        xmlFree(name);
8628
0
    }
8629
8.96k
    NEXT;
8630
8.96k
    SKIP_BLANKS;
8631
8.96k
}
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
137k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8646
137k
    SKIP_BLANKS;
8647
137k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8648
136k
    else if (CUR == '(') {
8649
3.63k
  NEXT;
8650
3.63k
  SKIP_BLANKS;
8651
3.63k
  xmlXPathCompileExpr(ctxt, 1);
8652
3.63k
  CHECK_ERROR;
8653
3.23k
  if (CUR != ')') {
8654
30
      XP_ERROR(XPATH_EXPR_ERROR);
8655
0
  }
8656
3.20k
  NEXT;
8657
3.20k
  SKIP_BLANKS;
8658
132k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8659
103k
  xmlXPathCompNumber(ctxt);
8660
103k
    } else if ((CUR == '\'') || (CUR == '"')) {
8661
18.7k
  xmlXPathCompLiteral(ctxt);
8662
18.7k
    } else {
8663
10.4k
  xmlXPathCompFunctionCall(ctxt);
8664
10.4k
    }
8665
136k
    SKIP_BLANKS;
8666
136k
}
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
137k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8684
137k
    xmlXPathCompPrimaryExpr(ctxt);
8685
137k
    CHECK_ERROR;
8686
135k
    SKIP_BLANKS;
8687
8688
160k
    while (CUR == '[') {
8689
25.0k
  xmlXPathCompPredicate(ctxt, 1);
8690
25.0k
  SKIP_BLANKS;
8691
25.0k
    }
8692
8693
8694
135k
}
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
96.7k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8706
96.7k
    const xmlChar *end;
8707
96.7k
    xmlChar *ret;
8708
8709
96.7k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8710
96.7k
    if (end == NULL) {
8711
1
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8712
0
    }
8713
96.7k
    if (end == ctxt->cur)
8714
9.40k
        return(NULL);
8715
8716
87.3k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8717
87.3k
    if (ret == NULL)
8718
0
        xmlXPathPErrMemory(ctxt);
8719
87.3k
    return(ret);
8720
96.7k
}
8721
8722
/**
8723
 *  [19]   PathExpr ::=   LocationPath
8724
 *               | FilterExpr
8725
 *               | FilterExpr '/' RelativeLocationPath
8726
 *               | FilterExpr '//' RelativeLocationPath
8727
 *
8728
 * Compile a path expression.
8729
 *
8730
 * @param ctxt  the XPath Parser context
8731
 */
8732
8733
static void
8734
5.09M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8735
5.09M
    int lc = 1;           /* Should we branch to LocationPath ?         */
8736
5.09M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8737
8738
5.09M
    SKIP_BLANKS;
8739
5.09M
    if ((CUR == '$') || (CUR == '(') ||
8740
5.09M
  (IS_ASCII_DIGIT(CUR)) ||
8741
4.99M
        (CUR == '\'') || (CUR == '"') ||
8742
4.97M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8743
126k
  lc = 0;
8744
4.97M
    } else if (CUR == '*') {
8745
  /* relative or absolute location path */
8746
4.80M
  lc = 1;
8747
4.80M
    } else if (CUR == '/') {
8748
  /* relative or absolute location path */
8749
64.8k
  lc = 1;
8750
105k
    } else if (CUR == '@') {
8751
  /* relative abbreviated attribute location path */
8752
2.14k
  lc = 1;
8753
103k
    } else if (CUR == '.') {
8754
  /* relative abbreviated attribute location path */
8755
6.38k
  lc = 1;
8756
96.7k
    } 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
96.7k
  SKIP_BLANKS;
8769
96.7k
  name = xmlXPathScanName(ctxt);
8770
96.7k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8771
2.75k
      lc = 1;
8772
2.75k
      xmlFree(name);
8773
94.0k
  } else if (name != NULL) {
8774
84.5k
      int len =xmlStrlen(name);
8775
8776
8777
318k
      while (NXT(len) != 0) {
8778
318k
    if (NXT(len) == '/') {
8779
        /* element name */
8780
5.17k
        lc = 1;
8781
5.17k
        break;
8782
313k
    } else if (IS_BLANK_CH(NXT(len))) {
8783
        /* ignore blanks */
8784
234k
        ;
8785
234k
    } else if (NXT(len) == ':') {
8786
257
        lc = 1;
8787
257
        break;
8788
78.6k
    } else if ((NXT(len) == '(')) {
8789
        /* Node Type or Function */
8790
10.7k
        if (xmlXPathIsNodeType(name)) {
8791
297
      lc = 1;
8792
10.4k
        } else {
8793
10.4k
      lc = 0;
8794
10.4k
        }
8795
10.7k
                    break;
8796
67.8k
    } else if ((NXT(len) == '[')) {
8797
        /* element name */
8798
284
        lc = 1;
8799
284
        break;
8800
67.5k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8801
56.3k
         (NXT(len) == '=')) {
8802
25.5k
        lc = 1;
8803
25.5k
        break;
8804
42.0k
    } else {
8805
42.0k
        lc = 1;
8806
42.0k
        break;
8807
42.0k
    }
8808
234k
    len++;
8809
234k
      }
8810
84.5k
      if (NXT(len) == 0) {
8811
    /* element name */
8812
540
    lc = 1;
8813
540
      }
8814
84.5k
      xmlFree(name);
8815
84.5k
  } else {
8816
      /* make sure all cases are covered explicitly */
8817
9.41k
      XP_ERROR(XPATH_EXPR_ERROR);
8818
0
  }
8819
96.7k
    }
8820
8821
5.08M
    if (lc) {
8822
4.95M
  if (CUR == '/') {
8823
64.8k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8824
4.88M
  } else {
8825
4.88M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8826
4.88M
  }
8827
4.95M
  xmlXPathCompLocationPath(ctxt);
8828
4.95M
    } else {
8829
137k
  xmlXPathCompFilterExpr(ctxt);
8830
137k
  CHECK_ERROR;
8831
134k
  if ((CUR == '/') && (NXT(1) == '/')) {
8832
292
      SKIP(2);
8833
292
      SKIP_BLANKS;
8834
8835
292
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8836
292
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8837
8838
292
      xmlXPathCompRelativeLocationPath(ctxt);
8839
134k
  } else if (CUR == '/') {
8840
532
      xmlXPathCompRelativeLocationPath(ctxt);
8841
532
  }
8842
134k
    }
8843
5.08M
    SKIP_BLANKS;
8844
5.08M
}
8845
8846
/**
8847
 *  [18]   UnionExpr ::=   PathExpr
8848
 *               | UnionExpr '|' PathExpr
8849
 *
8850
 * Compile an union expression.
8851
 *
8852
 * @param ctxt  the XPath Parser context
8853
 */
8854
8855
static void
8856
5.06M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8857
5.06M
    xmlXPathCompPathExpr(ctxt);
8858
5.06M
    CHECK_ERROR;
8859
5.06M
    SKIP_BLANKS;
8860
5.09M
    while (CUR == '|') {
8861
29.9k
  int op1 = ctxt->comp->last;
8862
29.9k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8863
8864
29.9k
  NEXT;
8865
29.9k
  SKIP_BLANKS;
8866
29.9k
  xmlXPathCompPathExpr(ctxt);
8867
8868
29.9k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8869
8870
29.9k
  SKIP_BLANKS;
8871
29.9k
    }
8872
5.06M
}
8873
8874
/**
8875
 *  [27]   UnaryExpr ::=   UnionExpr
8876
 *                   | '-' UnaryExpr
8877
 *
8878
 * Compile an unary expression.
8879
 *
8880
 * @param ctxt  the XPath Parser context
8881
 */
8882
8883
static void
8884
5.06M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8885
5.06M
    int minus = 0;
8886
5.06M
    int found = 0;
8887
8888
5.06M
    SKIP_BLANKS;
8889
5.19M
    while (CUR == '-') {
8890
129k
        minus = 1 - minus;
8891
129k
  found = 1;
8892
129k
  NEXT;
8893
129k
  SKIP_BLANKS;
8894
129k
    }
8895
8896
5.06M
    xmlXPathCompUnionExpr(ctxt);
8897
5.06M
    CHECK_ERROR;
8898
5.06M
    if (found) {
8899
21.2k
  if (minus)
8900
14.9k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8901
6.23k
  else
8902
6.23k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8903
21.2k
    }
8904
5.06M
}
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
259k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8920
259k
    xmlXPathCompUnaryExpr(ctxt);
8921
259k
    CHECK_ERROR;
8922
255k
    SKIP_BLANKS;
8923
5.06M
    while ((CUR == '*') ||
8924
256k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8925
4.81M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8926
4.81M
  int op = -1;
8927
4.81M
  int op1 = ctxt->comp->last;
8928
8929
4.81M
        if (CUR == '*') {
8930
4.80M
      op = 0;
8931
4.80M
      NEXT;
8932
4.80M
  } else if (CUR == 'd') {
8933
1.01k
      op = 1;
8934
1.01k
      SKIP(3);
8935
1.01k
  } else if (CUR == 'm') {
8936
314
      op = 2;
8937
314
      SKIP(3);
8938
314
  }
8939
4.81M
  SKIP_BLANKS;
8940
4.81M
        xmlXPathCompUnaryExpr(ctxt);
8941
4.81M
  CHECK_ERROR;
8942
4.80M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8943
4.80M
  SKIP_BLANKS;
8944
4.80M
    }
8945
255k
}
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
223k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8959
8960
223k
    xmlXPathCompMultiplicativeExpr(ctxt);
8961
223k
    CHECK_ERROR;
8962
219k
    SKIP_BLANKS;
8963
255k
    while ((CUR == '+') || (CUR == '-')) {
8964
35.4k
  int plus;
8965
35.4k
  int op1 = ctxt->comp->last;
8966
8967
35.4k
        if (CUR == '+') plus = 1;
8968
22.5k
  else plus = 0;
8969
35.4k
  NEXT;
8970
35.4k
  SKIP_BLANKS;
8971
35.4k
        xmlXPathCompMultiplicativeExpr(ctxt);
8972
35.4k
  CHECK_ERROR;
8973
35.2k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8974
35.2k
  SKIP_BLANKS;
8975
35.2k
    }
8976
219k
}
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
192k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8997
192k
    xmlXPathCompAdditiveExpr(ctxt);
8998
192k
    CHECK_ERROR;
8999
188k
    SKIP_BLANKS;
9000
219k
    while ((CUR == '<') || (CUR == '>')) {
9001
31.7k
  int inf, strict;
9002
31.7k
  int op1 = ctxt->comp->last;
9003
9004
31.7k
        if (CUR == '<') inf = 1;
9005
25.5k
  else inf = 0;
9006
31.7k
  if (NXT(1) == '=') strict = 0;
9007
27.8k
  else strict = 1;
9008
31.7k
  NEXT;
9009
31.7k
  if (!strict) NEXT;
9010
31.7k
  SKIP_BLANKS;
9011
31.7k
        xmlXPathCompAdditiveExpr(ctxt);
9012
31.7k
  CHECK_ERROR;
9013
31.3k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9014
31.3k
  SKIP_BLANKS;
9015
31.3k
    }
9016
188k
}
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
110k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9034
110k
    xmlXPathCompRelationalExpr(ctxt);
9035
110k
    CHECK_ERROR;
9036
106k
    SKIP_BLANKS;
9037
187k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9038
81.6k
  int eq;
9039
81.6k
  int op1 = ctxt->comp->last;
9040
9041
81.6k
        if (CUR == '=') eq = 1;
9042
4.11k
  else eq = 0;
9043
81.6k
  NEXT;
9044
81.6k
  if (!eq) NEXT;
9045
81.6k
  SKIP_BLANKS;
9046
81.6k
        xmlXPathCompRelationalExpr(ctxt);
9047
81.6k
  CHECK_ERROR;
9048
81.1k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9049
81.1k
  SKIP_BLANKS;
9050
81.1k
    }
9051
106k
}
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
109k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9063
109k
    xmlXPathCompEqualityExpr(ctxt);
9064
109k
    CHECK_ERROR;
9065
105k
    SKIP_BLANKS;
9066
106k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9067
1.04k
  int op1 = ctxt->comp->last;
9068
1.04k
        SKIP(3);
9069
1.04k
  SKIP_BLANKS;
9070
1.04k
        xmlXPathCompEqualityExpr(ctxt);
9071
1.04k
  CHECK_ERROR;
9072
978
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9073
978
  SKIP_BLANKS;
9074
978
    }
9075
105k
}
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
104k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9089
104k
    xmlXPathContextPtr xpctxt = ctxt->context;
9090
9091
104k
    if (xpctxt != NULL) {
9092
104k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9093
104k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9094
        /*
9095
         * Parsing a single '(' pushes about 10 functions on the call stack
9096
         * before recursing!
9097
         */
9098
104k
        xpctxt->depth += 10;
9099
104k
    }
9100
9101
104k
    xmlXPathCompAndExpr(ctxt);
9102
104k
    CHECK_ERROR;
9103
100k
    SKIP_BLANKS;
9104
105k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9105
5.35k
  int op1 = ctxt->comp->last;
9106
5.35k
        SKIP(2);
9107
5.35k
  SKIP_BLANKS;
9108
5.35k
        xmlXPathCompAndExpr(ctxt);
9109
5.35k
  CHECK_ERROR;
9110
5.17k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9111
5.17k
  SKIP_BLANKS;
9112
5.17k
    }
9113
99.9k
    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
74.7k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9121
74.7k
    }
9122
9123
99.9k
    if (xpctxt != NULL)
9124
99.9k
        xpctxt->depth -= 10;
9125
99.9k
}
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
35.5k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9138
35.5k
    int op1 = ctxt->comp->last;
9139
9140
35.5k
    SKIP_BLANKS;
9141
35.5k
    if (CUR != '[') {
9142
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9143
0
    }
9144
35.5k
    NEXT;
9145
35.5k
    SKIP_BLANKS;
9146
9147
35.5k
    ctxt->comp->last = -1;
9148
    /*
9149
    * This call to xmlXPathCompileExpr() will deactivate sorting
9150
    * of the predicate result.
9151
    * TODO: Sorting is still activated for filters, since I'm not
9152
    *  sure if needed. Normally sorting should not be needed, since
9153
    *  a filter can only diminish the number of items in a sequence,
9154
    *  but won't change its order; so if the initial sequence is sorted,
9155
    *  subsequent sorting is not needed.
9156
    */
9157
35.5k
    if (! filter)
9158
10.5k
  xmlXPathCompileExpr(ctxt, 0);
9159
25.0k
    else
9160
25.0k
  xmlXPathCompileExpr(ctxt, 1);
9161
35.5k
    CHECK_ERROR;
9162
9163
33.4k
    if (CUR != ']') {
9164
53
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9165
0
    }
9166
9167
33.3k
    if (filter)
9168
23.7k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9169
9.61k
    else
9170
9.61k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9171
9172
33.3k
    NEXT;
9173
33.3k
    SKIP_BLANKS;
9174
33.3k
}
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
4.97M
         xmlChar *name) {
9202
4.97M
    int blanks;
9203
9204
4.97M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9205
0
  return(NULL);
9206
0
    }
9207
4.97M
    *type = (xmlXPathTypeVal) 0;
9208
4.97M
    *test = (xmlXPathTestVal) 0;
9209
4.97M
    *prefix = NULL;
9210
4.97M
    SKIP_BLANKS;
9211
9212
4.97M
    if ((name == NULL) && (CUR == '*')) {
9213
  /*
9214
   * All elements
9215
   */
9216
4.86M
  NEXT;
9217
4.86M
  *test = NODE_TEST_ALL;
9218
4.86M
  return(NULL);
9219
4.86M
    }
9220
9221
106k
    if (name == NULL)
9222
4.31k
  name = xmlXPathParseNCName(ctxt);
9223
106k
    if (name == NULL) {
9224
178
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9225
0
    }
9226
9227
105k
    blanks = IS_BLANK_CH(CUR);
9228
105k
    SKIP_BLANKS;
9229
105k
    if (CUR == '(') {
9230
675
  NEXT;
9231
  /*
9232
   * NodeType or PI search
9233
   */
9234
675
  if (xmlStrEqual(name, BAD_CAST "comment"))
9235
19
      *type = NODE_TYPE_COMMENT;
9236
656
  else if (xmlStrEqual(name, BAD_CAST "node"))
9237
326
      *type = NODE_TYPE_NODE;
9238
330
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9239
65
      *type = NODE_TYPE_PI;
9240
265
  else if (xmlStrEqual(name, BAD_CAST "text"))
9241
258
      *type = NODE_TYPE_TEXT;
9242
7
  else {
9243
7
      if (name != NULL)
9244
7
    xmlFree(name);
9245
7
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9246
0
  }
9247
9248
668
  *test = NODE_TEST_TYPE;
9249
9250
668
  SKIP_BLANKS;
9251
668
  if (*type == NODE_TYPE_PI) {
9252
      /*
9253
       * Specific case: search a PI by name.
9254
       */
9255
65
      if (name != NULL)
9256
65
    xmlFree(name);
9257
65
      name = NULL;
9258
65
      if (CUR != ')') {
9259
51
    name = xmlXPathParseLiteral(ctxt);
9260
51
    *test = NODE_TEST_PI;
9261
51
    SKIP_BLANKS;
9262
51
      }
9263
65
  }
9264
668
  if (CUR != ')') {
9265
33
      if (name != NULL)
9266
32
    xmlFree(name);
9267
33
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9268
0
  }
9269
635
  NEXT;
9270
635
  return(name);
9271
668
    }
9272
105k
    *test = NODE_TEST_NAME;
9273
105k
    if ((!blanks) && (CUR == ':')) {
9274
1.56k
  NEXT;
9275
9276
  /*
9277
   * Since currently the parser context don't have a
9278
   * namespace list associated:
9279
   * The namespace name for this prefix can be computed
9280
   * only at evaluation time. The compilation is done
9281
   * outside of any context.
9282
   */
9283
1.56k
  *prefix = name;
9284
9285
1.56k
  if (CUR == '*') {
9286
      /*
9287
       * All elements
9288
       */
9289
654
      NEXT;
9290
654
      *test = NODE_TEST_ALL;
9291
654
      return(NULL);
9292
654
  }
9293
9294
911
  name = xmlXPathParseNCName(ctxt);
9295
911
  if (name == NULL) {
9296
18
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9297
0
  }
9298
911
    }
9299
104k
    return(name);
9300
105k
}
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
104k
xmlXPathIsAxisName(const xmlChar *name) {
9322
104k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9323
104k
    switch (name[0]) {
9324
2.20k
  case 'a':
9325
2.20k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9326
114
    ret = AXIS_ANCESTOR;
9327
2.20k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9328
38
    ret = AXIS_ANCESTOR_OR_SELF;
9329
2.20k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9330
66
    ret = AXIS_ATTRIBUTE;
9331
2.20k
      break;
9332
1.19k
  case 'c':
9333
1.19k
      if (xmlStrEqual(name, BAD_CAST "child"))
9334
71
    ret = AXIS_CHILD;
9335
1.19k
      break;
9336
2.68k
  case 'd':
9337
2.68k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9338
76
    ret = AXIS_DESCENDANT;
9339
2.68k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9340
12
    ret = AXIS_DESCENDANT_OR_SELF;
9341
2.68k
      break;
9342
2.57k
  case 'f':
9343
2.57k
      if (xmlStrEqual(name, BAD_CAST "following"))
9344
1.24k
    ret = AXIS_FOLLOWING;
9345
2.57k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9346
563
    ret = AXIS_FOLLOWING_SIBLING;
9347
2.57k
      break;
9348
4.42k
  case 'n':
9349
4.42k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9350
196
    ret = AXIS_NAMESPACE;
9351
4.42k
      break;
9352
12.0k
  case 'p':
9353
12.0k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9354
2.84k
    ret = AXIS_PARENT;
9355
12.0k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9356
75
    ret = AXIS_PRECEDING;
9357
12.0k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9358
445
    ret = AXIS_PRECEDING_SIBLING;
9359
12.0k
      break;
9360
714
  case 's':
9361
714
      if (xmlStrEqual(name, BAD_CAST "self"))
9362
117
    ret = AXIS_SELF;
9363
714
      break;
9364
104k
    }
9365
104k
    return(ret);
9366
104k
}
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
4.98M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9391
4.98M
    SKIP_BLANKS;
9392
4.98M
    if ((CUR == '.') && (NXT(1) == '.')) {
9393
1.48k
  SKIP(2);
9394
1.48k
  SKIP_BLANKS;
9395
1.48k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9396
1.48k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9397
4.98M
    } else if (CUR == '.') {
9398
12.3k
  NEXT;
9399
12.3k
  SKIP_BLANKS;
9400
4.97M
    } else {
9401
4.97M
  xmlChar *name = NULL;
9402
4.97M
  xmlChar *prefix = NULL;
9403
4.97M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9404
4.97M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9405
4.97M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9406
4.97M
  int op1;
9407
9408
4.97M
  if (CUR == '*') {
9409
4.84M
      axis = AXIS_CHILD;
9410
4.84M
  } else {
9411
124k
      if (name == NULL)
9412
124k
    name = xmlXPathParseNCName(ctxt);
9413
124k
      if (name != NULL) {
9414
104k
    axis = xmlXPathIsAxisName(name);
9415
104k
    if (axis != 0) {
9416
5.85k
        SKIP_BLANKS;
9417
5.85k
        if ((CUR == ':') && (NXT(1) == ':')) {
9418
2.76k
      SKIP(2);
9419
2.76k
      xmlFree(name);
9420
2.76k
      name = NULL;
9421
3.09k
        } else {
9422
      /* an element name can conflict with an axis one :-\ */
9423
3.09k
      axis = AXIS_CHILD;
9424
3.09k
        }
9425
98.9k
    } else {
9426
98.9k
        axis = AXIS_CHILD;
9427
98.9k
    }
9428
104k
      } else if (CUR == '@') {
9429
19.3k
    NEXT;
9430
19.3k
    axis = AXIS_ATTRIBUTE;
9431
19.3k
      } else {
9432
510
    axis = AXIS_CHILD;
9433
510
      }
9434
124k
  }
9435
9436
4.97M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9437
677
            xmlFree(name);
9438
677
            return;
9439
677
        }
9440
9441
4.97M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9442
4.97M
  if (test == 0)
9443
185
      return;
9444
9445
4.97M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9446
1.56k
      (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
4.97M
  op1 = ctxt->comp->last;
9454
4.97M
  ctxt->comp->last = -1;
9455
9456
4.97M
  SKIP_BLANKS;
9457
4.98M
  while (CUR == '[') {
9458
10.5k
      xmlXPathCompPredicate(ctxt, 0);
9459
10.5k
  }
9460
9461
4.97M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9462
4.97M
                           test, type, (void *)prefix, (void *)name) == -1) {
9463
34
            xmlFree(prefix);
9464
34
            xmlFree(name);
9465
34
        }
9466
4.97M
    }
9467
4.98M
}
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
4.93M
(xmlXPathParserContextPtr ctxt) {
9482
4.93M
    SKIP_BLANKS;
9483
4.93M
    if ((CUR == '/') && (NXT(1) == '/')) {
9484
2.62k
  SKIP(2);
9485
2.62k
  SKIP_BLANKS;
9486
2.62k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9487
2.62k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9488
4.92M
    } else if (CUR == '/') {
9489
9.08k
      NEXT;
9490
9.08k
  SKIP_BLANKS;
9491
9.08k
    }
9492
4.93M
    xmlXPathCompStep(ctxt);
9493
4.93M
    CHECK_ERROR;
9494
4.92M
    SKIP_BLANKS;
9495
4.98M
    while (CUR == '/') {
9496
54.4k
  if ((CUR == '/') && (NXT(1) == '/')) {
9497
16.3k
      SKIP(2);
9498
16.3k
      SKIP_BLANKS;
9499
16.3k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9500
16.3k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9501
16.3k
      xmlXPathCompStep(ctxt);
9502
38.0k
  } else if (CUR == '/') {
9503
38.0k
      NEXT;
9504
38.0k
      SKIP_BLANKS;
9505
38.0k
      xmlXPathCompStep(ctxt);
9506
38.0k
  }
9507
54.4k
  SKIP_BLANKS;
9508
54.4k
    }
9509
4.92M
}
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
4.95M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9525
4.95M
    SKIP_BLANKS;
9526
4.95M
    if (CUR != '/') {
9527
4.88M
        xmlXPathCompRelativeLocationPath(ctxt);
9528
4.88M
    } else {
9529
131k
  while (CUR == '/') {
9530
66.7k
      if ((CUR == '/') && (NXT(1) == '/')) {
9531
21.9k
    SKIP(2);
9532
21.9k
    SKIP_BLANKS;
9533
21.9k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9534
21.9k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9535
21.9k
    xmlXPathCompRelativeLocationPath(ctxt);
9536
44.8k
      } else if (CUR == '/') {
9537
44.8k
    NEXT;
9538
44.8k
    SKIP_BLANKS;
9539
44.8k
    if ((CUR != 0) &&
9540
44.8k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9541
40.5k
                     (CUR == '_') || (CUR == '.') ||
9542
37.2k
         (CUR == '@') || (CUR == '*')))
9543
20.1k
        xmlXPathCompRelativeLocationPath(ctxt);
9544
44.8k
      }
9545
66.7k
      CHECK_ERROR;
9546
66.7k
  }
9547
64.8k
    }
9548
4.95M
}
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
458k
{
9578
458k
    xmlXPathContextPtr xpctxt;
9579
458k
    xmlNodePtr oldnode;
9580
458k
    xmlDocPtr olddoc;
9581
458k
    xmlXPathStepOpPtr filterOp;
9582
458k
    int oldcs, oldpp;
9583
458k
    int i, j, pos;
9584
9585
458k
    if ((set == NULL) || (set->nodeNr == 0))
9586
10.7k
        return;
9587
9588
    /*
9589
    * Check if the node set contains a sufficient number of nodes for
9590
    * the requested range.
9591
    */
9592
447k
    if (set->nodeNr < minPos) {
9593
85.6k
        xmlXPathNodeSetClear(set, hasNsNodes);
9594
85.6k
        return;
9595
85.6k
    }
9596
9597
361k
    xpctxt = ctxt->context;
9598
361k
    oldnode = xpctxt->node;
9599
361k
    olddoc = xpctxt->doc;
9600
361k
    oldcs = xpctxt->contextSize;
9601
361k
    oldpp = xpctxt->proximityPosition;
9602
361k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9603
9604
361k
    xpctxt->contextSize = set->nodeNr;
9605
9606
3.87M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9607
3.82M
        xmlNodePtr node = set->nodeTab[i];
9608
3.82M
        int res;
9609
9610
3.82M
        xpctxt->node = node;
9611
3.82M
        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
3.82M
        if ((node->type != XML_NAMESPACE_DECL) &&
9620
3.82M
            (node->doc != NULL))
9621
3.82M
            xpctxt->doc = node->doc;
9622
9623
3.82M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9624
9625
3.82M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9626
85
            break;
9627
3.82M
        if (res < 0) {
9628
            /* Shouldn't happen */
9629
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9630
0
            break;
9631
0
        }
9632
9633
3.82M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9634
3.64M
            if (i != j) {
9635
1.44k
                set->nodeTab[j] = node;
9636
1.44k
                set->nodeTab[i] = NULL;
9637
1.44k
            }
9638
9639
3.64M
            j += 1;
9640
3.64M
        } else {
9641
            /* Remove the entry from the initial node set. */
9642
182k
            set->nodeTab[i] = NULL;
9643
182k
            if (node->type == XML_NAMESPACE_DECL)
9644
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9645
182k
        }
9646
9647
3.82M
        if (res != 0) {
9648
3.64M
            if (pos == maxPos) {
9649
312k
                i += 1;
9650
312k
                break;
9651
312k
            }
9652
9653
3.32M
            pos += 1;
9654
3.32M
        }
9655
3.82M
    }
9656
9657
    /* Free remaining nodes. */
9658
361k
    if (hasNsNodes) {
9659
6.21k
        for (; i < set->nodeNr; i++) {
9660
1.00k
            xmlNodePtr node = set->nodeTab[i];
9661
1.00k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9662
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9663
1.00k
        }
9664
5.21k
    }
9665
9666
361k
    set->nodeNr = j;
9667
9668
    /* If too many elements were removed, shrink table to preserve memory. */
9669
361k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9670
82.4k
        (set->nodeNr < set->nodeMax / 2)) {
9671
22.8k
        xmlNodePtr *tmp;
9672
22.8k
        int nodeMax = set->nodeNr;
9673
9674
22.8k
        if (nodeMax < XML_NODESET_DEFAULT)
9675
13.6k
            nodeMax = XML_NODESET_DEFAULT;
9676
22.8k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9677
22.8k
                nodeMax * sizeof(xmlNodePtr));
9678
22.8k
        if (tmp == NULL) {
9679
0
            xmlXPathPErrMemory(ctxt);
9680
22.8k
        } else {
9681
22.8k
            set->nodeTab = tmp;
9682
22.8k
            set->nodeMax = nodeMax;
9683
22.8k
        }
9684
22.8k
    }
9685
9686
361k
    xpctxt->node = oldnode;
9687
361k
    xpctxt->doc = olddoc;
9688
361k
    xpctxt->contextSize = oldcs;
9689
361k
    xpctxt->proximityPosition = oldpp;
9690
361k
}
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
444k
{
9711
444k
    if (op->ch1 != -1) {
9712
2.84k
  xmlXPathCompExprPtr comp = ctxt->comp;
9713
  /*
9714
  * Process inner predicates first.
9715
  */
9716
2.84k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9717
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9718
0
  }
9719
2.84k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9720
2.84k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9721
2.84k
        ctxt->context->depth += 1;
9722
2.84k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9723
2.84k
                                    1, set->nodeNr, hasNsNodes);
9724
2.84k
        ctxt->context->depth -= 1;
9725
2.84k
  CHECK_ERROR;
9726
2.84k
    }
9727
9728
444k
    if (op->ch2 != -1)
9729
444k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9730
444k
}
9731
9732
static int
9733
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9734
          xmlXPathStepOpPtr op,
9735
          int *maxPos)
9736
63.3k
{
9737
9738
63.3k
    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
63.3k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9754
0
  return(0);
9755
9756
63.3k
    if (op->ch2 != -1) {
9757
63.3k
  exprOp = &ctxt->comp->steps[op->ch2];
9758
63.3k
    } else
9759
0
  return(0);
9760
9761
63.3k
    if ((exprOp != NULL) &&
9762
63.3k
  (exprOp->op == XPATH_OP_VALUE) &&
9763
6.82k
  (exprOp->value4 != NULL) &&
9764
6.82k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9765
5.46k
    {
9766
5.46k
        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
5.46k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9780
5.16k
      *maxPos = (int) floatval;
9781
5.16k
            if (floatval == (double) *maxPos)
9782
4.94k
                return(1);
9783
5.16k
        }
9784
5.46k
    }
9785
58.3k
    return(0);
9786
63.3k
}
9787
9788
static int
9789
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9790
                           xmlXPathStepOpPtr op,
9791
         xmlNodePtr * first, xmlNodePtr * last,
9792
         int toBool)
9793
16.9M
{
9794
9795
16.9M
#define XP_TEST_HIT \
9796
19.4M
    if (hasAxisRange != 0) { \
9797
22.8k
  if (++pos == maxPos) { \
9798
4.68k
      if (addNode(seq, cur) < 0) \
9799
4.68k
          xmlXPathPErrMemory(ctxt); \
9800
4.68k
      goto axis_range_end; } \
9801
19.4M
    } else { \
9802
19.4M
  if (addNode(seq, cur) < 0) \
9803
19.4M
      xmlXPathPErrMemory(ctxt); \
9804
19.4M
  if (breakOnFirstHit) goto first_hit; }
9805
9806
16.9M
#define XP_TEST_HIT_NS \
9807
16.9M
    if (hasAxisRange != 0) { \
9808
0
  if (++pos == maxPos) { \
9809
0
      hasNsNodes = 1; \
9810
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9811
0
          xmlXPathPErrMemory(ctxt); \
9812
0
  goto axis_range_end; } \
9813
0
    } else { \
9814
0
  hasNsNodes = 1; \
9815
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9816
0
      xmlXPathPErrMemory(ctxt); \
9817
0
  if (breakOnFirstHit) goto first_hit; }
9818
9819
16.9M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9820
16.9M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9821
16.9M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9822
16.9M
    const xmlChar *prefix = op->value4;
9823
16.9M
    const xmlChar *name = op->value5;
9824
16.9M
    const xmlChar *URI = NULL;
9825
9826
16.9M
    int total = 0, hasNsNodes = 0;
9827
    /* The popped object holding the context nodes */
9828
16.9M
    xmlXPathObjectPtr obj;
9829
    /* The set of context nodes for the node tests */
9830
16.9M
    xmlNodeSetPtr contextSeq;
9831
16.9M
    int contextIdx;
9832
16.9M
    xmlNodePtr contextNode;
9833
    /* The final resulting node set wrt to all context nodes */
9834
16.9M
    xmlNodeSetPtr outSeq;
9835
    /*
9836
    * The temporary resulting node set wrt 1 context node.
9837
    * Used to feed predicate evaluation.
9838
    */
9839
16.9M
    xmlNodeSetPtr seq;
9840
16.9M
    xmlNodePtr cur;
9841
    /* First predicate operator */
9842
16.9M
    xmlXPathStepOpPtr predOp;
9843
16.9M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9844
16.9M
    int hasPredicateRange, hasAxisRange, pos;
9845
16.9M
    int breakOnFirstHit;
9846
9847
16.9M
    xmlXPathTraversalFunction next = NULL;
9848
16.9M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9849
16.9M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9850
16.9M
    xmlNodePtr oldContextNode;
9851
16.9M
    xmlXPathContextPtr xpctxt = ctxt->context;
9852
9853
9854
16.9M
    CHECK_TYPE0(XPATH_NODESET);
9855
16.9M
    obj = xmlXPathValuePop(ctxt);
9856
    /*
9857
    * Setup namespaces.
9858
    */
9859
16.9M
    if (prefix != NULL) {
9860
1.12k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9861
1.12k
        if (URI == NULL) {
9862
117
      xmlXPathReleaseObject(xpctxt, obj);
9863
117
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9864
117
                           "Undefined namespace prefix: %s\n", prefix);
9865
117
            return 0;
9866
117
  }
9867
1.12k
    }
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
16.9M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9882
16.9M
    switch (axis) {
9883
0
        case AXIS_ANCESTOR:
9884
0
            first = NULL;
9885
0
            next = xmlXPathNextAncestor;
9886
0
            break;
9887
0
        case AXIS_ANCESTOR_OR_SELF:
9888
0
            first = NULL;
9889
0
            next = xmlXPathNextAncestorOrSelf;
9890
0
            break;
9891
15.1k
        case AXIS_ATTRIBUTE:
9892
15.1k
            first = NULL;
9893
15.1k
      last = NULL;
9894
15.1k
            next = xmlXPathNextAttribute;
9895
15.1k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9896
15.1k
            break;
9897
16.8M
        case AXIS_CHILD:
9898
16.8M
      last = NULL;
9899
16.8M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9900
16.8M
    (type == NODE_TYPE_NODE))
9901
16.8M
      {
9902
    /*
9903
    * Optimization if an element node type is 'element'.
9904
    */
9905
16.8M
    next = xmlXPathNextChildElement;
9906
16.8M
      } else
9907
1.27k
    next = xmlXPathNextChild;
9908
16.8M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9909
16.8M
            break;
9910
41.1k
        case AXIS_DESCENDANT:
9911
41.1k
      last = NULL;
9912
41.1k
            next = xmlXPathNextDescendant;
9913
41.1k
            break;
9914
52.6k
        case AXIS_DESCENDANT_OR_SELF:
9915
52.6k
      last = NULL;
9916
52.6k
            next = xmlXPathNextDescendantOrSelf;
9917
52.6k
            break;
9918
16
        case AXIS_FOLLOWING:
9919
16
      last = NULL;
9920
16
            next = xmlXPathNextFollowing;
9921
16
            break;
9922
81
        case AXIS_FOLLOWING_SIBLING:
9923
81
      last = NULL;
9924
81
            next = xmlXPathNextFollowingSibling;
9925
81
            break;
9926
0
        case AXIS_NAMESPACE:
9927
0
            first = NULL;
9928
0
      last = NULL;
9929
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9930
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9931
0
            break;
9932
2.97k
        case AXIS_PARENT:
9933
2.97k
            first = NULL;
9934
2.97k
            next = xmlXPathNextParent;
9935
2.97k
            break;
9936
0
        case AXIS_PRECEDING:
9937
0
            first = NULL;
9938
0
            next = xmlXPathNextPrecedingInternal;
9939
0
            break;
9940
0
        case AXIS_PRECEDING_SIBLING:
9941
0
            first = NULL;
9942
0
            next = xmlXPathNextPrecedingSibling;
9943
0
            break;
9944
92
        case AXIS_SELF:
9945
92
            first = NULL;
9946
92
      last = NULL;
9947
92
            next = xmlXPathNextSelf;
9948
92
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9949
92
            break;
9950
16.9M
    }
9951
9952
16.9M
    if (next == NULL) {
9953
0
  xmlXPathReleaseObject(xpctxt, obj);
9954
0
        return(0);
9955
0
    }
9956
16.9M
    contextSeq = obj->nodesetval;
9957
16.9M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9958
118k
        xmlXPathValuePush(ctxt, obj);
9959
118k
        return(0);
9960
118k
    }
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
16.8M
    maxPos = 0;
9980
16.8M
    predOp = NULL;
9981
16.8M
    hasPredicateRange = 0;
9982
16.8M
    hasAxisRange = 0;
9983
16.8M
    if (op->ch2 != -1) {
9984
  /*
9985
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9986
  */
9987
63.3k
  predOp = &ctxt->comp->steps[op->ch2];
9988
63.3k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9989
4.94k
      if (predOp->ch1 != -1) {
9990
    /*
9991
    * Use the next inner predicate operator.
9992
    */
9993
898
    predOp = &ctxt->comp->steps[predOp->ch1];
9994
898
    hasPredicateRange = 1;
9995
4.05k
      } else {
9996
    /*
9997
    * There's no other predicate than the [n] predicate.
9998
    */
9999
4.05k
    predOp = NULL;
10000
4.05k
    hasAxisRange = 1;
10001
4.05k
      }
10002
4.94k
  }
10003
63.3k
    }
10004
16.8M
    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
16.8M
    oldContextNode = xpctxt->node;
10019
16.8M
    addNode = xmlXPathNodeSetAddUnique;
10020
16.8M
    outSeq = NULL;
10021
16.8M
    seq = NULL;
10022
16.8M
    contextNode = NULL;
10023
16.8M
    contextIdx = 0;
10024
10025
10026
40.3M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10027
23.4M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
10028
23.4M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
10029
10030
23.4M
  if (seq == NULL) {
10031
16.9M
      seq = xmlXPathNodeSetCreate(NULL);
10032
16.9M
      if (seq == NULL) {
10033
0
                xmlXPathPErrMemory(ctxt);
10034
0
    total = 0;
10035
0
    goto error;
10036
0
      }
10037
16.9M
  }
10038
  /*
10039
  * Traverse the axis and test the nodes.
10040
  */
10041
23.4M
  pos = 0;
10042
23.4M
  cur = NULL;
10043
23.4M
  hasNsNodes = 0;
10044
66.4M
        do {
10045
66.4M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10046
0
                goto error;
10047
10048
66.4M
            cur = next(ctxt, cur);
10049
66.4M
            if (cur == NULL)
10050
23.4M
                break;
10051
10052
      /*
10053
      * QUESTION TODO: What does the "first" and "last" stuff do?
10054
      */
10055
42.9M
            if ((first != NULL) && (*first != NULL)) {
10056
4.81k
    if (*first == cur)
10057
71
        break;
10058
4.74k
    if (((total % 256) == 0) &&
10059
131
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10060
131
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10061
#else
10062
        (xmlXPathCmpNodes(*first, cur) >= 0))
10063
#endif
10064
89
    {
10065
89
        break;
10066
89
    }
10067
4.74k
      }
10068
42.9M
      if ((last != NULL) && (*last != NULL)) {
10069
0
    if (*last == cur)
10070
0
        break;
10071
0
    if (((total % 256) == 0) &&
10072
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10073
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10074
#else
10075
        (xmlXPathCmpNodes(cur, *last) >= 0))
10076
#endif
10077
0
    {
10078
0
        break;
10079
0
    }
10080
0
      }
10081
10082
42.9M
            total++;
10083
10084
42.9M
      switch (test) {
10085
0
                case NODE_TEST_NONE:
10086
0
        total = 0;
10087
0
        goto error;
10088
7.88M
                case NODE_TEST_TYPE:
10089
7.88M
        if (type == NODE_TYPE_NODE) {
10090
7.88M
      switch (cur->type) {
10091
29.6k
          case XML_DOCUMENT_NODE:
10092
29.6k
          case XML_HTML_DOCUMENT_NODE:
10093
5.42M
          case XML_ELEMENT_NODE:
10094
5.42M
          case XML_ATTRIBUTE_NODE:
10095
6.01M
          case XML_PI_NODE:
10096
6.01M
          case XML_COMMENT_NODE:
10097
6.01M
          case XML_CDATA_SECTION_NODE:
10098
7.88M
          case XML_TEXT_NODE:
10099
7.88M
        XP_TEST_HIT
10100
7.88M
        break;
10101
7.88M
          case XML_NAMESPACE_DECL: {
10102
0
        if (axis == AXIS_NAMESPACE) {
10103
0
            XP_TEST_HIT_NS
10104
0
        } else {
10105
0
                              hasNsNodes = 1;
10106
0
            XP_TEST_HIT
10107
0
        }
10108
0
        break;
10109
0
                            }
10110
329
          default:
10111
329
        break;
10112
7.88M
      }
10113
7.88M
        } else if (cur->type == (xmlElementType) type) {
10114
775
      if (cur->type == XML_NAMESPACE_DECL)
10115
0
          XP_TEST_HIT_NS
10116
775
      else
10117
775
          XP_TEST_HIT
10118
1.11k
        } else if ((type == NODE_TYPE_TEXT) &&
10119
610
       (cur->type == XML_CDATA_SECTION_NODE))
10120
226
        {
10121
226
      XP_TEST_HIT
10122
226
        }
10123
7.88M
        break;
10124
7.88M
                case NODE_TEST_PI:
10125
1.70k
                    if ((cur->type == XML_PI_NODE) &&
10126
277
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10127
0
        {
10128
0
      XP_TEST_HIT
10129
0
                    }
10130
1.70k
                    break;
10131
16.9M
                case NODE_TEST_ALL:
10132
16.9M
                    if (axis == AXIS_ATTRIBUTE) {
10133
63.9k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10134
63.9k
      {
10135
63.9k
                            if (prefix == NULL)
10136
62.7k
          {
10137
62.7k
        XP_TEST_HIT
10138
62.7k
                            } else if ((cur->ns != NULL) &&
10139
302
        (xmlStrEqual(URI, cur->ns->href)))
10140
268
          {
10141
268
        XP_TEST_HIT
10142
268
                            }
10143
63.9k
                        }
10144
16.8M
                    } else if (axis == AXIS_NAMESPACE) {
10145
0
                        if (cur->type == XML_NAMESPACE_DECL)
10146
0
      {
10147
0
          XP_TEST_HIT_NS
10148
0
                        }
10149
16.8M
                    } else {
10150
16.8M
                        if (cur->type == XML_ELEMENT_NODE) {
10151
11.5M
                            if (prefix == NULL)
10152
11.5M
          {
10153
11.5M
        XP_TEST_HIT
10154
10155
11.5M
                            } else if ((cur->ns != NULL) &&
10156
297
        (xmlStrEqual(URI, cur->ns->href)))
10157
0
          {
10158
0
        XP_TEST_HIT
10159
0
                            }
10160
11.5M
                        }
10161
16.8M
                    }
10162
16.9M
                    break;
10163
16.9M
                case NODE_TEST_NS:{
10164
                        /* TODO */
10165
0
                        break;
10166
16.9M
                    }
10167
18.1M
                case NODE_TEST_NAME:
10168
18.1M
                    if (axis == AXIS_ATTRIBUTE) {
10169
4.69k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10170
0
          break;
10171
18.1M
        } else if (axis == AXIS_NAMESPACE) {
10172
0
                        if (cur->type != XML_NAMESPACE_DECL)
10173
0
          break;
10174
18.1M
        } else {
10175
18.1M
            if (cur->type != XML_ELEMENT_NODE)
10176
1.76M
          break;
10177
18.1M
        }
10178
16.3M
                    switch (cur->type) {
10179
16.3M
                        case XML_ELEMENT_NODE:
10180
16.3M
                            if (xmlStrEqual(name, cur->name)) {
10181
1.09k
                                if (prefix == NULL) {
10182
683
                                    if (cur->ns == NULL)
10183
407
            {
10184
407
          XP_TEST_HIT
10185
407
                                    }
10186
683
                                } else {
10187
409
                                    if ((cur->ns != NULL) &&
10188
203
                                        (xmlStrEqual(URI, cur->ns->href)))
10189
0
            {
10190
0
          XP_TEST_HIT
10191
0
                                    }
10192
409
                                }
10193
1.09k
                            }
10194
16.3M
                            break;
10195
16.3M
                        case XML_ATTRIBUTE_NODE:{
10196
4.69k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10197
10198
4.69k
                                if (xmlStrEqual(name, attr->name)) {
10199
1.17k
                                    if (prefix == NULL) {
10200
855
                                        if ((attr->ns == NULL) ||
10201
353
                                            (attr->ns->prefix == NULL))
10202
502
          {
10203
502
              XP_TEST_HIT
10204
502
                                        }
10205
855
                                    } else {
10206
318
                                        if ((attr->ns != NULL) &&
10207
252
                                            (xmlStrEqual(URI,
10208
252
                attr->ns->href)))
10209
218
          {
10210
218
              XP_TEST_HIT
10211
218
                                        }
10212
318
                                    }
10213
1.17k
                                }
10214
4.61k
                                break;
10215
4.69k
                            }
10216
4.61k
                        case XML_NAMESPACE_DECL:
10217
0
                            if (cur->type == XML_NAMESPACE_DECL) {
10218
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
10219
10220
0
                                if ((ns->prefix != NULL) && (name != NULL)
10221
0
                                    && (xmlStrEqual(ns->prefix, name)))
10222
0
        {
10223
0
            XP_TEST_HIT_NS
10224
0
                                }
10225
0
                            }
10226
0
                            break;
10227
0
                        default:
10228
0
                            break;
10229
16.3M
                    }
10230
16.3M
                    break;
10231
42.9M
      } /* switch(test) */
10232
42.9M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10233
10234
23.4M
  goto apply_predicates;
10235
10236
23.4M
axis_range_end: /* ----------------------------------------------------- */
10237
  /*
10238
  * We have a "/foo[n]", and position() = n was reached.
10239
  * Note that we can have as well "/foo/::parent::foo[1]", so
10240
  * a duplicate-aware merge is still needed.
10241
  * Merge with the result.
10242
  */
10243
4.68k
  if (outSeq == NULL) {
10244
1.25k
      outSeq = seq;
10245
1.25k
      seq = NULL;
10246
3.43k
  } else {
10247
3.43k
      outSeq = mergeAndClear(outSeq, seq);
10248
3.43k
            if (outSeq == NULL)
10249
0
                xmlXPathPErrMemory(ctxt);
10250
3.43k
        }
10251
  /*
10252
  * Break if only a true/false result was requested.
10253
  */
10254
4.68k
  if (toBool)
10255
495
      break;
10256
4.19k
  continue;
10257
10258
4.19k
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
2.16k
  if (outSeq == NULL) {
10264
2.16k
      outSeq = seq;
10265
2.16k
      seq = NULL;
10266
2.16k
  } else {
10267
0
      outSeq = mergeAndClear(outSeq, seq);
10268
0
            if (outSeq == NULL)
10269
0
                xmlXPathPErrMemory(ctxt);
10270
0
        }
10271
2.16k
  break;
10272
10273
23.4M
apply_predicates: /* --------------------------------------------------- */
10274
23.4M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10275
0
      goto error;
10276
10277
        /*
10278
  * Apply predicates.
10279
  */
10280
23.4M
        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
441k
      if (hasPredicateRange != 0)
10310
94.9k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10311
94.9k
              hasNsNodes);
10312
346k
      else
10313
346k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10314
346k
              hasNsNodes);
10315
10316
441k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10317
48
    total = 0;
10318
48
    goto error;
10319
48
      }
10320
441k
        }
10321
10322
23.4M
        if (seq->nodeNr > 0) {
10323
      /*
10324
      * Add to result set.
10325
      */
10326
1.45M
      if (outSeq == NULL) {
10327
459k
    outSeq = seq;
10328
459k
    seq = NULL;
10329
994k
      } else {
10330
994k
    outSeq = mergeAndClear(outSeq, seq);
10331
994k
                if (outSeq == NULL)
10332
0
                    xmlXPathPErrMemory(ctxt);
10333
994k
      }
10334
10335
1.45M
            if (toBool)
10336
10.8k
                break;
10337
1.45M
  }
10338
23.4M
    }
10339
10340
16.8M
error:
10341
16.8M
    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
16.8M
    xmlXPathReleaseObject(xpctxt, obj);
10353
10354
    /*
10355
    * Ensure we return at least an empty set.
10356
    */
10357
16.8M
    if (outSeq == NULL) {
10358
16.4M
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10359
16.4M
      outSeq = seq;
10360
16.4M
        } else {
10361
4
      outSeq = xmlXPathNodeSetCreate(NULL);
10362
4
            if (outSeq == NULL)
10363
0
                xmlXPathPErrMemory(ctxt);
10364
4
        }
10365
16.4M
    }
10366
16.8M
    if ((seq != NULL) && (seq != outSeq)) {
10367
36.8k
   xmlXPathFreeNodeSet(seq);
10368
36.8k
    }
10369
    /*
10370
    * Hand over the result. Better to push the set also in
10371
    * case of errors.
10372
    */
10373
16.8M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10374
    /*
10375
    * Reset the context node.
10376
    */
10377
16.8M
    xpctxt->node = oldContextNode;
10378
    /*
10379
    * When traversing the namespace axis in "toBool" mode, it's
10380
    * possible that tmpNsList wasn't freed.
10381
    */
10382
16.8M
    if (xpctxt->tmpNsList != NULL) {
10383
0
        xmlFree(xpctxt->tmpNsList);
10384
0
        xpctxt->tmpNsList = NULL;
10385
0
    }
10386
10387
16.8M
    return(total);
10388
16.8M
}
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
10.3k
{
10407
10.3k
    int total = 0, cur;
10408
10.3k
    xmlXPathCompExprPtr comp;
10409
10.3k
    xmlXPathObjectPtr arg1, arg2;
10410
10411
10.3k
    CHECK_ERROR0;
10412
10.3k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10413
0
        return(0);
10414
10.3k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10415
10.3k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10416
10.3k
    ctxt->context->depth += 1;
10417
10.3k
    comp = ctxt->comp;
10418
10.3k
    switch (op->op) {
10419
0
        case XPATH_OP_END:
10420
0
            break;
10421
414
        case XPATH_OP_UNION:
10422
414
            total =
10423
414
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10424
414
                                        first);
10425
414
      CHECK_ERROR0;
10426
342
            if ((ctxt->value != NULL)
10427
342
                && (ctxt->value->type == XPATH_NODESET)
10428
340
                && (ctxt->value->nodesetval != NULL)
10429
340
                && (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
190
    if (ctxt->value->nodesetval->nodeNr > 1)
10441
101
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10442
190
                *first = ctxt->value->nodesetval->nodeTab[0];
10443
190
            }
10444
342
            cur =
10445
342
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10446
342
                                        first);
10447
342
      CHECK_ERROR0;
10448
10449
339
            arg2 = xmlXPathValuePop(ctxt);
10450
339
            arg1 = xmlXPathValuePop(ctxt);
10451
339
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10452
337
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10453
13
          xmlXPathReleaseObject(ctxt->context, arg1);
10454
13
          xmlXPathReleaseObject(ctxt->context, arg2);
10455
13
                XP_ERROR0(XPATH_INVALID_TYPE);
10456
0
            }
10457
326
            if ((ctxt->context->opLimit != 0) &&
10458
0
                (((arg1->nodesetval != NULL) &&
10459
0
                  (xmlXPathCheckOpLimit(ctxt,
10460
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10461
0
                 ((arg2->nodesetval != NULL) &&
10462
0
                  (xmlXPathCheckOpLimit(ctxt,
10463
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10464
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10465
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10466
0
                break;
10467
0
            }
10468
10469
326
            if ((arg2->nodesetval != NULL) &&
10470
326
                (arg2->nodesetval->nodeNr != 0)) {
10471
79
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10472
79
                                                        arg2->nodesetval);
10473
79
                if (arg1->nodesetval == NULL)
10474
0
                    xmlXPathPErrMemory(ctxt);
10475
79
            }
10476
326
            xmlXPathValuePush(ctxt, arg1);
10477
326
      xmlXPathReleaseObject(ctxt->context, arg2);
10478
326
            total += cur;
10479
326
            break;
10480
73
        case XPATH_OP_ROOT:
10481
73
            xmlXPathRoot(ctxt);
10482
73
            break;
10483
203
        case XPATH_OP_NODE:
10484
203
            if (op->ch1 != -1)
10485
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10486
203
      CHECK_ERROR0;
10487
203
            if (op->ch2 != -1)
10488
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10489
203
      CHECK_ERROR0;
10490
203
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10491
203
    ctxt->context->node));
10492
203
            break;
10493
1.35k
        case XPATH_OP_COLLECT:{
10494
1.35k
                if (op->ch1 == -1)
10495
0
                    break;
10496
10497
1.35k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10498
1.35k
    CHECK_ERROR0;
10499
10500
1.35k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10501
1.35k
                break;
10502
1.35k
            }
10503
14
        case XPATH_OP_VALUE:
10504
14
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10505
14
            break;
10506
1.70k
        case XPATH_OP_SORT:
10507
1.70k
            if (op->ch1 != -1)
10508
1.70k
                total +=
10509
1.70k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10510
1.70k
                                            first);
10511
1.70k
      CHECK_ERROR0;
10512
1.68k
            if ((ctxt->value != NULL)
10513
1.68k
                && (ctxt->value->type == XPATH_NODESET)
10514
1.27k
                && (ctxt->value->nodesetval != NULL)
10515
1.27k
    && (ctxt->value->nodesetval->nodeNr > 1))
10516
737
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10517
1.68k
            break;
10518
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10519
6.21k
  case XPATH_OP_FILTER:
10520
6.21k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10521
6.21k
            break;
10522
0
#endif
10523
405
        default:
10524
405
            total += xmlXPathCompOpEval(ctxt, op);
10525
405
            break;
10526
10.3k
    }
10527
10528
10.2k
    ctxt->context->depth -= 1;
10529
10.2k
    return(total);
10530
10.3k
}
10531
10532
/**
10533
 * Evaluate the Precompiled XPath operation searching only the last
10534
 * element in document order
10535
 *
10536
 * @param ctxt  the XPath parser context with the compiled expression
10537
 * @param op  an XPath compiled operation
10538
 * @param last  the last elem found so far
10539
 * @returns the number of nodes traversed
10540
 */
10541
static int
10542
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10543
                       xmlNodePtr * last)
10544
0
{
10545
0
    int total = 0, cur;
10546
0
    xmlXPathCompExprPtr comp;
10547
0
    xmlXPathObjectPtr arg1, arg2;
10548
10549
0
    CHECK_ERROR0;
10550
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10551
0
        return(0);
10552
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10553
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10554
0
    ctxt->context->depth += 1;
10555
0
    comp = ctxt->comp;
10556
0
    switch (op->op) {
10557
0
        case XPATH_OP_END:
10558
0
            break;
10559
0
        case XPATH_OP_UNION:
10560
0
            total =
10561
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10562
0
      CHECK_ERROR0;
10563
0
            if ((ctxt->value != NULL)
10564
0
                && (ctxt->value->type == XPATH_NODESET)
10565
0
                && (ctxt->value->nodesetval != NULL)
10566
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10567
                /*
10568
                 * limit tree traversing to first node in the result
10569
                 */
10570
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10571
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10572
0
                *last =
10573
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10574
0
                                                     nodesetval->nodeNr -
10575
0
                                                     1];
10576
0
            }
10577
0
            cur =
10578
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10579
0
      CHECK_ERROR0;
10580
0
            if ((ctxt->value != NULL)
10581
0
                && (ctxt->value->type == XPATH_NODESET)
10582
0
                && (ctxt->value->nodesetval != NULL)
10583
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10584
0
            }
10585
10586
0
            arg2 = xmlXPathValuePop(ctxt);
10587
0
            arg1 = xmlXPathValuePop(ctxt);
10588
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10589
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10590
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10591
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10592
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10593
0
            }
10594
0
            if ((ctxt->context->opLimit != 0) &&
10595
0
                (((arg1->nodesetval != NULL) &&
10596
0
                  (xmlXPathCheckOpLimit(ctxt,
10597
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10598
0
                 ((arg2->nodesetval != NULL) &&
10599
0
                  (xmlXPathCheckOpLimit(ctxt,
10600
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10601
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10602
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10603
0
                break;
10604
0
            }
10605
10606
0
            if ((arg2->nodesetval != NULL) &&
10607
0
                (arg2->nodesetval->nodeNr != 0)) {
10608
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10609
0
                                                        arg2->nodesetval);
10610
0
                if (arg1->nodesetval == NULL)
10611
0
                    xmlXPathPErrMemory(ctxt);
10612
0
            }
10613
0
            xmlXPathValuePush(ctxt, arg1);
10614
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10615
0
            total += cur;
10616
0
            break;
10617
0
        case XPATH_OP_ROOT:
10618
0
            xmlXPathRoot(ctxt);
10619
0
            break;
10620
0
        case XPATH_OP_NODE:
10621
0
            if (op->ch1 != -1)
10622
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10623
0
      CHECK_ERROR0;
10624
0
            if (op->ch2 != -1)
10625
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10626
0
      CHECK_ERROR0;
10627
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10628
0
    ctxt->context->node));
10629
0
            break;
10630
0
        case XPATH_OP_COLLECT:{
10631
0
                if (op->ch1 == -1)
10632
0
                    break;
10633
10634
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10635
0
    CHECK_ERROR0;
10636
10637
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10638
0
                break;
10639
0
            }
10640
0
        case XPATH_OP_VALUE:
10641
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10642
0
            break;
10643
0
        case XPATH_OP_SORT:
10644
0
            if (op->ch1 != -1)
10645
0
                total +=
10646
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10647
0
                                           last);
10648
0
      CHECK_ERROR0;
10649
0
            if ((ctxt->value != NULL)
10650
0
                && (ctxt->value->type == XPATH_NODESET)
10651
0
                && (ctxt->value->nodesetval != NULL)
10652
0
    && (ctxt->value->nodesetval->nodeNr > 1))
10653
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10654
0
            break;
10655
0
        default:
10656
0
            total += xmlXPathCompOpEval(ctxt, op);
10657
0
            break;
10658
0
    }
10659
10660
0
    ctxt->context->depth -= 1;
10661
0
    return (total);
10662
0
}
10663
10664
#ifdef XP_OPTIMIZED_FILTER_FIRST
10665
static int
10666
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10667
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10668
6.21k
{
10669
6.21k
    int total = 0;
10670
6.21k
    xmlXPathCompExprPtr comp;
10671
6.21k
    xmlXPathObjectPtr obj;
10672
6.21k
    xmlNodeSetPtr set;
10673
10674
6.21k
    CHECK_ERROR0;
10675
6.21k
    comp = ctxt->comp;
10676
    /*
10677
    * Optimization for ()[last()] selection i.e. the last elem
10678
    */
10679
6.21k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10680
6.21k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10681
1.18k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10682
72
  int f = comp->steps[op->ch2].ch1;
10683
10684
72
  if ((f != -1) &&
10685
72
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10686
31
      (comp->steps[f].value5 == NULL) &&
10687
28
      (comp->steps[f].value == 0) &&
10688
18
      (comp->steps[f].value4 != NULL) &&
10689
18
      (xmlStrEqual
10690
18
      (comp->steps[f].value4, BAD_CAST "last"))) {
10691
0
      xmlNodePtr last = NULL;
10692
10693
0
      total +=
10694
0
    xmlXPathCompOpEvalLast(ctxt,
10695
0
        &comp->steps[op->ch1],
10696
0
        &last);
10697
0
      CHECK_ERROR0;
10698
      /*
10699
      * The nodeset should be in document order,
10700
      * Keep only the last value
10701
      */
10702
0
      if ((ctxt->value != NULL) &&
10703
0
    (ctxt->value->type == XPATH_NODESET) &&
10704
0
    (ctxt->value->nodesetval != NULL) &&
10705
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10706
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
10707
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10708
0
    *first = *(ctxt->value->nodesetval->nodeTab);
10709
0
      }
10710
0
      return (total);
10711
0
  }
10712
72
    }
10713
10714
6.21k
    if (op->ch1 != -1)
10715
6.21k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10716
6.21k
    CHECK_ERROR0;
10717
5.30k
    if (op->ch2 == -1)
10718
0
  return (total);
10719
5.30k
    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
5.30k
    CHECK_TYPE0(XPATH_NODESET);
10728
5.30k
    obj = xmlXPathValuePop(ctxt);
10729
5.30k
    set = obj->nodesetval;
10730
5.30k
    if (set != NULL) {
10731
5.30k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10732
5.30k
        if (set->nodeNr > 0)
10733
1.91k
            *first = set->nodeTab[0];
10734
5.30k
    }
10735
5.30k
    xmlXPathValuePush(ctxt, obj);
10736
10737
5.30k
    return (total);
10738
5.30k
}
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
48.9M
{
10751
48.9M
    int total = 0;
10752
48.9M
    int equal, ret;
10753
48.9M
    xmlXPathCompExprPtr comp;
10754
48.9M
    xmlXPathObjectPtr arg1, arg2;
10755
10756
48.9M
    CHECK_ERROR0;
10757
48.9M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10758
0
        return(0);
10759
48.9M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10760
48.9M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10761
48.9M
    ctxt->context->depth += 1;
10762
48.9M
    comp = ctxt->comp;
10763
48.9M
    switch (op->op) {
10764
0
        case XPATH_OP_END:
10765
0
            break;
10766
1.03M
        case XPATH_OP_AND:
10767
1.03M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10768
1.03M
      CHECK_ERROR0;
10769
1.03M
            xmlXPathBooleanFunction(ctxt, 1);
10770
1.03M
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10771
1.02M
                break;
10772
912
            arg2 = xmlXPathValuePop(ctxt);
10773
912
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10774
912
      if (ctxt->error) {
10775
53
    xmlXPathFreeObject(arg2);
10776
53
    break;
10777
53
      }
10778
859
            xmlXPathBooleanFunction(ctxt, 1);
10779
859
            if (ctxt->value != NULL)
10780
859
                ctxt->value->boolval &= arg2->boolval;
10781
859
      xmlXPathReleaseObject(ctxt->context, arg2);
10782
859
            break;
10783
8.27k
        case XPATH_OP_OR:
10784
8.27k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10785
8.27k
      CHECK_ERROR0;
10786
7.46k
            xmlXPathBooleanFunction(ctxt, 1);
10787
7.46k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10788
2.25k
                break;
10789
5.21k
            arg2 = xmlXPathValuePop(ctxt);
10790
5.21k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10791
5.21k
      if (ctxt->error) {
10792
151
    xmlXPathFreeObject(arg2);
10793
151
    break;
10794
151
      }
10795
5.06k
            xmlXPathBooleanFunction(ctxt, 1);
10796
5.06k
            if (ctxt->value != NULL)
10797
5.06k
                ctxt->value->boolval |= arg2->boolval;
10798
5.06k
      xmlXPathReleaseObject(ctxt->context, arg2);
10799
5.06k
            break;
10800
6.66M
        case XPATH_OP_EQUAL:
10801
6.66M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10802
6.66M
      CHECK_ERROR0;
10803
6.66M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10804
6.66M
      CHECK_ERROR0;
10805
6.66M
      if (op->value)
10806
6.64M
    equal = xmlXPathEqualValues(ctxt);
10807
13.2k
      else
10808
13.2k
    equal = xmlXPathNotEqualValues(ctxt);
10809
6.66M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10810
6.66M
            break;
10811
2.97M
        case XPATH_OP_CMP:
10812
2.97M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10813
2.97M
      CHECK_ERROR0;
10814
2.97M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10815
2.97M
      CHECK_ERROR0;
10816
2.97M
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10817
2.97M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10818
2.97M
            break;
10819
2.66M
        case XPATH_OP_PLUS:
10820
2.66M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10821
2.66M
      CHECK_ERROR0;
10822
2.66M
            if (op->ch2 != -1) {
10823
2.62M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10824
2.62M
      }
10825
2.66M
      CHECK_ERROR0;
10826
2.65M
            if (op->value == 0)
10827
37.4k
                xmlXPathSubValues(ctxt);
10828
2.62M
            else if (op->value == 1)
10829
2.58M
                xmlXPathAddValues(ctxt);
10830
32.3k
            else if (op->value == 2)
10831
20.8k
                xmlXPathValueFlipSign(ctxt);
10832
11.4k
            else if (op->value == 3) {
10833
11.4k
                CAST_TO_NUMBER;
10834
11.4k
                CHECK_TYPE0(XPATH_NUMBER);
10835
11.4k
            }
10836
2.65M
            break;
10837
2.65M
        case XPATH_OP_MULT:
10838
1.09M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10839
1.09M
      CHECK_ERROR0;
10840
1.08M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10841
1.08M
      CHECK_ERROR0;
10842
1.08M
            if (op->value == 0)
10843
1.08M
                xmlXPathMultValues(ctxt);
10844
1.81k
            else if (op->value == 1)
10845
1.01k
                xmlXPathDivValues(ctxt);
10846
799
            else if (op->value == 2)
10847
799
                xmlXPathModValues(ctxt);
10848
1.08M
            break;
10849
118k
        case XPATH_OP_UNION:
10850
118k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10851
118k
      CHECK_ERROR0;
10852
118k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10853
118k
      CHECK_ERROR0;
10854
10855
118k
            arg2 = xmlXPathValuePop(ctxt);
10856
118k
            arg1 = xmlXPathValuePop(ctxt);
10857
118k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10858
118k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10859
39
          xmlXPathReleaseObject(ctxt->context, arg1);
10860
39
          xmlXPathReleaseObject(ctxt->context, arg2);
10861
39
                XP_ERROR0(XPATH_INVALID_TYPE);
10862
0
            }
10863
118k
            if ((ctxt->context->opLimit != 0) &&
10864
0
                (((arg1->nodesetval != NULL) &&
10865
0
                  (xmlXPathCheckOpLimit(ctxt,
10866
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10867
0
                 ((arg2->nodesetval != NULL) &&
10868
0
                  (xmlXPathCheckOpLimit(ctxt,
10869
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10870
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10871
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10872
0
                break;
10873
0
            }
10874
10875
118k
      if (((arg2->nodesetval != NULL) &&
10876
118k
     (arg2->nodesetval->nodeNr != 0)))
10877
17.8k
      {
10878
17.8k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10879
17.8k
              arg2->nodesetval);
10880
17.8k
                if (arg1->nodesetval == NULL)
10881
0
                    xmlXPathPErrMemory(ctxt);
10882
17.8k
      }
10883
10884
118k
            xmlXPathValuePush(ctxt, arg1);
10885
118k
      xmlXPathReleaseObject(ctxt->context, arg2);
10886
118k
            break;
10887
3.68M
        case XPATH_OP_ROOT:
10888
3.68M
            xmlXPathRoot(ctxt);
10889
3.68M
            break;
10890
13.4M
        case XPATH_OP_NODE:
10891
13.4M
            if (op->ch1 != -1)
10892
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10893
13.4M
      CHECK_ERROR0;
10894
13.4M
            if (op->ch2 != -1)
10895
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10896
13.4M
      CHECK_ERROR0;
10897
13.4M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10898
13.4M
                                                    ctxt->context->node));
10899
13.4M
            break;
10900
16.9M
        case XPATH_OP_COLLECT:{
10901
16.9M
                if (op->ch1 == -1)
10902
0
                    break;
10903
10904
16.9M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10905
16.9M
    CHECK_ERROR0;
10906
10907
16.9M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10908
16.9M
                break;
10909
16.9M
            }
10910
190k
        case XPATH_OP_VALUE:
10911
190k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10912
190k
            break;
10913
13
        case XPATH_OP_VARIABLE:{
10914
13
    xmlXPathObjectPtr val;
10915
10916
13
                if (op->ch1 != -1)
10917
0
                    total +=
10918
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10919
13
                if (op->value5 == NULL) {
10920
10
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10921
10
        if (val == NULL) {
10922
10
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10923
10
                                       "Undefined variable: %s\n", op->value4);
10924
10
                        return 0;
10925
10
                    }
10926
0
                    xmlXPathValuePush(ctxt, val);
10927
3
    } else {
10928
3
                    const xmlChar *URI;
10929
10930
3
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10931
3
                    if (URI == NULL) {
10932
2
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10933
2
                                       "Undefined namespace prefix: %s\n",
10934
2
                                       op->value5);
10935
2
                        return 0;
10936
2
                    }
10937
1
        val = xmlXPathVariableLookupNS(ctxt->context,
10938
1
                                                       op->value4, URI);
10939
1
        if (val == NULL) {
10940
1
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10941
1
                                       "Undefined variable: %s:%s\n",
10942
1
                                       op->value5, op->value4);
10943
1
                        return 0;
10944
1
                    }
10945
0
                    xmlXPathValuePush(ctxt, val);
10946
0
                }
10947
0
                break;
10948
13
            }
10949
25.9k
        case XPATH_OP_FUNCTION:{
10950
25.9k
                xmlXPathFunction func;
10951
25.9k
                const xmlChar *oldFunc, *oldFuncURI;
10952
25.9k
    int i;
10953
25.9k
                int frame;
10954
10955
25.9k
                frame = ctxt->valueNr;
10956
25.9k
                if (op->ch1 != -1) {
10957
24.2k
                    total +=
10958
24.2k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10959
24.2k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10960
1.01k
                        break;
10961
24.2k
                }
10962
24.9k
    if (ctxt->valueNr < frame + op->value)
10963
24.9k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10964
75.8k
    for (i = 0; i < op->value; i++) {
10965
50.9k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10966
50.9k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10967
50.9k
                }
10968
24.9k
                if (op->cache != NULL)
10969
17.7k
                    func = op->cache;
10970
7.13k
                else {
10971
7.13k
                    const xmlChar *URI = NULL;
10972
10973
7.13k
                    if (op->value5 == NULL) {
10974
7.12k
                        func = xmlXPathFunctionLookup(ctxt->context,
10975
7.12k
                                                      op->value4);
10976
7.12k
                        if (func == NULL) {
10977
268
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10978
268
                                           "Unregistered function: %s\n",
10979
268
                                           op->value4);
10980
268
                            return 0;
10981
268
                        }
10982
7.12k
                    } else {
10983
11
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10984
11
                        if (URI == NULL) {
10985
10
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10986
10
                                           "Undefined namespace prefix: %s\n",
10987
10
                                           op->value5);
10988
10
                            return 0;
10989
10
                        }
10990
1
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10991
1
                                                        op->value4, URI);
10992
1
                        if (func == NULL) {
10993
1
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10994
1
                                           "Unregistered function: %s:%s\n",
10995
1
                                           op->value5, op->value4);
10996
1
                            return 0;
10997
1
                        }
10998
1
                    }
10999
6.85k
                    op->cache = func;
11000
6.85k
                    op->cacheURI = (void *) URI;
11001
6.85k
                }
11002
24.6k
                oldFunc = ctxt->context->function;
11003
24.6k
                oldFuncURI = ctxt->context->functionURI;
11004
24.6k
                ctxt->context->function = op->value4;
11005
24.6k
                ctxt->context->functionURI = op->cacheURI;
11006
24.6k
                func(ctxt, op->value);
11007
24.6k
                ctxt->context->function = oldFunc;
11008
24.6k
                ctxt->context->functionURI = oldFuncURI;
11009
24.6k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11010
23.1k
                    (ctxt->valueNr != frame + 1))
11011
24.6k
                    XP_ERROR0(XPATH_STACK_ERROR);
11012
24.6k
                break;
11013
24.6k
            }
11014
58.6k
        case XPATH_OP_ARG:
11015
58.6k
            if (op->ch1 != -1) {
11016
34.4k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11017
34.4k
          CHECK_ERROR0;
11018
34.4k
            }
11019
53.8k
            if (op->ch2 != -1) {
11020
53.8k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11021
53.8k
          CHECK_ERROR0;
11022
53.8k
      }
11023
52.8k
            break;
11024
52.8k
        case XPATH_OP_PREDICATE:
11025
16.9k
        case XPATH_OP_FILTER:{
11026
16.9k
                xmlXPathObjectPtr obj;
11027
16.9k
                xmlNodeSetPtr set;
11028
11029
                /*
11030
                 * Optimization for ()[1] selection i.e. the first elem
11031
                 */
11032
16.9k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11033
16.9k
#ifdef XP_OPTIMIZED_FILTER_FIRST
11034
        /*
11035
        * FILTER TODO: Can we assume that the inner processing
11036
        *  will result in an ordered list if we have an
11037
        *  XPATH_OP_FILTER?
11038
        *  What about an additional field or flag on
11039
        *  xmlXPathObject like @sorted ? This way we wouldn't need
11040
        *  to assume anything, so it would be more robust and
11041
        *  easier to optimize.
11042
        */
11043
16.9k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11044
13.5k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11045
#else
11046
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
#endif
11048
13.8k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11049
8.73k
                    xmlXPathObjectPtr val;
11050
11051
8.73k
                    val = comp->steps[op->ch2].value4;
11052
8.73k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11053
8.69k
                        (val->floatval == 1.0)) {
11054
7.92k
                        xmlNodePtr first = NULL;
11055
11056
7.92k
                        total +=
11057
7.92k
                            xmlXPathCompOpEvalFirst(ctxt,
11058
7.92k
                                                    &comp->steps[op->ch1],
11059
7.92k
                                                    &first);
11060
7.92k
      CHECK_ERROR0;
11061
                        /*
11062
                         * The nodeset should be in document order,
11063
                         * Keep only the first value
11064
                         */
11065
6.98k
                        if ((ctxt->value != NULL) &&
11066
6.98k
                            (ctxt->value->type == XPATH_NODESET) &&
11067
6.57k
                            (ctxt->value->nodesetval != NULL) &&
11068
6.57k
                            (ctxt->value->nodesetval->nodeNr > 1))
11069
737
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11070
737
                                                        1, 1);
11071
6.98k
                        break;
11072
7.92k
                    }
11073
8.73k
                }
11074
                /*
11075
                 * Optimization for ()[last()] selection i.e. the last elem
11076
                 */
11077
9.03k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11078
9.03k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11079
1.72k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11080
1.10k
                    int f = comp->steps[op->ch2].ch1;
11081
11082
1.10k
                    if ((f != -1) &&
11083
1.10k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11084
23
                        (comp->steps[f].value5 == NULL) &&
11085
20
                        (comp->steps[f].value == 0) &&
11086
10
                        (comp->steps[f].value4 != NULL) &&
11087
10
                        (xmlStrEqual
11088
10
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11089
0
                        xmlNodePtr last = NULL;
11090
11091
0
                        total +=
11092
0
                            xmlXPathCompOpEvalLast(ctxt,
11093
0
                                                   &comp->steps[op->ch1],
11094
0
                                                   &last);
11095
0
      CHECK_ERROR0;
11096
                        /*
11097
                         * The nodeset should be in document order,
11098
                         * Keep only the last value
11099
                         */
11100
0
                        if ((ctxt->value != NULL) &&
11101
0
                            (ctxt->value->type == XPATH_NODESET) &&
11102
0
                            (ctxt->value->nodesetval != NULL) &&
11103
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11104
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11105
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11106
0
                        break;
11107
0
                    }
11108
1.10k
                }
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
9.03k
                if (op->ch1 != -1)
11121
9.03k
                    total +=
11122
9.03k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11123
9.03k
    CHECK_ERROR0;
11124
8.37k
                if (op->ch2 == -1)
11125
0
                    break;
11126
8.37k
                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
8.37k
                CHECK_TYPE0(XPATH_NODESET);
11136
8.35k
                obj = xmlXPathValuePop(ctxt);
11137
8.35k
                set = obj->nodesetval;
11138
8.35k
                if (set != NULL)
11139
8.35k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11140
8.35k
                                          1, set->nodeNr, 1);
11141
8.35k
                xmlXPathValuePush(ctxt, obj);
11142
8.35k
                break;
11143
8.37k
            }
11144
60.9k
        case XPATH_OP_SORT:
11145
60.9k
            if (op->ch1 != -1)
11146
60.9k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11147
60.9k
      CHECK_ERROR0;
11148
57.5k
            if ((ctxt->value != NULL) &&
11149
57.5k
                (ctxt->value->type == XPATH_NODESET) &&
11150
30.7k
                (ctxt->value->nodesetval != NULL) &&
11151
30.7k
    (ctxt->value->nodesetval->nodeNr > 1))
11152
6.62k
      {
11153
6.62k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11154
6.62k
      }
11155
57.5k
            break;
11156
0
        default:
11157
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11158
0
            break;
11159
48.9M
    }
11160
11161
48.9M
    ctxt->context->depth -= 1;
11162
48.9M
    return (total);
11163
48.9M
}
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
3.82M
{
11178
3.82M
    xmlXPathObjectPtr resObj = NULL;
11179
11180
3.84M
start:
11181
3.84M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11182
0
        return(0);
11183
    /* comp = ctxt->comp; */
11184
3.84M
    switch (op->op) {
11185
0
        case XPATH_OP_END:
11186
0
            return (0);
11187
28.6k
  case XPATH_OP_VALUE:
11188
28.6k
      resObj = (xmlXPathObjectPtr) op->value4;
11189
28.6k
      if (isPredicate)
11190
28.6k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11191
0
      return(xmlXPathCastToBoolean(resObj));
11192
18.8k
  case XPATH_OP_SORT:
11193
      /*
11194
      * We don't need sorting for boolean results. Skip this one.
11195
      */
11196
18.8k
            if (op->ch1 != -1) {
11197
18.8k
    op = &ctxt->comp->steps[op->ch1];
11198
18.8k
    goto start;
11199
18.8k
      }
11200
0
      return(0);
11201
27.0k
  case XPATH_OP_COLLECT:
11202
27.0k
      if (op->ch1 == -1)
11203
0
    return(0);
11204
11205
27.0k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11206
27.0k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11207
3
    return(-1);
11208
11209
27.0k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11210
27.0k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11211
15
    return(-1);
11212
11213
27.0k
      resObj = xmlXPathValuePop(ctxt);
11214
27.0k
      if (resObj == NULL)
11215
0
    return(-1);
11216
27.0k
      break;
11217
3.76M
  default:
11218
      /*
11219
      * Fallback to call xmlXPathCompOpEval().
11220
      */
11221
3.76M
      xmlXPathCompOpEval(ctxt, op);
11222
3.76M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11223
67
    return(-1);
11224
11225
3.76M
      resObj = xmlXPathValuePop(ctxt);
11226
3.76M
      if (resObj == NULL)
11227
0
    return(-1);
11228
3.76M
      break;
11229
3.84M
    }
11230
11231
3.79M
    if (resObj) {
11232
3.79M
  int res;
11233
11234
3.79M
  if (resObj->type == XPATH_BOOLEAN) {
11235
3.40M
      res = resObj->boolval;
11236
3.40M
  } 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
384k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11246
384k
  } else {
11247
0
      res = xmlXPathCastToBoolean(resObj);
11248
0
  }
11249
3.79M
  xmlXPathReleaseObject(ctxt->context, resObj);
11250
3.79M
  return(res);
11251
3.79M
    }
11252
11253
0
    return(0);
11254
3.79M
}
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
7.09k
{
11497
7.09k
    xmlXPathCompExprPtr comp;
11498
7.09k
    int oldDepth;
11499
11500
7.09k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11501
0
  return(-1);
11502
11503
7.09k
    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
7.09k
    comp = ctxt->comp;
11553
7.09k
    if (comp->last < 0) {
11554
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11555
0
  return(-1);
11556
0
    }
11557
7.09k
    oldDepth = ctxt->context->depth;
11558
7.09k
    if (toBool)
11559
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11560
0
      &comp->steps[comp->last], 0));
11561
7.09k
    else
11562
7.09k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11563
7.09k
    ctxt->context->depth = oldDepth;
11564
11565
7.09k
    return(0);
11566
7.09k
}
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
413k
                                xmlXPathObject *res) {
11627
413k
    if ((ctxt == NULL) || (res == NULL)) return(0);
11628
413k
    switch (res->type) {
11629
0
        case XPATH_BOOLEAN:
11630
0
      return(res->boolval);
11631
43.3k
        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
43.3k
      return(res->floatval == ctxt->context->proximityPosition);
11637
0
#endif
11638
353k
        case XPATH_NODESET:
11639
353k
        case XPATH_XSLT_TREE:
11640
353k
      if (res->nodesetval == NULL)
11641
0
    return(0);
11642
353k
      return(res->nodesetval->nodeNr != 0);
11643
16.6k
        case XPATH_STRING:
11644
16.6k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11645
0
        default:
11646
0
      break;
11647
413k
    }
11648
0
    return(0);
11649
413k
}
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
2.08M
{
11741
2.08M
    xmlXPathCompExprPtr comp = pctxt->comp;
11742
2.08M
    xmlXPathContextPtr ctxt;
11743
11744
    /*
11745
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11746
    * internal representation.
11747
    */
11748
11749
2.08M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11750
616k
        (op->ch1 != -1) &&
11751
616k
        (op->ch2 == -1 /* no predicate */))
11752
610k
    {
11753
610k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11754
11755
610k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11756
57.1k
            ((xmlXPathAxisVal) prevop->value ==
11757
57.1k
                AXIS_DESCENDANT_OR_SELF) &&
11758
26.9k
            (prevop->ch2 == -1) &&
11759
26.9k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11760
26.9k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11761
26.9k
        {
11762
            /*
11763
            * This is a "descendant-or-self::node()" without predicates.
11764
            * Try to eliminate it.
11765
            */
11766
11767
26.9k
            switch ((xmlXPathAxisVal) op->value) {
11768
16.8k
                case AXIS_CHILD:
11769
16.8k
                case AXIS_DESCENDANT:
11770
                    /*
11771
                    * Convert "descendant-or-self::node()/child::" or
11772
                    * "descendant-or-self::node()/descendant::" to
11773
                    * "descendant::"
11774
                    */
11775
16.8k
                    op->ch1   = prevop->ch1;
11776
16.8k
                    op->value = AXIS_DESCENDANT;
11777
16.8k
                    break;
11778
0
                case AXIS_SELF:
11779
1.37k
                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
1.37k
                    op->ch1   = prevop->ch1;
11786
1.37k
                    op->value = AXIS_DESCENDANT_OR_SELF;
11787
1.37k
                    break;
11788
8.66k
                default:
11789
8.66k
                    break;
11790
26.9k
            }
11791
26.9k
  }
11792
610k
    }
11793
11794
    /* OP_VALUE has invalid ch1. */
11795
2.08M
    if (op->op == XPATH_OP_VALUE)
11796
99.0k
        return;
11797
11798
    /* Recurse */
11799
1.98M
    ctxt = pctxt->context;
11800
1.98M
    if (ctxt != NULL) {
11801
1.98M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11802
969
            return;
11803
1.98M
        ctxt->depth += 1;
11804
1.98M
    }
11805
1.98M
    if (op->ch1 != -1)
11806
1.38M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11807
1.98M
    if (op->ch2 != -1)
11808
698k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11809
1.98M
    if (ctxt != NULL)
11810
1.98M
        ctxt->depth -= 1;
11811
1.98M
}
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
8.68k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
12003
#ifdef XPATH_STREAMING
12004
    xmlXPathCompExprPtr comp;
12005
#endif
12006
8.68k
    int oldDepth = 0;
12007
12008
8.68k
    if ((ctxt == NULL) || (ctxt->context == NULL))
12009
0
        return;
12010
8.68k
    if (ctxt->context->lastError.code != 0)
12011
327
        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
8.36k
    {
12027
8.36k
        if (ctxt->context != NULL)
12028
8.36k
            oldDepth = ctxt->context->depth;
12029
8.36k
  xmlXPathCompileExpr(ctxt, 1);
12030
8.36k
        if (ctxt->context != NULL)
12031
8.36k
            ctxt->context->depth = oldDepth;
12032
8.36k
        CHECK_ERROR;
12033
12034
        /* Check for trailing characters. */
12035
7.21k
        if (*ctxt->cur != 0)
12036
7.09k
            XP_ERROR(XPATH_EXPR_ERROR);
12037
12038
7.09k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12039
7.05k
            if (ctxt->context != NULL)
12040
7.05k
                oldDepth = ctxt->context->depth;
12041
7.05k
      xmlXPathOptimizeExpression(ctxt,
12042
7.05k
    &ctxt->comp->steps[ctxt->comp->last]);
12043
7.05k
            if (ctxt->context != NULL)
12044
7.05k
                ctxt->context->depth = oldDepth;
12045
7.05k
        }
12046
7.09k
    }
12047
12048
0
    xmlXPathRunEval(ctxt, 0);
12049
7.09k
}
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 */