Coverage Report

Created: 2025-07-11 06:12

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
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
4.06k
#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.63k
#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
102k
#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
1.17M
#define XPATH_MAX_RECURSION_DEPTH 500
113
#elif defined(_WIN32)
114
/* Windows typically limits stack size to 1MB. */
115
#define XPATH_MAX_RECURSION_DEPTH 1000
116
#else
117
#define XPATH_MAX_RECURSION_DEPTH 5000
118
#endif
119
120
/*
121
 * TODO:
122
 * There are a few spots where some tests are done which depend upon ascii
123
 * data.  These should be enhanced for full UTF8 support (see particularly
124
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
125
 */
126
127
#if defined(LIBXML_XPATH_ENABLED)
128
129
static void
130
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
131
132
static const struct {
133
    const char *name;
134
    xmlXPathFunction func;
135
} xmlXPathStandardFunctions[] = {
136
    { "boolean", xmlXPathBooleanFunction },
137
    { "ceiling", xmlXPathCeilingFunction },
138
    { "count", xmlXPathCountFunction },
139
    { "concat", xmlXPathConcatFunction },
140
    { "contains", xmlXPathContainsFunction },
141
    { "id", xmlXPathIdFunction },
142
    { "false", xmlXPathFalseFunction },
143
    { "floor", xmlXPathFloorFunction },
144
    { "last", xmlXPathLastFunction },
145
    { "lang", xmlXPathLangFunction },
146
    { "local-name", xmlXPathLocalNameFunction },
147
    { "not", xmlXPathNotFunction },
148
    { "name", xmlXPathNameFunction },
149
    { "namespace-uri", xmlXPathNamespaceURIFunction },
150
    { "normalize-space", xmlXPathNormalizeFunction },
151
    { "number", xmlXPathNumberFunction },
152
    { "position", xmlXPathPositionFunction },
153
    { "round", xmlXPathRoundFunction },
154
    { "string", xmlXPathStringFunction },
155
    { "string-length", xmlXPathStringLengthFunction },
156
    { "starts-with", xmlXPathStartsWithFunction },
157
    { "substring", xmlXPathSubstringFunction },
158
    { "substring-before", xmlXPathSubstringBeforeFunction },
159
    { "substring-after", xmlXPathSubstringAfterFunction },
160
    { "sum", xmlXPathSumFunction },
161
    { "true", xmlXPathTrueFunction },
162
    { "translate", xmlXPathTranslateFunction }
163
};
164
165
#define NUM_STANDARD_FUNCTIONS \
166
56
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
652
#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
198
xmlXPathSFComputeHash(const xmlChar *name) {
187
198
    unsigned hashValue = 5381;
188
198
    const xmlChar *ptr;
189
190
1.45k
    for (ptr = name; *ptr; ptr++)
191
1.25k
        hashValue = hashValue * 33 + *ptr;
192
193
198
    return(hashValue);
194
198
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
2
xmlInitXPathInternal(void) {
202
2
    size_t i;
203
204
2
#if defined(NAN) && defined(INFINITY)
205
2
    xmlXPathNAN = NAN;
206
2
    xmlXPathPINF = INFINITY;
207
2
    xmlXPathNINF = -INFINITY;
208
#else
209
    /* MSVC doesn't allow division by zero in constant expressions. */
210
    double zero = 0.0;
211
    xmlXPathNAN = 0.0 / zero;
212
    xmlXPathPINF = 1.0 / zero;
213
    xmlXPathNINF = -xmlXPathPINF;
214
#endif
215
216
    /*
217
     * Initialize hash table for standard functions
218
     */
219
220
130
    for (i = 0; i < SF_HASH_SIZE; i++)
221
128
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
56
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
54
        const char *name = xmlXPathStandardFunctions[i].name;
225
54
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
68
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
14
            bucketIndex += 1;
229
14
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
14
        }
232
233
54
        xmlXPathSFHash[bucketIndex] = i;
234
54
    }
235
2
}
236
237
/************************************************************************
238
 *                  *
239
 *      Floating point stuff        *
240
 *                  *
241
 ************************************************************************/
242
243
/**
244
 * Checks whether a double is a NaN.
245
 *
246
 * @param val  a double value
247
 * @returns 1 if the value is a NaN, 0 otherwise
248
 */
249
int
250
15.9k
xmlXPathIsNaN(double val) {
251
15.9k
#ifdef isnan
252
15.9k
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
15.9k
}
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
1.25k
xmlXPathIsInf(double val) {
266
1.25k
#ifdef isinf
267
1.25k
    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
1.25k
}
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
98.4M
#define XML_NODE_SORT_VALUE(n) XML_PTR_TO_INT((n)->content)
296
297
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
298
299
/**
300
 * Compare two nodes w.r.t document order.
301
 * This one is optimized for handling of non-element nodes.
302
 *
303
 * @param node1  the first node
304
 * @param node2  the second node
305
 * @returns -2 in case of error 1 if first point < second point, 0 if
306
 *         it's the same node, -1 otherwise
307
 */
308
static int
309
23.3M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
23.3M
    int depth1, depth2;
311
23.3M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
23.3M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
23.3M
    xmlNodePtr cur, root;
314
23.3M
    XML_INTPTR_T l1, l2;
315
316
23.3M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
23.3M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
23.3M
    switch (node1->type) {
326
18.8M
  case XML_ELEMENT_NODE:
327
18.8M
      if (node2->type == XML_ELEMENT_NODE) {
328
13.9M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
13.9M
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
13.9M
        (node1->doc == node2->doc))
331
13.9M
    {
332
13.9M
        l1 = -XML_NODE_SORT_VALUE(node1);
333
13.9M
        l2 = -XML_NODE_SORT_VALUE(node2);
334
13.9M
        if (l1 < l2)
335
11.5M
      return(1);
336
2.32M
        if (l1 > l2)
337
2.32M
      return(-1);
338
2.32M
    } else
339
48
        goto turtle_comparison;
340
13.9M
      }
341
4.98M
      break;
342
4.98M
  case XML_ATTRIBUTE_NODE:
343
12.9k
      precedence1 = 1; /* element is owner */
344
12.9k
      miscNode1 = node1;
345
12.9k
      node1 = node1->parent;
346
12.9k
      misc = 1;
347
12.9k
      break;
348
4.37M
  case XML_TEXT_NODE:
349
4.41M
  case XML_CDATA_SECTION_NODE:
350
4.43M
  case XML_COMMENT_NODE:
351
4.46M
  case XML_PI_NODE: {
352
4.46M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
4.46M
      if (node1->prev != NULL) {
357
6.23M
    do {
358
6.23M
        node1 = node1->prev;
359
6.23M
        if (node1->type == XML_ELEMENT_NODE) {
360
3.93M
      precedence1 = 3; /* element in prev-sibl axis */
361
3.93M
      break;
362
3.93M
        }
363
2.29M
        if (node1->prev == NULL) {
364
17.2k
      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
17.2k
      node1 = node1->parent;
370
17.2k
      break;
371
17.2k
        }
372
2.29M
    } while (1);
373
3.95M
      } else {
374
513k
    precedence1 = 2; /* element is parent */
375
513k
    node1 = node1->parent;
376
513k
      }
377
4.46M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
4.46M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
90
    node1 = miscNode1;
383
90
    precedence1 = 0;
384
90
      } else
385
4.46M
    misc = 1;
386
4.46M
  }
387
0
      break;
388
10.4k
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
10.4k
      return(1);
393
2.74k
  default:
394
2.74k
      break;
395
23.3M
    }
396
9.46M
    switch (node2->type) {
397
3.40M
  case XML_ELEMENT_NODE:
398
3.40M
      break;
399
12.9k
  case XML_ATTRIBUTE_NODE:
400
12.9k
      precedence2 = 1; /* element is owner */
401
12.9k
      miscNode2 = node2;
402
12.9k
      node2 = node2->parent;
403
12.9k
      misc = 1;
404
12.9k
      break;
405
5.83M
  case XML_TEXT_NODE:
406
5.87M
  case XML_CDATA_SECTION_NODE:
407
5.90M
  case XML_COMMENT_NODE:
408
5.93M
  case XML_PI_NODE: {
409
5.93M
      miscNode2 = node2;
410
5.93M
      if (node2->prev != NULL) {
411
7.55M
    do {
412
7.55M
        node2 = node2->prev;
413
7.55M
        if (node2->type == XML_ELEMENT_NODE) {
414
5.25M
      precedence2 = 3; /* element in prev-sibl axis */
415
5.25M
      break;
416
5.25M
        }
417
2.29M
        if (node2->prev == NULL) {
418
15.8k
      precedence2 = 2; /* element is parent */
419
15.8k
      node2 = node2->parent;
420
15.8k
      break;
421
15.8k
        }
422
2.29M
    } while (1);
423
5.27M
      } else {
424
657k
    precedence2 = 2; /* element is parent */
425
657k
    node2 = node2->parent;
426
657k
      }
427
5.93M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
5.93M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
23
      {
430
23
    node2 = miscNode2;
431
23
    precedence2 = 0;
432
23
      } else
433
5.93M
    misc = 1;
434
5.93M
  }
435
0
      break;
436
959
  case XML_NAMESPACE_DECL:
437
959
      return(1);
438
121k
  default:
439
121k
      break;
440
9.46M
    }
441
9.46M
    if (misc) {
442
9.35M
  if (node1 == node2) {
443
1.09M
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
168k
    cur = miscNode2->prev;
449
170k
    while (cur != NULL) {
450
170k
        if (cur == miscNode1)
451
168k
      return(1);
452
2.28k
        if (cur->type == XML_ELEMENT_NODE)
453
304
      return(-1);
454
1.98k
        cur = cur->prev;
455
1.98k
    }
456
120
    return (-1);
457
930k
      } 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
930k
    if (precedence1 < precedence2)
464
741k
        return(1);
465
189k
    else
466
189k
        return(-1);
467
930k
      }
468
1.09M
  }
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
8.25M
  if ((precedence2 == 3) && (precedence1 > 1)) {
479
786k
      cur = node1->parent;
480
59.4M
      while (cur) {
481
58.7M
    if (cur == node2)
482
71.4k
        return(1);
483
58.6M
    cur = cur->parent;
484
58.6M
      }
485
786k
  }
486
8.18M
  if ((precedence1 == 3) && (precedence2 > 1)) {
487
709k
      cur = node2->parent;
488
52.5M
      while (cur) {
489
51.8M
    if (cur == node1)
490
58.9k
        return(-1);
491
51.8M
    cur = cur->parent;
492
51.8M
      }
493
709k
  }
494
8.18M
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
8.23M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
8.23M
  (node2->type == XML_ELEMENT_NODE) &&
501
8.23M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
8.23M
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
8.23M
  (node1->doc == node2->doc)) {
504
505
8.11M
  l1 = -XML_NODE_SORT_VALUE(node1);
506
8.11M
  l2 = -XML_NODE_SORT_VALUE(node2);
507
8.11M
  if (l1 < l2)
508
7.06M
      return(1);
509
1.04M
  if (l1 > l2)
510
1.04M
      return(-1);
511
1.04M
    }
512
513
124k
turtle_comparison:
514
515
124k
    if (node1 == node2->prev)
516
102
  return(1);
517
124k
    if (node1 == node2->next)
518
0
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
130k
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
9.43k
  if (cur->parent == node1)
524
2.74k
      return(1);
525
6.68k
  depth2++;
526
6.68k
    }
527
121k
    root = cur;
528
2.35M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
2.35M
  if (cur->parent == node2)
530
121k
      return(-1);
531
2.23M
  depth1++;
532
2.23M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
44
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
175
    while (depth1 > depth2) {
543
131
  depth1--;
544
131
  node1 = node1->parent;
545
131
    }
546
732
    while (depth2 > depth1) {
547
688
  depth2--;
548
688
  node2 = node2->parent;
549
688
    }
550
44
    while (node1->parent != node2->parent) {
551
0
  node1 = node1->parent;
552
0
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
0
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
0
    }
557
    /*
558
     * Find who's first.
559
     */
560
44
    if (node1 == node2->prev)
561
33
  return(1);
562
11
    if (node1 == node2->next)
563
11
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
0
    if ((node1->type == XML_ELEMENT_NODE) &&
568
0
  (node2->type == XML_ELEMENT_NODE) &&
569
0
  (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
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
0
  if (cur == node2)
583
0
      return(1);
584
0
    return(-1); /* assume there is no sibling list corruption */
585
0
}
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
1.93M
#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
23.3M
    {
607
23.3M
        int res = xmlXPathCmpNodesExt(x, y);
608
23.3M
        return res == -2 ? res : -res;
609
23.3M
    }
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
23.3M
#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
112
    { 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
1.42k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
1.42k
       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
63
{
678
63
    if (ctxt == NULL)
679
0
        return;
680
63
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
63
                        &ctxt->lastError);
682
63
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
63
{
692
63
    if (ctxt == NULL)
693
0
        return;
694
63
    ctxt->error = XPATH_MEMORY_ERROR;
695
63
    xmlXPathErrMemory(ctxt->context);
696
63
}
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
1.42k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
1.42k
    va_list ap;
709
1.42k
    xmlStructuredErrorFunc schannel = NULL;
710
1.42k
    xmlGenericErrorFunc channel = NULL;
711
1.42k
    void *data = NULL;
712
1.42k
    xmlNodePtr node = NULL;
713
1.42k
    int res;
714
715
1.42k
    if (ctxt == NULL)
716
0
        return;
717
1.42k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
1.42k
    if (ctxt->error != 0)
721
12
        return;
722
723
1.40k
    ctxt->error = code;
724
725
1.40k
    if (ctxt->context != NULL) {
726
1.40k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
1.40k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
1.40k
        xmlResetError(err);
734
735
1.40k
        err->domain = XML_FROM_XPATH;
736
1.40k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
1.40k
        err->level = XML_ERR_ERROR;
738
1.40k
        if (ctxt->base != NULL) {
739
1.15k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
1.15k
            if (err->str1 == NULL) {
741
0
                xmlXPathPErrMemory(ctxt);
742
0
                return;
743
0
            }
744
1.15k
        }
745
1.40k
        err->int1 = ctxt->cur - ctxt->base;
746
1.40k
        err->node = ctxt->context->debugNode;
747
748
1.40k
        schannel = ctxt->context->error;
749
1.40k
        data = ctxt->context->userData;
750
1.40k
        node = ctxt->context->debugNode;
751
1.40k
    }
752
753
1.40k
    if (schannel == NULL) {
754
1.40k
        channel = xmlGenericError;
755
1.40k
        data = xmlGenericErrorContext;
756
1.40k
    }
757
758
1.40k
    va_start(ap, fmt);
759
1.40k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
1.40k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
1.40k
                         XML_ERR_ERROR, NULL, 0,
762
1.40k
                         (const char *) ctxt->base, NULL, NULL,
763
1.40k
                         ctxt->cur - ctxt->base, 0,
764
1.40k
                         fmt, ap);
765
1.40k
    va_end(ap);
766
1.40k
    if (res < 0)
767
0
        xmlXPathPErrMemory(ctxt);
768
1.40k
}
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
1.32k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
1.32k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
1.32k
}
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
612
              int line ATTRIBUTE_UNUSED, int no) {
792
612
    xmlXPathErr(ctxt, no);
793
612
}
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
16.0M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
16.0M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
16.0M
    if ((opCount > xpctxt->opLimit) ||
807
16.0M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
29
        xpctxt->opCount = xpctxt->opLimit;
809
29
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
29
        return(-1);
811
29
    }
812
813
16.0M
    xpctxt->opCount += opCount;
814
16.0M
    return(0);
815
16.0M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
16.0M
    ((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
1.61k
xmlXPathNewCompExpr(void) {
941
1.61k
    xmlXPathCompExprPtr cur;
942
943
1.61k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
1.61k
    if (cur == NULL)
945
0
  return(NULL);
946
1.61k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
1.61k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
1.61k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
1.61k
    cur->nbStep = 0;
953
1.61k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
1.61k
                                     sizeof(xmlXPathStepOp));
955
1.61k
    if (cur->steps == NULL) {
956
0
  xmlFree(cur);
957
0
  return(NULL);
958
0
    }
959
1.61k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
1.61k
    cur->last = -1;
961
1.61k
    return(cur);
962
1.61k
}
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
1.61k
{
972
1.61k
    xmlXPathStepOpPtr op;
973
1.61k
    int i;
974
975
1.61k
    if (comp == NULL)
976
0
        return;
977
1.61k
    if (comp->dict == NULL) {
978
1.14M
  for (i = 0; i < comp->nbStep; i++) {
979
1.14M
      op = &comp->steps[i];
980
1.14M
      if (op->value4 != NULL) {
981
658
    if (op->op == XPATH_OP_VALUE)
982
311
        xmlXPathFreeObject(op->value4);
983
347
    else
984
347
        xmlFree(op->value4);
985
658
      }
986
1.14M
      if (op->value5 != NULL)
987
284k
    xmlFree(op->value5);
988
1.14M
  }
989
1.61k
    } 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
1.61k
    if (comp->steps != NULL) {
1000
1.61k
        xmlFree(comp->steps);
1001
1.61k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
1.61k
    if (comp->expr != NULL) {
1008
151
        xmlFree(comp->expr);
1009
151
    }
1010
1011
1.61k
    xmlFree(comp);
1012
1.61k
}
1013
1014
/**
1015
 * Add a step to an XPath Compiled Expression
1016
 *
1017
 * @param ctxt  XPath parser context
1018
 * @param ch1  first child index
1019
 * @param ch2  second child index
1020
 * @param op  an op
1021
 * @param value  the first int value
1022
 * @param value2  the second int value
1023
 * @param value3  the third int value
1024
 * @param value4  the first string value
1025
 * @param value5  the second string value
1026
 * @returns -1 in case of failure, the index otherwise
1027
 */
1028
static int
1029
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1030
   xmlXPathOp op, int value,
1031
1.14M
   int value2, int value3, void *value4, void *value5) {
1032
1.14M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
1.14M
    if (comp->nbStep >= comp->maxStep) {
1034
4.06k
  xmlXPathStepOp *real;
1035
4.06k
        int newSize;
1036
1037
4.06k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
4.06k
                                  10, XPATH_MAX_STEPS);
1039
4.06k
        if (newSize < 0) {
1040
0
      xmlXPathPErrMemory(ctxt);
1041
0
      return(-1);
1042
0
        }
1043
4.06k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
4.06k
  if (real == NULL) {
1045
0
      xmlXPathPErrMemory(ctxt);
1046
0
      return(-1);
1047
0
  }
1048
4.06k
  comp->steps = real;
1049
4.06k
  comp->maxStep = newSize;
1050
4.06k
    }
1051
1.14M
    comp->last = comp->nbStep;
1052
1.14M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
1.14M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
1.14M
    comp->steps[comp->nbStep].op = op;
1055
1.14M
    comp->steps[comp->nbStep].value = value;
1056
1.14M
    comp->steps[comp->nbStep].value2 = value2;
1057
1.14M
    comp->steps[comp->nbStep].value3 = value3;
1058
1.14M
    if ((comp->dict != NULL) &&
1059
1.14M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
0
   (op == XPATH_OP_COLLECT))) {
1061
0
        if (value4 != NULL) {
1062
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
0
      xmlFree(value4);
1065
0
  } else
1066
0
      comp->steps[comp->nbStep].value4 = NULL;
1067
0
        if (value5 != NULL) {
1068
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
0
      xmlFree(value5);
1071
0
  } else
1072
0
      comp->steps[comp->nbStep].value5 = NULL;
1073
1.14M
    } else {
1074
1.14M
  comp->steps[comp->nbStep].value4 = value4;
1075
1.14M
  comp->steps[comp->nbStep].value5 = value5;
1076
1.14M
    }
1077
1.14M
    comp->steps[comp->nbStep].cache = NULL;
1078
1.14M
    return(comp->nbStep++);
1079
1.14M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
285k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
285k
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
1.05k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
1.05k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
569k
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
569k
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
1.34k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
1.34k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
284k
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
284k
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
284k
      (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
302
{
1516
302
    xmlXPathContextCachePtr ret;
1517
1518
302
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
302
    if (ret == NULL)
1520
0
  return(NULL);
1521
302
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
302
    ret->maxNodeset = 100;
1523
302
    ret->maxMisc = 100;
1524
302
    return(ret);
1525
302
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
378
{
1530
7.34k
    while (list != NULL) {
1531
6.96k
        xmlXPathObjectPtr next;
1532
1533
6.96k
        next = (void *) list->stringval;
1534
1535
6.96k
  if (list->nodesetval != NULL) {
1536
4.54k
      if (list->nodesetval->nodeTab != NULL)
1537
4.37k
    xmlFree(list->nodesetval->nodeTab);
1538
4.54k
      xmlFree(list->nodesetval);
1539
4.54k
  }
1540
6.96k
  xmlFree(list);
1541
1542
6.96k
        list = next;
1543
6.96k
    }
1544
378
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
300
{
1549
300
    if (cache == NULL)
1550
0
  return;
1551
300
    if (cache->nodesetObjs)
1552
300
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
300
    if (cache->miscObjs)
1554
78
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
300
    xmlFree(cache);
1556
300
}
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
302
{
1582
302
    if (ctxt == NULL)
1583
0
  return(-1);
1584
302
    if (active) {
1585
302
  xmlXPathContextCachePtr cache;
1586
1587
302
  if (ctxt->cache == NULL) {
1588
302
      ctxt->cache = xmlXPathNewCache();
1589
302
      if (ctxt->cache == NULL) {
1590
0
                xmlXPathErrMemory(ctxt);
1591
0
    return(-1);
1592
0
            }
1593
302
  }
1594
302
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
302
  if (options == 0) {
1596
302
      if (value < 0)
1597
302
    value = 100;
1598
302
      cache->maxNodeset = value;
1599
302
      cache->maxMisc = value;
1600
302
  }
1601
302
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
302
    return(0);
1606
302
}
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
31.6k
{
1621
31.6k
    xmlXPathObjectPtr ret;
1622
31.6k
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
31.6k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
31.6k
  xmlXPathContextCachePtr cache =
1626
31.6k
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
31.6k
  if (cache->miscObjs != NULL) {
1629
28.3k
      ret = cache->miscObjs;
1630
28.3k
            cache->miscObjs = (void *) ret->stringval;
1631
28.3k
            cache->numMisc -= 1;
1632
28.3k
            ret->stringval = NULL;
1633
28.3k
      ret->type = XPATH_NODESET;
1634
28.3k
      ret->nodesetval = val;
1635
28.3k
      return(ret);
1636
28.3k
  }
1637
31.6k
    }
1638
1639
3.27k
    ret = xmlXPathWrapNodeSet(val);
1640
3.27k
    if (ret == NULL)
1641
0
        xmlXPathPErrMemory(pctxt);
1642
3.27k
    return(ret);
1643
31.6k
}
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
961k
{
1656
961k
    xmlXPathObjectPtr ret;
1657
961k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
961k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
961k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
961k
  if (cache->miscObjs != NULL) {
1663
959k
      ret = cache->miscObjs;
1664
959k
            cache->miscObjs = (void *) ret->stringval;
1665
959k
            cache->numMisc -= 1;
1666
959k
      ret->type = XPATH_STRING;
1667
959k
      ret->stringval = val;
1668
959k
      return(ret);
1669
959k
  }
1670
961k
    }
1671
1672
1.88k
    ret = xmlXPathWrapString(val);
1673
1.88k
    if (ret == NULL)
1674
0
        xmlXPathPErrMemory(pctxt);
1675
1.88k
    return(ret);
1676
961k
}
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
34.0k
{
1690
34.0k
    xmlXPathObjectPtr ret;
1691
34.0k
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
34.0k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
34.0k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
34.0k
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
33.7k
      ret = cache->nodesetObjs;
1701
33.7k
            cache->nodesetObjs = (void *) ret->stringval;
1702
33.7k
            cache->numNodeset -= 1;
1703
33.7k
            ret->stringval = NULL;
1704
33.7k
      ret->type = XPATH_NODESET;
1705
33.7k
      ret->boolval = 0;
1706
33.7k
      if (val) {
1707
33.7k
    if ((ret->nodesetval->nodeMax == 0) ||
1708
33.7k
        (val->type == XML_NAMESPACE_DECL))
1709
2.27k
    {
1710
2.27k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
2
                        xmlXPathPErrMemory(pctxt);
1712
31.4k
    } else {
1713
31.4k
        ret->nodesetval->nodeTab[0] = val;
1714
31.4k
        ret->nodesetval->nodeNr = 1;
1715
31.4k
    }
1716
33.7k
      }
1717
33.7k
      return(ret);
1718
33.7k
  } else if (cache->miscObjs != NULL) {
1719
7
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
7
      set = xmlXPathNodeSetCreate(val);
1725
7
      if (set == NULL) {
1726
0
                xmlXPathPErrMemory(pctxt);
1727
0
    return(NULL);
1728
0
      }
1729
1730
7
      ret = cache->miscObjs;
1731
7
            cache->miscObjs = (void *) ret->stringval;
1732
7
            cache->numMisc -= 1;
1733
7
            ret->stringval = NULL;
1734
7
      ret->type = XPATH_NODESET;
1735
7
      ret->boolval = 0;
1736
7
      ret->nodesetval = set;
1737
7
      return(ret);
1738
7
  }
1739
34.0k
    }
1740
310
    ret = xmlXPathNewNodeSet(val);
1741
310
    if (ret == NULL)
1742
0
        xmlXPathPErrMemory(pctxt);
1743
310
    return(ret);
1744
34.0k
}
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
710
{
1757
710
    xmlXPathObjectPtr ret;
1758
710
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
710
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
710
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
710
  if (cache->miscObjs != NULL) {
1764
541
            xmlChar *copy;
1765
1766
541
            if (val == NULL)
1767
0
                val = BAD_CAST "";
1768
541
            copy = xmlStrdup(val);
1769
541
            if (copy == NULL) {
1770
0
                xmlXPathPErrMemory(pctxt);
1771
0
                return(NULL);
1772
0
            }
1773
1774
541
      ret = cache->miscObjs;
1775
541
            cache->miscObjs = (void *) ret->stringval;
1776
541
            cache->numMisc -= 1;
1777
541
      ret->type = XPATH_STRING;
1778
541
            ret->stringval = copy;
1779
541
      return(ret);
1780
541
  }
1781
710
    }
1782
1783
169
    ret = xmlXPathNewString(val);
1784
169
    if (ret == NULL)
1785
0
        xmlXPathPErrMemory(pctxt);
1786
169
    return(ret);
1787
710
}
1788
1789
/**
1790
 * This is the cached version of #xmlXPathNewCString.
1791
 * Acquire an xmlXPathObject of type string and of value `val`
1792
 *
1793
 * @param pctxt  the XPath context
1794
 * @param val  the char * value
1795
 * @returns the created or reused object.
1796
 */
1797
static xmlXPathObjectPtr
1798
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1799
0
{
1800
0
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
0
}
1802
1803
/**
1804
 * This is the cached version of #xmlXPathNewBoolean.
1805
 * Acquires an xmlXPathObject of type boolean and of value `val`
1806
 *
1807
 * @param pctxt  the XPath context
1808
 * @param val  the boolean value
1809
 * @returns the created or reused object.
1810
 */
1811
static xmlXPathObjectPtr
1812
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1813
1.62k
{
1814
1.62k
    xmlXPathObjectPtr ret;
1815
1.62k
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
1.62k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
1.62k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
1.62k
  if (cache->miscObjs != NULL) {
1821
783
      ret = cache->miscObjs;
1822
783
            cache->miscObjs = (void *) ret->stringval;
1823
783
            cache->numMisc -= 1;
1824
783
            ret->stringval = NULL;
1825
783
      ret->type = XPATH_BOOLEAN;
1826
783
      ret->boolval = (val != 0);
1827
783
      return(ret);
1828
783
  }
1829
1.62k
    }
1830
1831
841
    ret = xmlXPathNewBoolean(val);
1832
841
    if (ret == NULL)
1833
0
        xmlXPathPErrMemory(pctxt);
1834
841
    return(ret);
1835
1.62k
}
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
303k
{
1848
303k
    xmlXPathObjectPtr ret;
1849
303k
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
303k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
303k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
303k
  if (cache->miscObjs != NULL) {
1855
303k
      ret = cache->miscObjs;
1856
303k
            cache->miscObjs = (void *) ret->stringval;
1857
303k
            cache->numMisc -= 1;
1858
303k
            ret->stringval = NULL;
1859
303k
      ret->type = XPATH_NUMBER;
1860
303k
      ret->floatval = val;
1861
303k
      return(ret);
1862
303k
  }
1863
303k
    }
1864
1865
337
    ret = xmlXPathNewFloat(val);
1866
337
    if (ret == NULL)
1867
0
        xmlXPathPErrMemory(pctxt);
1868
337
    return(ret);
1869
303k
}
1870
1871
/**
1872
 * This is the cached version of #xmlXPathObjectCopy.
1873
 * Acquire a copy of a given object
1874
 *
1875
 * @param pctxt  the XPath context
1876
 * @param val  the original object
1877
 * @returns a created or reused created object.
1878
 */
1879
static xmlXPathObjectPtr
1880
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1881
1.42k
{
1882
1.42k
    xmlXPathObjectPtr ret;
1883
1.42k
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
1.42k
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
1.42k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
1.42k
  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
539
      case XPATH_STRING:
1901
539
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
881
      case XPATH_NUMBER:
1905
881
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
1.42k
  }
1909
1.42k
    }
1910
0
    ret = xmlXPathObjectCopy(val);
1911
0
    if (ret == NULL)
1912
0
        xmlXPathPErrMemory(pctxt);
1913
0
    return(ret);
1914
1.42k
}
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
303k
                             xmlXPathObjectPtr val) {
1932
303k
    double ret = 0.0;
1933
1934
303k
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
303k
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
889
    case XPATH_NODESET:
1941
889
    case XPATH_XSLT_TREE: {
1942
889
        xmlChar *str;
1943
1944
889
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
889
        if (str == NULL) {
1946
0
            xmlXPathPErrMemory(ctxt);
1947
0
            ret = xmlXPathNAN;
1948
889
        } else {
1949
889
      ret = xmlXPathCastStringToNumber(str);
1950
889
            xmlFree(str);
1951
889
        }
1952
889
  break;
1953
889
    }
1954
302k
    case XPATH_STRING:
1955
302k
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
302k
  break;
1957
228
    case XPATH_NUMBER:
1958
228
  ret = val->floatval;
1959
228
  break;
1960
364
    case XPATH_BOOLEAN:
1961
364
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
364
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
303k
    }
1968
303k
    return(ret);
1969
303k
}
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
5.52M
{
1980
5.52M
    xmlXPathObjectPtr ret;
1981
1982
5.52M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
7
        return (NULL);
1984
1985
5.52M
    ctxt->valueNr--;
1986
5.52M
    if (ctxt->valueNr > 0)
1987
1.51M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
4.01M
    else
1989
4.01M
        ctxt->value = NULL;
1990
5.52M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
5.52M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
5.52M
    return (ret);
1993
5.52M
}
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
5.52M
{
2008
5.52M
    if (ctxt == NULL) return(-1);
2009
5.52M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
30
        xmlXPathPErrMemory(ctxt);
2014
30
        return(-1);
2015
30
    }
2016
5.52M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
1.63k
        xmlXPathObjectPtr *tmp;
2018
1.63k
        int newSize;
2019
2020
1.63k
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
1.63k
                                  10, XPATH_MAX_STACK_DEPTH);
2022
1.63k
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
1.63k
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
1.63k
        if (tmp == NULL) {
2029
6
            xmlXPathPErrMemory(ctxt);
2030
6
            xmlXPathFreeObject(value);
2031
6
            return (-1);
2032
6
        }
2033
1.62k
  ctxt->valueTab = tmp;
2034
1.62k
        ctxt->valueMax = newSize;
2035
1.62k
    }
2036
5.52M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
5.52M
    ctxt->value = value;
2038
5.52M
    return (ctxt->valueNr++);
2039
5.52M
}
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
478
xmlXPathPopNumber (xmlXPathParserContext *ctxt) {
2075
478
    xmlXPathObjectPtr obj;
2076
478
    double ret;
2077
2078
478
    obj = xmlXPathValuePop(ctxt);
2079
478
    if (obj == NULL) {
2080
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2081
0
  return(0);
2082
0
    }
2083
478
    if (obj->type != XPATH_NUMBER)
2084
252
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2085
226
    else
2086
226
        ret = obj->floatval;
2087
478
    xmlXPathReleaseObject(ctxt->context, obj);
2088
478
    return(ret);
2089
478
}
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
5.58k
xmlXPathPopString (xmlXPathParserContext *ctxt) {
2100
5.58k
    xmlXPathObjectPtr obj;
2101
5.58k
    xmlChar * ret;
2102
2103
5.58k
    obj = xmlXPathValuePop(ctxt);
2104
5.58k
    if (obj == NULL) {
2105
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2106
0
  return(NULL);
2107
0
    }
2108
5.58k
    ret = xmlXPathCastToString(obj);
2109
5.58k
    if (ret == NULL)
2110
0
        xmlXPathPErrMemory(ctxt);
2111
5.58k
    xmlXPathReleaseObject(ctxt->context, obj);
2112
5.58k
    return(ret);
2113
5.58k
}
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
21.5k
xmlXPathPopNodeSet (xmlXPathParserContext *ctxt) {
2124
21.5k
    xmlXPathObjectPtr obj;
2125
21.5k
    xmlNodeSetPtr ret;
2126
2127
21.5k
    if (ctxt == NULL) return(NULL);
2128
21.5k
    if (ctxt->value == NULL) {
2129
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130
0
  return(NULL);
2131
0
    }
2132
21.5k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2133
80
  xmlXPathSetTypeError(ctxt);
2134
80
  return(NULL);
2135
80
    }
2136
21.4k
    obj = xmlXPathValuePop(ctxt);
2137
21.4k
    ret = obj->nodesetval;
2138
21.4k
    obj->nodesetval = NULL;
2139
21.4k
    xmlXPathReleaseObject(ctxt->context, obj);
2140
21.4k
    return(ret);
2141
21.5k
}
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
6.12M
#define CUR (*ctxt->cur)
2194
934
#define SKIP(val) ctxt->cur += (val)
2195
2.55M
#define NXT(val) ctxt->cur[(val)]
2196
78.1k
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
3.44M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
1.74M
#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
44
#define UPPER_DOUBLE 1E9
2213
44
#define LOWER_DOUBLE 1E-5
2214
#define LOWER_DOUBLE_EXP 5
2215
2216
#define INTEGER_DIGITS DBL_DIG
2217
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2218
0
#define EXPONENT_DIGITS (3 + 2)
2219
2220
/**
2221
 * Convert the number into a string representation.
2222
 *
2223
 * @param number  number to format
2224
 * @param buffer  output buffer
2225
 * @param buffersize  size of output buffer
2226
 */
2227
static void
2228
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2229
404
{
2230
404
    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
404
    default:
2240
404
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
404
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
404
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
404
                   (number == (int) number)) {
2248
360
      char work[30];
2249
360
      char *ptr, *cur;
2250
360
      int value = (int) number;
2251
2252
360
            ptr = &buffer[0];
2253
360
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
360
      } else {
2256
360
    snprintf(work, 29, "%d", value);
2257
360
    cur = &work[0];
2258
720
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
360
        *ptr++ = *cur++;
2260
360
    }
2261
360
      }
2262
360
      if (ptr - buffer < buffersize) {
2263
360
    *ptr = 0;
2264
360
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
360
  } 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
44
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
44
      int integer_place, fraction_place;
2280
44
      char *ptr;
2281
44
      char *after_fraction;
2282
44
      double absolute_value;
2283
44
      int size;
2284
2285
44
      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
44
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
44
      (absolute_value < LOWER_DOUBLE)) &&
2294
44
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
0
    fraction_place = DBL_DIG - 1;
2298
0
    size = snprintf(work, sizeof(work),"%*.*e",
2299
0
       integer_place, fraction_place, number);
2300
0
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
0
      }
2303
44
      else {
2304
    /* Use regular notation */
2305
44
    if (absolute_value > 0.0) {
2306
44
        integer_place = (int)log10(absolute_value);
2307
44
        if (integer_place > 0)
2308
0
            fraction_place = DBL_DIG - integer_place - 1;
2309
44
        else
2310
44
            fraction_place = DBL_DIG - integer_place;
2311
44
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
44
    size = snprintf(work, sizeof(work), "%0.*f",
2315
44
        fraction_place, number);
2316
44
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
44
      while (work[0] == ' ') {
2320
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
0
    size--;
2322
0
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
44
      after_fraction = work + size;
2326
44
      ptr = after_fraction;
2327
660
      while (*(--ptr) == '0')
2328
616
    ;
2329
44
      if (*ptr != '.')
2330
44
          ptr++;
2331
44
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
44
      size = strlen(work) + 1;
2335
44
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
44
      memmove(buffer, work, size);
2340
44
  }
2341
404
  break;
2342
404
    }
2343
404
}
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
300
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
300
    XML_INTPTR_T count = 0;
2366
300
    xmlNodePtr cur;
2367
2368
300
    if (doc == NULL)
2369
0
  return(-1);
2370
300
    cur = doc->children;
2371
2.82M
    while (cur != NULL) {
2372
2.82M
  if (cur->type == XML_ELEMENT_NODE) {
2373
2.49M
            count += 1;
2374
2.49M
            cur->content = XML_INT_TO_PTR(-count);
2375
2.49M
      if (cur->children != NULL) {
2376
41.4k
    cur = cur->children;
2377
41.4k
    continue;
2378
41.4k
      }
2379
2.49M
  }
2380
2.78M
  if (cur->next != NULL) {
2381
2.75M
      cur = cur->next;
2382
2.75M
      continue;
2383
2.75M
  }
2384
41.7k
  do {
2385
41.7k
      cur = cur->parent;
2386
41.7k
      if (cur == NULL)
2387
0
    break;
2388
41.7k
      if (cur == (xmlNodePtr) doc) {
2389
299
    cur = NULL;
2390
299
    break;
2391
299
      }
2392
41.4k
      if (cur->next != NULL) {
2393
27.8k
    cur = cur->next;
2394
27.8k
    break;
2395
27.8k
      }
2396
41.4k
  } while (cur != NULL);
2397
28.1k
    }
2398
300
    return(count);
2399
300
}
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
8.27k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
8.27k
    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
8.27k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
8.27k
#endif /* WITH_TIM_SORT */
2591
8.27k
}
2592
2593
5.86M
#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
227k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
227k
    xmlNsPtr cur;
2606
2607
227k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
227k
    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
227k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
227k
    if (cur == NULL)
2617
0
  return(NULL);
2618
227k
    memset(cur, 0, sizeof(xmlNs));
2619
227k
    cur->type = XML_NAMESPACE_DECL;
2620
227k
    if (ns->href != NULL) {
2621
227k
  cur->href = xmlStrdup(ns->href);
2622
227k
        if (cur->href == NULL) {
2623
0
            xmlFree(cur);
2624
0
            return(NULL);
2625
0
        }
2626
227k
    }
2627
227k
    if (ns->prefix != NULL) {
2628
227k
  cur->prefix = xmlStrdup(ns->prefix);
2629
227k
        if (cur->prefix == NULL) {
2630
0
            xmlFree((xmlChar *) cur->href);
2631
0
            xmlFree(cur);
2632
0
            return(NULL);
2633
0
        }
2634
227k
    }
2635
227k
    cur->next = (xmlNsPtr) node;
2636
227k
    return((xmlNodePtr) cur);
2637
227k
}
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
227k
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
227k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
227k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
227k
  if (ns->href != NULL)
2653
227k
      xmlFree((xmlChar *)ns->href);
2654
227k
  if (ns->prefix != NULL)
2655
227k
      xmlFree((xmlChar *)ns->prefix);
2656
227k
  xmlFree(ns);
2657
227k
    }
2658
227k
}
2659
2660
/**
2661
 * Create a new xmlNodeSet of type double and of value `val`
2662
 *
2663
 * @param val  an initial xmlNode, or NULL
2664
 * @returns the newly created object.
2665
 */
2666
xmlNodeSet *
2667
2.91M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
2.91M
    xmlNodeSetPtr ret;
2669
2670
2.91M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
2.91M
    if (ret == NULL)
2672
4
  return(NULL);
2673
2.91M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
2.91M
    if (val != NULL) {
2675
1.91M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
1.91M
               sizeof(xmlNodePtr));
2677
1.91M
  if (ret->nodeTab == NULL) {
2678
1
      xmlFree(ret);
2679
1
      return(NULL);
2680
1
  }
2681
1.91M
  memset(ret->nodeTab, 0 ,
2682
1.91M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
1.91M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
1.91M
  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
1.91M
      ret->nodeTab[ret->nodeNr++] = val;
2695
1.91M
    }
2696
2.91M
    return(ret);
2697
2.91M
}
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
28
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
28
    int i;
2709
2710
28
    if ((cur == NULL) || (val == NULL)) return(0);
2711
28
    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
28
    } else {
2726
477
  for (i = 0; i < cur->nodeNr; i++) {
2727
477
      if (cur->nodeTab[i] == val)
2728
28
    return(1);
2729
477
  }
2730
28
    }
2731
0
    return(0);
2732
28
}
2733
2734
static int
2735
102k
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
102k
    xmlNodePtr *temp;
2737
102k
    int newSize;
2738
2739
102k
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
102k
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
102k
    if (newSize < 0)
2742
0
        return(-1);
2743
102k
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
102k
    if (temp == NULL)
2745
2
        return(-1);
2746
102k
    cur->nodeMax = newSize;
2747
102k
    cur->nodeTab = temp;
2748
2749
102k
    return(0);
2750
102k
}
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
215k
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
215k
    int i;
2763
215k
    xmlNodePtr nsNode;
2764
2765
215k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
215k
        (ns->type != XML_NAMESPACE_DECL) ||
2767
215k
  (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
533k
    for (i = 0;i < cur->nodeNr;i++) {
2775
317k
        if ((cur->nodeTab[i] != NULL) &&
2776
317k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
317k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
317k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
317k
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
215k
    if (cur->nodeNr >= cur->nodeMax) {
2786
1.48k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
0
            return(-1);
2788
1.48k
    }
2789
215k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
215k
    if(nsNode == NULL)
2791
0
        return(-1);
2792
215k
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
215k
    return(0);
2794
215k
}
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
1.62k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
1.62k
    int i;
2806
2807
1.62k
    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
1.31M
    for (i = 0;i < cur->nodeNr;i++)
2814
1.31M
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
1.62k
    if (cur->nodeNr >= cur->nodeMax) {
2820
25
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
0
            return(-1);
2822
25
    }
2823
2824
1.62k
    if (val->type == XML_NAMESPACE_DECL) {
2825
1.62k
  xmlNsPtr ns = (xmlNsPtr) val;
2826
1.62k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828
1.62k
        if (nsNode == NULL)
2829
0
            return(-1);
2830
1.62k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2831
1.62k
    } else
2832
6
  cur->nodeTab[cur->nodeNr++] = val;
2833
1.62k
    return(0);
2834
1.62k
}
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
13.6M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
13.6M
    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
13.6M
    if (cur->nodeNr >= cur->nodeMax) {
2853
84.9k
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
2
            return(-1);
2855
84.9k
    }
2856
2857
13.6M
    if (val->type == XML_NAMESPACE_DECL) {
2858
5.52k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
5.52k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
5.52k
        if (nsNode == NULL)
2862
0
            return(-1);
2863
5.52k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
5.52k
    } else
2865
13.6M
  cur->nodeTab[cur->nodeNr++] = val;
2866
13.6M
    return(0);
2867
13.6M
}
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
960k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
960k
    int i, j, initNr, skip;
2882
960k
    xmlNodePtr n1, n2;
2883
2884
960k
    if (val1 == NULL) {
2885
535
  val1 = xmlXPathNodeSetCreate(NULL);
2886
535
        if (val1 == NULL)
2887
0
            return (NULL);
2888
535
    }
2889
960k
    if (val2 == NULL)
2890
0
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
960k
    initNr = val1->nodeNr;
2894
2895
2.91M
    for (i = 0;i < val2->nodeNr;i++) {
2896
1.94M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
1.94M
  skip = 0;
2901
67.6M
  for (j = 0; j < initNr; j++) {
2902
65.6M
      n1 = val1->nodeTab[j];
2903
65.6M
      if (n1 == n2) {
2904
4
    skip = 1;
2905
4
    break;
2906
65.6M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
65.6M
           (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
65.6M
  }
2917
1.94M
  if (skip)
2918
4
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
1.94M
        if (val1->nodeNr >= val1->nodeMax) {
2924
1.65k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
0
                goto error;
2926
1.65k
        }
2927
1.94M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
5.09k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
5.09k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
5.09k
            if (nsNode == NULL)
2932
0
                goto error;
2933
5.09k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
5.09k
  } else
2935
1.94M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
1.94M
    }
2937
2938
960k
    return(val1);
2939
2940
0
error:
2941
0
    xmlXPathFreeNodeSet(val1);
2942
0
    return(NULL);
2943
960k
}
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
454k
{
2959
454k
    {
2960
454k
  int i, j, initNbSet1;
2961
454k
  xmlNodePtr n1, n2;
2962
2963
454k
  initNbSet1 = set1->nodeNr;
2964
914k
  for (i = 0;i < set2->nodeNr;i++) {
2965
459k
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
11.0M
      for (j = 0; j < initNbSet1; j++) {
2970
10.9M
    n1 = set1->nodeTab[j];
2971
10.9M
    if (n1 == n2) {
2972
375k
        goto skip_node;
2973
10.6M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
10.6M
        (n2->type == XML_NAMESPACE_DECL))
2975
113k
    {
2976
113k
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
113k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
4.01k
      ((xmlNsPtr) n2)->prefix)))
2979
1.53k
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
1.53k
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
1.53k
      goto skip_node;
2985
1.53k
        }
2986
113k
    }
2987
10.9M
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
83.0k
            if (set1->nodeNr >= set1->nodeMax) {
2992
12.8k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
0
                    goto error;
2994
12.8k
            }
2995
83.0k
      set1->nodeTab[set1->nodeNr++] = n2;
2996
459k
skip_node:
2997
459k
            set2->nodeTab[i] = NULL;
2998
459k
  }
2999
454k
    }
3000
454k
    set2->nodeNr = 0;
3001
454k
    return(set1);
3002
3003
0
error:
3004
0
    xmlXPathFreeNodeSet(set1);
3005
0
    xmlXPathNodeSetClear(set2, 1);
3006
0
    return(NULL);
3007
454k
}
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
57.2k
{
3022
57.2k
    {
3023
57.2k
  int i;
3024
57.2k
  xmlNodePtr n2;
3025
3026
735k
  for (i = 0;i < set2->nodeNr;i++) {
3027
678k
      n2 = set2->nodeTab[i];
3028
678k
            if (set1->nodeNr >= set1->nodeMax) {
3029
1.83k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
0
                    goto error;
3031
1.83k
            }
3032
678k
      set1->nodeTab[set1->nodeNr++] = n2;
3033
678k
            set2->nodeTab[i] = NULL;
3034
678k
  }
3035
57.2k
    }
3036
57.2k
    set2->nodeNr = 0;
3037
57.2k
    return(set1);
3038
3039
0
error:
3040
0
    xmlXPathFreeNodeSet(set1);
3041
0
    xmlXPathNodeSetClear(set2, 1);
3042
0
    return(NULL);
3043
57.2k
}
3044
3045
/**
3046
 * Removes an xmlNode from an existing NodeSet
3047
 *
3048
 * @param cur  the initial node set
3049
 * @param val  an xmlNode
3050
 */
3051
void
3052
0
xmlXPathNodeSetDel(xmlNodeSet *cur, xmlNode *val) {
3053
0
    int i;
3054
3055
0
    if (cur == NULL) return;
3056
0
    if (val == NULL) return;
3057
3058
    /*
3059
     * find node in nodeTab
3060
     */
3061
0
    for (i = 0;i < cur->nodeNr;i++)
3062
0
        if (cur->nodeTab[i] == val) break;
3063
3064
0
    if (i >= cur->nodeNr) { /* not found */
3065
0
        return;
3066
0
    }
3067
0
    if ((cur->nodeTab[i] != NULL) &&
3068
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3069
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3070
0
    cur->nodeNr--;
3071
0
    for (;i < cur->nodeNr;i++)
3072
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3073
0
    cur->nodeTab[cur->nodeNr] = NULL;
3074
0
}
3075
3076
/**
3077
 * Removes an entry from an existing NodeSet list.
3078
 *
3079
 * @param cur  the initial node set
3080
 * @param val  the index to remove
3081
 */
3082
void
3083
0
xmlXPathNodeSetRemove(xmlNodeSet *cur, int val) {
3084
0
    if (cur == NULL) return;
3085
0
    if (val >= cur->nodeNr) return;
3086
0
    if ((cur->nodeTab[val] != NULL) &&
3087
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3088
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3089
0
    cur->nodeNr--;
3090
0
    for (;val < cur->nodeNr;val++)
3091
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3092
0
    cur->nodeTab[cur->nodeNr] = NULL;
3093
0
}
3094
3095
/**
3096
 * Free the NodeSet compound (not the actual nodes !).
3097
 *
3098
 * @param obj  the xmlNodeSet to free
3099
 */
3100
void
3101
2.91M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
2.91M
    if (obj == NULL) return;
3103
2.91M
    if (obj->nodeTab != NULL) {
3104
1.93M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
16.8M
  for (i = 0;i < obj->nodeNr;i++)
3108
14.9M
      if ((obj->nodeTab[i] != NULL) &&
3109
14.9M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
223k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
1.93M
  xmlFree(obj->nodeTab);
3112
1.93M
    }
3113
2.91M
    xmlFree(obj);
3114
2.91M
}
3115
3116
/**
3117
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3118
 * are feed) starting with the entry at `pos`, but does *not* free the list
3119
 * itself. Sets the length of the list to `pos`.
3120
 *
3121
 * @param set  the node set to be cleared
3122
 * @param pos  the start position to clear from
3123
 * @param hasNsNodes  the node set might contain namespace nodes
3124
 */
3125
static void
3126
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3127
7
{
3128
7
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
7
    else if ((hasNsNodes)) {
3131
7
  int i;
3132
7
  xmlNodePtr node;
3133
3134
181k
  for (i = pos; i < set->nodeNr; i++) {
3135
181k
      node = set->nodeTab[i];
3136
181k
      if ((node != NULL) &&
3137
181k
    (node->type == XML_NAMESPACE_DECL))
3138
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
181k
  }
3140
7
    }
3141
7
    set->nodeNr = pos;
3142
7
}
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
0
{
3155
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
0
}
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
2.88M
xmlXPathNewNodeSet(xmlNode *val) {
3192
2.88M
    xmlXPathObjectPtr ret;
3193
3194
2.88M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
2.88M
    if (ret == NULL)
3196
25
  return(NULL);
3197
2.88M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
2.88M
    ret->type = XPATH_NODESET;
3199
2.88M
    ret->boolval = 0;
3200
2.88M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
2.88M
    if (ret->nodesetval == NULL) {
3202
3
        xmlFree(ret);
3203
3
        return(NULL);
3204
3
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
2.88M
    return(ret);
3207
2.88M
}
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
3.35k
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
3.35k
    xmlXPathObjectPtr ret;
3269
3270
3.35k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
3.35k
    if (ret == NULL) {
3272
0
        xmlXPathFreeNodeSet(val);
3273
0
  return(NULL);
3274
0
    }
3275
3.35k
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
3.35k
    ret->type = XPATH_NODESET;
3277
3.35k
    ret->nodesetval = val;
3278
3.35k
    return(ret);
3279
3.35k
}
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
50
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3377
50
    xmlNodeSetPtr ret;
3378
50
    xmlHashTablePtr hash;
3379
50
    int i, l;
3380
50
    xmlChar * strval;
3381
50
    xmlNodePtr cur;
3382
3383
50
    if (xmlXPathNodeSetIsEmpty(nodes))
3384
0
  return(nodes);
3385
3386
50
    ret = xmlXPathNodeSetCreate(NULL);
3387
50
    if (ret == NULL)
3388
0
        return(ret);
3389
50
    l = xmlXPathNodeSetGetLength(nodes);
3390
50
    hash = xmlHashCreate (l);
3391
5.91k
    for (i = 0; i < l; i++) {
3392
5.86k
  cur = xmlXPathNodeSetItem(nodes, i);
3393
5.86k
  strval = xmlXPathCastNodeToString(cur);
3394
5.86k
  if (xmlHashLookup(hash, strval) == NULL) {
3395
1.39k
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3396
0
                xmlFree(strval);
3397
0
                goto error;
3398
0
            }
3399
1.39k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3400
0
          goto error;
3401
4.47k
  } else {
3402
4.47k
      xmlFree(strval);
3403
4.47k
  }
3404
5.86k
    }
3405
50
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3406
50
    return(ret);
3407
3408
0
error:
3409
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3410
0
    xmlXPathFreeNodeSet(ret);
3411
0
    return(NULL);
3412
50
}
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
28
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3571
28
    int i, l;
3572
28
    xmlNodePtr cur;
3573
28
    xmlNodeSetPtr ret;
3574
3575
28
    if (node == NULL)
3576
0
  return(nodes);
3577
3578
28
    ret = xmlXPathNodeSetCreate(NULL);
3579
28
    if (ret == NULL)
3580
0
        return(ret);
3581
28
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3582
28
  (!xmlXPathNodeSetContains(nodes, node)))
3583
0
  return(ret);
3584
3585
28
    l = xmlXPathNodeSetGetLength(nodes);
3586
1.56M
    for (i = l - 1; i >= 0; i--) {
3587
1.56M
  cur = xmlXPathNodeSetItem(nodes, i);
3588
1.56M
  if (cur == node)
3589
28
      break;
3590
1.56M
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3591
0
            xmlXPathFreeNodeSet(ret);
3592
0
      return(NULL);
3593
0
        }
3594
1.56M
    }
3595
28
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3596
28
    return(ret);
3597
28
}
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
2.70k
         xmlXPathFunction f) {
3676
2.70k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
2.70k
}
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
2.70k
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
2.70k
    int ret;
3692
2.70k
    void *payload;
3693
3694
2.70k
    if (ctxt == NULL)
3695
0
  return(-1);
3696
2.70k
    if (name == NULL)
3697
0
  return(-1);
3698
3699
2.70k
    if (ctxt->funcHash == NULL)
3700
300
  ctxt->funcHash = xmlHashCreate(0);
3701
2.70k
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
2.70k
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
2.70k
    memcpy(&payload, &f, sizeof(f));
3708
2.70k
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
2.70k
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
2.70k
    return(0);
3715
2.70k
}
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
300
          void *funcCtxt) {
3728
300
    if (ctxt == NULL)
3729
0
  return;
3730
300
    ctxt->funcLookupFunc = f;
3731
300
    ctxt->funcLookupData = funcCtxt;
3732
300
}
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
144
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
144
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
144
}
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
187
       const xmlChar *ns_uri) {
3759
187
    xmlXPathFunction ret;
3760
187
    void *payload;
3761
3762
187
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
187
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
187
    if (ns_uri == NULL) {
3768
144
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
454
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
326
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
326
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
326
                       (char *) name) == 0)
3775
16
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
310
            bucketIndex += 1;
3778
310
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
310
        }
3781
144
    }
3782
3783
171
    if (ctxt->funcLookupFunc != NULL) {
3784
171
  xmlXPathFuncLookupFunc f;
3785
3786
171
  f = ctxt->funcLookupFunc;
3787
171
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
171
  if (ret != NULL)
3789
42
      return(ret);
3790
171
    }
3791
3792
129
    if (ctxt->funcHash == NULL)
3793
0
  return(NULL);
3794
3795
129
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
129
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
129
    return(ret);
3799
129
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
310
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
310
    if (ctxt == NULL)
3809
0
  return;
3810
3811
310
    xmlHashFree(ctxt->funcHash, NULL);
3812
310
    ctxt->funcHash = NULL;
3813
310
}
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
1.20k
       xmlXPathObject *value) {
3833
1.20k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
1.20k
}
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
1.20k
         xmlXPathObject *value) {
3850
1.20k
    if (ctxt == NULL)
3851
0
  return(-1);
3852
1.20k
    if (name == NULL)
3853
0
  return(-1);
3854
3855
1.20k
    if (ctxt->varHash == NULL)
3856
300
  ctxt->varHash = xmlHashCreate(0);
3857
1.20k
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
1.20k
    if (value == NULL)
3860
4
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
4
                             xmlXPathFreeObjectEntry));
3862
1.19k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
1.19k
             (void *) value, xmlXPathFreeObjectEntry));
3864
1.20k
}
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
300
   xmlXPathVariableLookupFunc f, void *data) {
3876
300
    if (ctxt == NULL)
3877
0
  return;
3878
300
    ctxt->varLookupFunc = f;
3879
300
    ctxt->varLookupData = data;
3880
300
}
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
0
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
0
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
0
    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
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
0
}
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
0
       const xmlChar *ns_uri) {
3917
0
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
0
    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
0
    if (ctxt->varHash == NULL)
3929
0
  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
310
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
310
    if (ctxt == NULL)
3944
0
  return;
3945
3946
310
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
310
    ctxt->varHash = NULL;
3948
310
}
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
3.30k
         const xmlChar *ns_uri) {
3962
3.30k
    xmlChar *copy;
3963
3964
3.30k
    if (ctxt == NULL)
3965
0
  return(-1);
3966
3.30k
    if (prefix == NULL)
3967
0
  return(-1);
3968
3.30k
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
3.30k
    if (ctxt->nsHash == NULL)
3972
300
  ctxt->nsHash = xmlHashCreate(10);
3973
3.30k
    if (ctxt->nsHash == NULL) {
3974
0
        xmlXPathErrMemory(ctxt);
3975
0
  return(-1);
3976
0
    }
3977
3.30k
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
3.30k
    copy = xmlStrdup(ns_uri);
3982
3.30k
    if (copy == NULL) {
3983
0
        xmlXPathErrMemory(ctxt);
3984
0
        return(-1);
3985
0
    }
3986
3.30k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
3.30k
                           xmlHashDefaultDeallocator) < 0) {
3988
0
        xmlXPathErrMemory(ctxt);
3989
0
        xmlFree(copy);
3990
0
        return(-1);
3991
0
    }
3992
3993
3.30k
    return(0);
3994
3.30k
}
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
222
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
222
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
222
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
222
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
0
  return(XML_XML_NAMESPACE);
4013
4014
222
    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
222
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
222
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
612
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
612
    if (ctxt == NULL)
4035
2
  return;
4036
4037
610
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
610
    ctxt->nsHash = NULL;
4039
610
}
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
41.8k
xmlXPathNewFloat(double val) {
4057
41.8k
    xmlXPathObjectPtr ret;
4058
4059
41.8k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
41.8k
    if (ret == NULL)
4061
0
  return(NULL);
4062
41.8k
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
41.8k
    ret->type = XPATH_NUMBER;
4064
41.8k
    ret->floatval = val;
4065
41.8k
    return(ret);
4066
41.8k
}
4067
4068
/**
4069
 * Create a new xmlXPathObject of type boolean and of value `val`
4070
 *
4071
 * @param val  the boolean value
4072
 * @returns the newly created object.
4073
 */
4074
xmlXPathObject *
4075
1.14k
xmlXPathNewBoolean(int val) {
4076
1.14k
    xmlXPathObjectPtr ret;
4077
4078
1.14k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
1.14k
    if (ret == NULL)
4080
0
  return(NULL);
4081
1.14k
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
1.14k
    ret->type = XPATH_BOOLEAN;
4083
1.14k
    ret->boolval = (val != 0);
4084
1.14k
    return(ret);
4085
1.14k
}
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
852
xmlXPathNewString(const xmlChar *val) {
4095
852
    xmlXPathObjectPtr ret;
4096
4097
852
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
852
    if (ret == NULL)
4099
0
  return(NULL);
4100
852
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
852
    ret->type = XPATH_STRING;
4102
852
    if (val == NULL)
4103
0
        val = BAD_CAST "";
4104
852
    ret->stringval = xmlStrdup(val);
4105
852
    if (ret->stringval == NULL) {
4106
0
        xmlFree(ret);
4107
0
        return(NULL);
4108
0
    }
4109
852
    return(ret);
4110
852
}
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
305k
xmlXPathWrapString (xmlChar *val) {
4122
305k
    xmlXPathObjectPtr ret;
4123
4124
305k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
305k
    if (ret == NULL) {
4126
2
        xmlFree(val);
4127
2
  return(NULL);
4128
2
    }
4129
305k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
305k
    ret->type = XPATH_STRING;
4131
305k
    ret->stringval = val;
4132
305k
    return(ret);
4133
305k
}
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
334
xmlXPathNewCString(const char *val) {
4143
334
    return(xmlXPathNewString(BAD_CAST val));
4144
334
}
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
535
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
535
    xmlXPathObjectPtr ret;
4185
4186
535
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
535
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
535
    if (ret == NULL)
4191
0
  return(NULL);
4192
535
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
535
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
0
  case XPATH_NUMBER:
4196
0
      break;
4197
0
  case XPATH_STRING:
4198
0
      ret->stringval = xmlStrdup(val->stringval);
4199
0
            if (ret->stringval == NULL) {
4200
0
                xmlFree(ret);
4201
0
                return(NULL);
4202
0
            }
4203
0
      break;
4204
0
  case XPATH_XSLT_TREE:
4205
535
  case XPATH_NODESET:
4206
535
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4207
535
            if (ret->nodesetval == NULL) {
4208
0
                xmlFree(ret);
4209
0
                return(NULL);
4210
0
            }
4211
      /* Do not deallocate the copied tree value */
4212
535
      ret->boolval = 0;
4213
535
      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
535
    }
4222
535
    return(ret);
4223
535
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
3.20M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
3.20M
    if (obj == NULL) return;
4233
2.88M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
1.92M
        if (obj->nodesetval != NULL)
4235
1.92M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
1.92M
    } else if (obj->type == XPATH_STRING) {
4237
960k
  if (obj->stringval != NULL)
4238
960k
      xmlFree(obj->stringval);
4239
960k
    }
4240
2.88M
    xmlFree(obj);
4241
2.88M
}
4242
4243
static void
4244
1.19k
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4245
1.19k
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4246
1.19k
}
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
1.67M
{
4258
1.67M
    if (obj == NULL)
4259
0
  return;
4260
1.67M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
10
   xmlXPathFreeObject(obj);
4262
1.67M
    } else {
4263
1.67M
  xmlXPathContextCachePtr cache =
4264
1.67M
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
1.67M
  switch (obj->type) {
4267
1.02M
      case XPATH_NODESET:
4268
1.02M
      case XPATH_XSLT_TREE:
4269
1.02M
    if (obj->nodesetval != NULL) {
4270
1.00M
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
1.00M
      (cache->numNodeset < cache->maxNodeset)) {
4272
38.2k
                        obj->stringval = (void *) cache->nodesetObjs;
4273
38.2k
                        cache->nodesetObjs = obj;
4274
38.2k
                        cache->numNodeset += 1;
4275
38.2k
      goto obj_cached;
4276
964k
        } else {
4277
964k
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
964k
      obj->nodesetval = NULL;
4279
964k
        }
4280
1.00M
    }
4281
985k
    break;
4282
985k
      case XPATH_STRING:
4283
306k
    if (obj->stringval != NULL)
4284
306k
        xmlFree(obj->stringval);
4285
306k
                obj->stringval = NULL;
4286
306k
    break;
4287
860
      case XPATH_BOOLEAN:
4288
345k
      case XPATH_NUMBER:
4289
345k
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
1.67M
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
1.63M
        if (cache->numMisc >= cache->maxMisc)
4298
342k
      goto free_obj;
4299
1.29M
        obj->stringval = (void *) cache->miscObjs;
4300
1.29M
        cache->miscObjs = obj;
4301
1.29M
        cache->numMisc += 1;
4302
4303
1.33M
obj_cached:
4304
1.33M
        obj->boolval = 0;
4305
1.33M
  if (obj->nodesetval != NULL) {
4306
38.2k
      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
38.2k
      if (tmpset->nodeNr > 0) {
4313
35.3k
    int i;
4314
35.3k
    xmlNodePtr node;
4315
4316
76.5k
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
41.1k
        node = tmpset->nodeTab[i];
4318
41.1k
        if ((node != NULL) &&
4319
41.1k
      (node->type == XML_NAMESPACE_DECL))
4320
2.66k
        {
4321
2.66k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
2.66k
        }
4323
41.1k
    }
4324
35.3k
      }
4325
38.2k
      tmpset->nodeNr = 0;
4326
38.2k
        }
4327
4328
1.33M
  return;
4329
4330
342k
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
342k
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
342k
  xmlFree(obj);
4337
342k
    }
4338
1.67M
}
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
0
xmlXPathCastBooleanToString (int val) {
4355
0
    xmlChar *ret;
4356
0
    if (val)
4357
0
  ret = xmlStrdup((const xmlChar *) "true");
4358
0
    else
4359
0
  ret = xmlStrdup((const xmlChar *) "false");
4360
0
    return(ret);
4361
0
}
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
434
xmlXPathCastNumberToString (double val) {
4371
434
    xmlChar *ret;
4372
434
    switch (xmlXPathIsInf(val)) {
4373
0
    case 1:
4374
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
0
  break;
4376
0
    case -1:
4377
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
0
  break;
4379
434
    default:
4380
434
  if (xmlXPathIsNaN(val)) {
4381
30
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
404
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
0
      ret = xmlStrdup((const xmlChar *) "0");
4385
404
  } else {
4386
      /* could be improved */
4387
404
      char buf[100];
4388
404
      xmlXPathFormatNumber(val, buf, 99);
4389
404
      buf[99] = 0;
4390
404
      ret = xmlStrdup((const xmlChar *) buf);
4391
404
  }
4392
434
    }
4393
434
    return(ret);
4394
434
}
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
992k
xmlXPathCastNodeToString (xmlNode *node) {
4404
992k
    return(xmlNodeGetContent(node));
4405
992k
}
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
967k
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
967k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
2.03k
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
965k
    if (ns->nodeNr > 1)
4419
587
  xmlXPathNodeSetSort(ns);
4420
965k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
967k
}
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
966k
xmlXPathCastToString(xmlXPathObject *val) {
4432
966k
    xmlChar *ret = NULL;
4433
4434
966k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
966k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
966k
        case XPATH_NODESET:
4441
966k
        case XPATH_XSLT_TREE:
4442
966k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
966k
      break;
4444
228
  case XPATH_STRING:
4445
228
      return(xmlStrdup(val->stringval));
4446
0
        case XPATH_BOOLEAN:
4447
0
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
0
      break;
4449
44
  case XPATH_NUMBER: {
4450
44
      ret = xmlXPathCastNumberToString(val->floatval);
4451
44
      break;
4452
966k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
966k
    }
4458
966k
    return(ret);
4459
966k
}
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
364
xmlXPathCastBooleanToNumber(int val) {
4508
364
    if (val)
4509
240
  return(1.0);
4510
124
    return(0.0);
4511
364
}
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
317k
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
317k
    return(xmlXPathStringEvalNumber(val));
4522
317k
}
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
14.0k
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
14.0k
    xmlChar *strval;
4534
14.0k
    double ret;
4535
4536
14.0k
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
14.0k
    strval = xmlXPathCastNodeToString(node);
4539
14.0k
    if (strval == NULL) {
4540
0
        xmlXPathPErrMemory(ctxt);
4541
0
  return(xmlXPathNAN);
4542
0
    }
4543
14.0k
    ret = xmlXPathCastStringToNumber(strval);
4544
14.0k
    xmlFree(strval);
4545
4546
14.0k
    return(ret);
4547
14.0k
}
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
11.6k
xmlXPathCastNodeToNumber (xmlNode *node) {
4557
11.6k
    return(xmlXPathNodeToNumberInternal(NULL, node));
4558
11.6k
}
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
200
xmlXPathCastNumberToBoolean (double val) {
4618
200
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
0
   return(0);
4620
200
     return(1);
4621
200
}
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
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
0
  return(0);
4633
0
    return(1);
4634
0
}
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
212
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
212
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
30
  return(0);
4646
182
    return(1);
4647
212
}
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
230
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
230
    int ret = 0;
4658
4659
230
    if (val == NULL)
4660
0
  return(0);
4661
230
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
212
    case XPATH_NODESET:
4666
212
    case XPATH_XSLT_TREE:
4667
212
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
212
  break;
4669
0
    case XPATH_STRING:
4670
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
0
  break;
4672
18
    case XPATH_NUMBER:
4673
18
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
18
  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
230
    }
4683
230
    return(ret);
4684
230
}
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
312
xmlXPathNewContext(xmlDoc *doc) {
4721
312
    xmlXPathContextPtr ret;
4722
4723
312
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
312
    if (ret == NULL)
4725
0
  return(NULL);
4726
312
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
312
    ret->doc = doc;
4728
312
    ret->node = NULL;
4729
4730
312
    ret->varHash = NULL;
4731
4732
312
    ret->nb_types = 0;
4733
312
    ret->max_types = 0;
4734
312
    ret->types = NULL;
4735
4736
312
    ret->nb_axis = 0;
4737
312
    ret->max_axis = 0;
4738
312
    ret->axis = NULL;
4739
4740
312
    ret->nsHash = NULL;
4741
312
    ret->user = NULL;
4742
4743
312
    ret->contextSize = -1;
4744
312
    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
312
    return(ret);
4754
312
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
310
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
310
    if (ctxt == NULL) return;
4764
4765
310
    if (ctxt->cache != NULL)
4766
300
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
310
    xmlXPathRegisteredNsCleanup(ctxt);
4768
310
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
310
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
310
    xmlResetError(&ctxt->lastError);
4771
310
    xmlFree(ctxt);
4772
310
}
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
1.61k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
1.61k
    xmlXPathParserContextPtr ret;
4809
4810
1.61k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
1.61k
    if (ret == NULL) {
4812
0
        xmlXPathErrMemory(ctxt);
4813
0
  return(NULL);
4814
0
    }
4815
1.61k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
1.61k
    ret->cur = ret->base = str;
4817
1.61k
    ret->context = ctxt;
4818
4819
1.61k
    ret->comp = xmlXPathNewCompExpr();
4820
1.61k
    if (ret->comp == NULL) {
4821
0
        xmlXPathErrMemory(ctxt);
4822
0
  xmlFree(ret->valueTab);
4823
0
  xmlFree(ret);
4824
0
  return(NULL);
4825
0
    }
4826
1.61k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
1.61k
    return(ret);
4832
1.61k
}
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
3.16k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
3.16k
    xmlXPathParserContextPtr ret;
4844
4845
3.16k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
3.16k
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
3.16k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
3.16k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
3.16k
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
3.16k
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
3.16k
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
3.16k
    ret->valueNr = 0;
4865
3.16k
    ret->value = NULL;
4866
4867
3.16k
    ret->context = ctxt;
4868
3.16k
    ret->comp = comp;
4869
4870
3.16k
    return(ret);
4871
3.16k
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
4.78k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
4.78k
    int i;
4881
4882
4.78k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
4.78k
    if (ctxt->valueTab != NULL) {
4886
4.04k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
564
            if (ctxt->context)
4888
564
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
564
        }
4892
3.47k
        xmlFree(ctxt->valueTab);
4893
3.47k
    }
4894
4.78k
    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
1.46k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
1.46k
    }
4903
4.78k
    xmlFree(ctxt);
4904
4.78k
}
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
11.1k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
11.1k
    int len = 2;
4922
11.1k
    const xmlChar * string = NULL;
4923
11.1k
    xmlNodePtr tmp = NULL;
4924
11.1k
    unsigned int ret = 0;
4925
4926
11.1k
    if (node == NULL)
4927
0
  return(0);
4928
4929
11.1k
    if (node->type == XML_DOCUMENT_NODE) {
4930
80
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
80
  if (tmp == NULL)
4932
0
      node = node->children;
4933
80
  else
4934
80
      node = tmp;
4935
4936
80
  if (node == NULL)
4937
0
      return(0);
4938
80
    }
4939
4940
11.1k
    switch (node->type) {
4941
28
  case XML_COMMENT_NODE:
4942
28
  case XML_PI_NODE:
4943
293
  case XML_CDATA_SECTION_NODE:
4944
5.33k
  case XML_TEXT_NODE:
4945
5.33k
      string = node->content;
4946
5.33k
      if (string == NULL)
4947
0
    return(0);
4948
5.33k
      if (string[0] == 0)
4949
0
    return(0);
4950
5.33k
      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
0
  case XML_ATTRIBUTE_NODE:
4959
0
      tmp = ((xmlAttrPtr) node)->children;
4960
0
      break;
4961
5.83k
  case XML_ELEMENT_NODE:
4962
5.83k
      tmp = node->children;
4963
5.83k
      break;
4964
0
  default:
4965
0
      return(0);
4966
11.1k
    }
4967
9.65k
    while (tmp != NULL) {
4968
6.53k
  switch (tmp->type) {
4969
2
      case XML_CDATA_SECTION_NODE:
4970
2.71k
      case XML_TEXT_NODE:
4971
2.71k
    string = tmp->content;
4972
2.71k
    break;
4973
3.81k
      default:
4974
3.81k
                string = NULL;
4975
3.81k
    break;
4976
6.53k
  }
4977
6.53k
  if ((string != NULL) && (string[0] != 0)) {
4978
2.71k
      if (len == 1) {
4979
2
    return(ret + (string[0] << 8));
4980
2
      }
4981
2.71k
      if (string[1] == 0) {
4982
2
    len = 1;
4983
2
    ret = string[0];
4984
2.71k
      } else {
4985
2.71k
    return(string[0] + (string[1] << 8));
4986
2.71k
      }
4987
2.71k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
3.81k
        if ((tmp->children != NULL) &&
4992
3.81k
            (tmp->type != XML_DTD_NODE) &&
4993
3.81k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
3.81k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
2.93k
            tmp = tmp->children;
4996
2.93k
            continue;
4997
2.93k
  }
4998
888
  if (tmp == node)
4999
0
      break;
5000
5001
888
  if (tmp->next != NULL) {
5002
888
      tmp = tmp->next;
5003
888
      continue;
5004
888
  }
5005
5006
0
  do {
5007
0
      tmp = tmp->parent;
5008
0
      if (tmp == NULL)
5009
0
    break;
5010
0
      if (tmp == node) {
5011
0
    tmp = NULL;
5012
0
    break;
5013
0
      }
5014
0
      if (tmp->next != NULL) {
5015
0
    tmp = tmp->next;
5016
0
    break;
5017
0
      }
5018
0
  } while (tmp != NULL);
5019
0
    }
5020
3.12k
    return(ret);
5021
5.83k
}
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
0
xmlXPathStringHash(const xmlChar * string) {
5032
0
    if (string == NULL)
5033
0
  return(0);
5034
0
    if (string[0] == 0)
5035
0
  return(0);
5036
0
    return(string[0] + (string[1] << 8));
5037
0
}
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
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
0
    int i, ret = 0;
5063
0
    xmlNodeSetPtr ns;
5064
0
    xmlChar *str2;
5065
5066
0
    if ((f == NULL) || (arg == NULL) ||
5067
0
  ((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
0
    ns = arg->nodesetval;
5073
0
    if (ns != NULL) {
5074
0
  for (i = 0;i < ns->nodeNr;i++) {
5075
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
0
       if (str2 != NULL) {
5077
0
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
0
     xmlFree(str2);
5079
0
     xmlXPathNumberFunction(ctxt, 1);
5080
0
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
0
     if (ret)
5083
0
         break;
5084
0
       } else {
5085
0
                 xmlXPathPErrMemory(ctxt);
5086
0
             }
5087
0
  }
5088
0
    }
5089
0
    xmlXPathReleaseObject(ctxt->context, arg);
5090
0
    xmlXPathReleaseObject(ctxt->context, f);
5091
0
    return(ret);
5092
0
}
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
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
0
    int i, ret = 0;
5117
0
    xmlNodeSetPtr ns;
5118
0
    xmlChar *str2;
5119
5120
0
    if ((s == NULL) || (arg == NULL) ||
5121
0
  ((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
0
    ns = arg->nodesetval;
5127
0
    if (ns != NULL) {
5128
0
  for (i = 0;i < ns->nodeNr;i++) {
5129
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
0
       if (str2 != NULL) {
5131
0
     xmlXPathValuePush(ctxt,
5132
0
         xmlXPathCacheNewString(ctxt, str2));
5133
0
     xmlFree(str2);
5134
0
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
0
     if (ret)
5137
0
         break;
5138
0
       } else {
5139
0
                 xmlXPathPErrMemory(ctxt);
5140
0
             }
5141
0
  }
5142
0
    }
5143
0
    xmlXPathReleaseObject(ctxt->context, arg);
5144
0
    xmlXPathReleaseObject(ctxt->context, s);
5145
0
    return(ret);
5146
0
}
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
242
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
242
    int i, j, init = 0;
5180
242
    double val1;
5181
242
    double *values2;
5182
242
    int ret = 0;
5183
242
    xmlNodeSetPtr ns1;
5184
242
    xmlNodeSetPtr ns2;
5185
5186
242
    if ((arg1 == NULL) ||
5187
242
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
242
    if ((arg2 == NULL) ||
5192
242
  ((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
242
    ns1 = arg1->nodesetval;
5199
242
    ns2 = arg2->nodesetval;
5200
5201
242
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
98
  xmlXPathFreeObject(arg1);
5203
98
  xmlXPathFreeObject(arg2);
5204
98
  return(0);
5205
98
    }
5206
144
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
56
  xmlXPathFreeObject(arg1);
5208
56
  xmlXPathFreeObject(arg2);
5209
56
  return(0);
5210
56
    }
5211
5212
88
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
88
    if (values2 == NULL) {
5214
0
        xmlXPathPErrMemory(ctxt);
5215
0
  xmlXPathFreeObject(arg1);
5216
0
  xmlXPathFreeObject(arg2);
5217
0
  return(0);
5218
0
    }
5219
118
    for (i = 0;i < ns1->nodeNr;i++) {
5220
88
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
88
  if (xmlXPathIsNaN(val1))
5222
29
      continue;
5223
2.32k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
2.32k
      if (init == 0) {
5225
2.32k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
2.32k
                                                          ns2->nodeTab[j]);
5227
2.32k
      }
5228
2.32k
      if (xmlXPathIsNaN(values2[j]))
5229
2.26k
    continue;
5230
59
      if (inf && strict)
5231
0
    ret = (val1 < values2[j]);
5232
59
      else if (inf && !strict)
5233
0
    ret = (val1 <= values2[j]);
5234
59
      else if (!inf && strict)
5235
59
    ret = (val1 > values2[j]);
5236
0
      else if (!inf && !strict)
5237
0
    ret = (val1 >= values2[j]);
5238
59
      if (ret)
5239
58
    break;
5240
59
  }
5241
59
  if (ret)
5242
58
      break;
5243
1
  init = 1;
5244
1
    }
5245
88
    xmlFree(values2);
5246
88
    xmlXPathFreeObject(arg1);
5247
88
    xmlXPathFreeObject(arg2);
5248
88
    return(ret);
5249
88
}
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
182
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
182
    if ((val == NULL) || (arg == NULL) ||
5274
182
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
182
    switch(val->type) {
5278
0
        case XPATH_NUMBER:
5279
0
      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
0
        case XPATH_STRING:
5284
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
182
        case XPATH_BOOLEAN:
5286
182
      xmlXPathValuePush(ctxt, arg);
5287
182
      xmlXPathBooleanFunction(ctxt, 1);
5288
182
      xmlXPathValuePush(ctxt, val);
5289
182
      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
182
    }
5295
0
    return(0);
5296
182
}
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
0
{
5315
0
    int i;
5316
0
    xmlNodeSetPtr ns;
5317
0
    xmlChar *str2;
5318
0
    unsigned int hash;
5319
5320
0
    if ((str == NULL) || (arg == NULL) ||
5321
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
0
    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
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
0
        return (0);
5330
0
    hash = xmlXPathStringHash(str);
5331
0
    for (i = 0; i < ns->nodeNr; i++) {
5332
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
0
            if (str2 == NULL) {
5335
0
                xmlXPathPErrMemory(ctxt);
5336
0
                return(0);
5337
0
            }
5338
0
            if (xmlStrEqual(str, str2)) {
5339
0
                xmlFree(str2);
5340
0
    if (neq)
5341
0
        continue;
5342
0
                return (1);
5343
0
            } else if (neq) {
5344
0
    xmlFree(str2);
5345
0
    return (1);
5346
0
      }
5347
0
            xmlFree(str2);
5348
0
        } else if (neq)
5349
0
      return (1);
5350
0
    }
5351
0
    return (0);
5352
0
}
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
0
    xmlXPathObjectPtr arg, double f, int neq) {
5371
0
  int i, ret=0;
5372
0
  xmlNodeSetPtr ns;
5373
0
  xmlChar *str2;
5374
0
  xmlXPathObjectPtr val;
5375
0
  double v;
5376
5377
0
    if ((arg == NULL) ||
5378
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
0
    ns = arg->nodesetval;
5382
0
    if (ns != NULL) {
5383
0
  for (i=0;i<ns->nodeNr;i++) {
5384
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
0
      if (str2 != NULL) {
5386
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
0
    xmlFree(str2);
5388
0
    xmlXPathNumberFunction(ctxt, 1);
5389
0
                CHECK_ERROR0;
5390
0
    val = xmlXPathValuePop(ctxt);
5391
0
    v = val->floatval;
5392
0
    xmlXPathReleaseObject(ctxt->context, val);
5393
0
    if (!xmlXPathIsNaN(v)) {
5394
0
        if ((!neq) && (v==f)) {
5395
0
      ret = 1;
5396
0
      break;
5397
0
        } else if ((neq) && (v!=f)) {
5398
0
      ret = 1;
5399
0
      break;
5400
0
        }
5401
0
    } else { /* NaN is unequal to any value */
5402
0
        if (neq)
5403
0
      ret = 1;
5404
0
    }
5405
0
      } else {
5406
0
                xmlXPathPErrMemory(ctxt);
5407
0
            }
5408
0
  }
5409
0
    }
5410
5411
0
    return(ret);
5412
0
}
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
83
                      xmlXPathObjectPtr arg2, int neq) {
5434
83
    int i, j;
5435
83
    unsigned int *hashs1;
5436
83
    unsigned int *hashs2;
5437
83
    xmlChar **values1;
5438
83
    xmlChar **values2;
5439
83
    int ret = 0;
5440
83
    xmlNodeSetPtr ns1;
5441
83
    xmlNodeSetPtr ns2;
5442
5443
83
    if ((arg1 == NULL) ||
5444
83
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
83
    if ((arg2 == NULL) ||
5447
83
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
83
    ns1 = arg1->nodesetval;
5451
83
    ns2 = arg2->nodesetval;
5452
5453
83
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
0
  return(0);
5455
83
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
1
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
82
    if (neq == 0)
5462
162
  for (i = 0;i < ns1->nodeNr;i++)
5463
11.5k
      for (j = 0;j < ns2->nodeNr;j++)
5464
11.4k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
2
        return(1);
5466
5467
80
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
80
    if (values1 == NULL) {
5469
0
        xmlXPathPErrMemory(ctxt);
5470
0
  return(0);
5471
0
    }
5472
80
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
80
    if (hashs1 == NULL) {
5474
0
        xmlXPathPErrMemory(ctxt);
5475
0
  xmlFree(values1);
5476
0
  return(0);
5477
0
    }
5478
80
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
80
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
80
    if (values2 == NULL) {
5481
0
        xmlXPathPErrMemory(ctxt);
5482
0
  xmlFree(hashs1);
5483
0
  xmlFree(values1);
5484
0
  return(0);
5485
0
    }
5486
80
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
80
    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
80
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
158
    for (i = 0;i < ns1->nodeNr;i++) {
5496
80
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
11.1k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
11.0k
      if (i == 0)
5499
11.0k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
11.0k
      if (hashs1[i] != hashs2[j]) {
5501
11.0k
    if (neq) {
5502
0
        ret = 1;
5503
0
        break;
5504
0
    }
5505
11.0k
      }
5506
8
      else {
5507
8
    if (values1[i] == NULL) {
5508
3
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
3
                    if (values1[i] == NULL)
5510
0
                        xmlXPathPErrMemory(ctxt);
5511
3
                }
5512
8
    if (values2[j] == NULL) {
5513
8
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
8
                    if (values2[j] == NULL)
5515
0
                        xmlXPathPErrMemory(ctxt);
5516
8
                }
5517
8
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
8
    if (ret)
5519
2
        break;
5520
8
      }
5521
11.0k
  }
5522
80
  if (ret)
5523
2
      break;
5524
80
    }
5525
160
    for (i = 0;i < ns1->nodeNr;i++)
5526
80
  if (values1[i] != NULL)
5527
3
      xmlFree(values1[i]);
5528
11.5k
    for (j = 0;j < ns2->nodeNr;j++)
5529
11.4k
  if (values2[j] != NULL)
5530
8
      xmlFree(values2[j]);
5531
80
    xmlFree(values1);
5532
80
    xmlFree(values2);
5533
80
    xmlFree(hashs1);
5534
80
    xmlFree(hashs2);
5535
80
    return(ret);
5536
80
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
182
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
182
    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
182
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
182
        case XPATH_BOOLEAN:
5550
182
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
0
    case XPATH_BOOLEAN:
5554
0
        ret = (arg1->boolval == arg2->boolval);
5555
0
        break;
5556
182
    case XPATH_NUMBER:
5557
182
        ret = (arg1->boolval ==
5558
182
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
182
        break;
5560
0
    case XPATH_STRING:
5561
0
        if ((arg2->stringval == NULL) ||
5562
0
      (arg2->stringval[0] == 0)) ret = 0;
5563
0
        else
5564
0
      ret = 1;
5565
0
        ret = (arg1->boolval == ret);
5566
0
        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
182
      }
5574
182
      break;
5575
182
        case XPATH_NUMBER:
5576
0
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
0
    case XPATH_BOOLEAN:
5580
0
        ret = (arg2->boolval==
5581
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
0
        break;
5583
0
    case XPATH_STRING:
5584
0
        xmlXPathValuePush(ctxt, arg2);
5585
0
        xmlXPathNumberFunction(ctxt, 1);
5586
0
        arg2 = xmlXPathValuePop(ctxt);
5587
0
                    if (ctxt->error)
5588
0
                        break;
5589
                    /* Falls through. */
5590
0
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
0
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
0
          xmlXPathIsNaN(arg2->floatval)) {
5594
0
            ret = 0;
5595
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
0
          ret = 1;
5598
0
      else
5599
0
          ret = 0;
5600
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
0
          ret = 1;
5603
0
      else
5604
0
          ret = 0;
5605
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
0
      else
5609
0
          ret = 0;
5610
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
0
      else
5614
0
          ret = 0;
5615
0
        } else {
5616
0
            ret = (arg1->floatval == arg2->floatval);
5617
0
        }
5618
0
        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
0
      }
5626
0
      break;
5627
0
        case XPATH_STRING:
5628
0
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
0
    case XPATH_BOOLEAN:
5632
0
        if ((arg1->stringval == NULL) ||
5633
0
      (arg1->stringval[0] == 0)) ret = 0;
5634
0
        else
5635
0
      ret = 1;
5636
0
        ret = (arg2->boolval == ret);
5637
0
        break;
5638
0
    case XPATH_STRING:
5639
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
0
        break;
5641
0
    case XPATH_NUMBER:
5642
0
        xmlXPathValuePush(ctxt, arg1);
5643
0
        xmlXPathNumberFunction(ctxt, 1);
5644
0
        arg1 = xmlXPathValuePop(ctxt);
5645
0
                    if (ctxt->error)
5646
0
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
0
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
0
          xmlXPathIsNaN(arg2->floatval)) {
5650
0
            ret = 0;
5651
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
0
          ret = 1;
5654
0
      else
5655
0
          ret = 0;
5656
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
0
          ret = 1;
5659
0
      else
5660
0
          ret = 0;
5661
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
0
      else
5665
0
          ret = 0;
5666
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
0
      else
5670
0
          ret = 0;
5671
0
        } else {
5672
0
            ret = (arg1->floatval == arg2->floatval);
5673
0
        }
5674
0
        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
0
      }
5682
0
      break;
5683
0
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
182
    }
5690
182
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
182
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
182
    return(ret);
5693
182
}
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
265
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
265
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
265
    int ret = 0;
5705
5706
265
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
265
    arg2 = xmlXPathValuePop(ctxt);
5708
265
    arg1 = xmlXPathValuePop(ctxt);
5709
265
    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
265
    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
265
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
265
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
83
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
0
    argtmp = arg2;
5732
0
    arg2 = arg1;
5733
0
    arg1 = argtmp;
5734
0
  }
5735
83
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
83
      case XPATH_NODESET:
5739
83
      case XPATH_XSLT_TREE:
5740
83
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
83
    break;
5742
0
      case XPATH_BOOLEAN:
5743
0
    if ((arg1->nodesetval == NULL) ||
5744
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
0
    else
5746
0
        ret = 1;
5747
0
    ret = (ret == arg2->boolval);
5748
0
    break;
5749
0
      case XPATH_NUMBER:
5750
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
0
    break;
5752
0
      case XPATH_STRING:
5753
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
0
                                                 arg2->stringval, 0);
5755
0
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
83
  }
5760
83
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
83
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
83
  return(ret);
5763
83
    }
5764
5765
182
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
265
}
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
0
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
0
    int ret = 0;
5778
5779
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
0
    arg2 = xmlXPathValuePop(ctxt);
5781
0
    arg1 = xmlXPathValuePop(ctxt);
5782
0
    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
0
    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
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
0
    argtmp = arg2;
5805
0
    arg2 = arg1;
5806
0
    arg1 = argtmp;
5807
0
  }
5808
0
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
0
      case XPATH_NODESET:
5812
0
      case XPATH_XSLT_TREE:
5813
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
0
    break;
5815
0
      case XPATH_BOOLEAN:
5816
0
    if ((arg1->nodesetval == NULL) ||
5817
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
0
    else
5819
0
        ret = 1;
5820
0
    ret = (ret != arg2->boolval);
5821
0
    break;
5822
0
      case XPATH_NUMBER:
5823
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
0
    break;
5825
0
      case XPATH_STRING:
5826
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
0
                                                 arg2->stringval, 1);
5828
0
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
0
  }
5833
0
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
0
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
0
  return(ret);
5836
0
    }
5837
5838
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
0
}
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
606
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
606
    int ret = 0, arg1i = 0, arg2i = 0;
5866
606
    xmlXPathObjectPtr arg1, arg2;
5867
5868
606
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
606
    arg2 = xmlXPathValuePop(ctxt);
5870
606
    arg1 = xmlXPathValuePop(ctxt);
5871
606
    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
606
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
606
      (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
424
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
424
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
242
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
242
  } else {
5890
182
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
0
                                arg1, arg2);
5893
182
      } else {
5894
182
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
182
                                arg2, arg1);
5896
182
      }
5897
182
  }
5898
424
  return(ret);
5899
424
    }
5900
5901
182
    if (arg1->type != XPATH_NUMBER) {
5902
182
  xmlXPathValuePush(ctxt, arg1);
5903
182
  xmlXPathNumberFunction(ctxt, 1);
5904
182
  arg1 = xmlXPathValuePop(ctxt);
5905
182
    }
5906
182
    if (arg2->type != XPATH_NUMBER) {
5907
182
  xmlXPathValuePush(ctxt, arg2);
5908
182
  xmlXPathNumberFunction(ctxt, 1);
5909
182
  arg2 = xmlXPathValuePop(ctxt);
5910
182
    }
5911
182
    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
182
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
0
  ret=0;
5920
182
    } else {
5921
182
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
182
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
182
  if (inf && strict) {
5924
182
      if ((arg1i == -1 && arg2i != -1) ||
5925
182
    (arg2i == 1 && arg1i != 1)) {
5926
0
    ret = 1;
5927
182
      } else if (arg1i == 0 && arg2i == 0) {
5928
182
    ret = (arg1->floatval < arg2->floatval);
5929
182
      } else {
5930
0
    ret = 0;
5931
0
      }
5932
182
  }
5933
0
  else if (inf && !strict) {
5934
0
      if (arg1i == -1 || arg2i == 1) {
5935
0
    ret = 1;
5936
0
      } else if (arg1i == 0 && arg2i == 0) {
5937
0
    ret = (arg1->floatval <= arg2->floatval);
5938
0
      } else {
5939
0
    ret = 0;
5940
0
      }
5941
0
  }
5942
0
  else if (!inf && strict) {
5943
0
      if ((arg1i == 1 && arg2i != 1) ||
5944
0
    (arg2i == -1 && arg1i != -1)) {
5945
0
    ret = 1;
5946
0
      } else if (arg1i == 0 && arg2i == 0) {
5947
0
    ret = (arg1->floatval > arg2->floatval);
5948
0
      } else {
5949
0
    ret = 0;
5950
0
      }
5951
0
  }
5952
0
  else if (!inf && !strict) {
5953
0
      if (arg1i == 1 || arg2i == -1) {
5954
0
    ret = 1;
5955
0
      } else if (arg1i == 0 && arg2i == 0) {
5956
0
    ret = (arg1->floatval >= arg2->floatval);
5957
0
      } else {
5958
0
    ret = 0;
5959
0
      }
5960
0
  }
5961
182
    }
5962
182
error:
5963
182
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
182
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
182
    return(ret);
5966
182
}
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
302k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
302k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
302k
    CAST_TO_NUMBER;
5979
302k
    CHECK_TYPE(XPATH_NUMBER);
5980
302k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
302k
}
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
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
2
    xmlXPathObjectPtr arg;
5993
2
    double val;
5994
5995
2
    arg = xmlXPathValuePop(ctxt);
5996
2
    if (arg == NULL)
5997
2
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
2
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
2
    xmlXPathReleaseObject(ctxt->context, arg);
6000
2
    CAST_TO_NUMBER;
6001
2
    CHECK_TYPE(XPATH_NUMBER);
6002
2
    ctxt->value->floatval += val;
6003
2
}
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
0
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
0
    xmlXPathObjectPtr arg;
6015
0
    double val;
6016
6017
0
    arg = xmlXPathValuePop(ctxt);
6018
0
    if (arg == NULL)
6019
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
0
    xmlXPathReleaseObject(ctxt->context, arg);
6022
0
    CAST_TO_NUMBER;
6023
0
    CHECK_TYPE(XPATH_NUMBER);
6024
0
    ctxt->value->floatval -= val;
6025
0
}
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
522
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
522
    xmlXPathObjectPtr arg;
6037
522
    double val;
6038
6039
522
    arg = xmlXPathValuePop(ctxt);
6040
522
    if (arg == NULL)
6041
522
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
522
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
522
    xmlXPathReleaseObject(ctxt->context, arg);
6044
522
    CAST_TO_NUMBER;
6045
522
    CHECK_TYPE(XPATH_NUMBER);
6046
522
    ctxt->value->floatval *= val;
6047
522
}
6048
6049
/**
6050
 * Implement the div operation on XPath objects `arg1` / `arg2`.
6051
 * The numeric operators convert their operands to numbers as if
6052
 * by calling the number function.
6053
 *
6054
 * @param ctxt  the XPath Parser context
6055
 */
6056
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6057
void
6058
0
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
0
    xmlXPathObjectPtr arg;
6060
0
    double val;
6061
6062
0
    arg = xmlXPathValuePop(ctxt);
6063
0
    if (arg == NULL)
6064
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
0
    xmlXPathReleaseObject(ctxt->context, arg);
6067
0
    CAST_TO_NUMBER;
6068
0
    CHECK_TYPE(XPATH_NUMBER);
6069
0
    ctxt->value->floatval /= val;
6070
0
}
6071
6072
/**
6073
 * Implement the mod operation on XPath objects: `arg1` / `arg2`
6074
 * The numeric operators convert their operands to numbers as if
6075
 * by calling the number function.
6076
 *
6077
 * @param ctxt  the XPath Parser context
6078
 */
6079
void
6080
0
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
0
    xmlXPathObjectPtr arg;
6082
0
    double arg1, arg2;
6083
6084
0
    arg = xmlXPathValuePop(ctxt);
6085
0
    if (arg == NULL)
6086
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
0
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
0
    xmlXPathReleaseObject(ctxt->context, arg);
6089
0
    CAST_TO_NUMBER;
6090
0
    CHECK_TYPE(XPATH_NUMBER);
6091
0
    arg1 = ctxt->value->floatval;
6092
0
    if (arg2 == 0)
6093
0
  ctxt->value->floatval = xmlXPathNAN;
6094
0
    else {
6095
0
  ctxt->value->floatval = fmod(arg1, arg2);
6096
0
    }
6097
0
}
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
0
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
0
    if (cur == NULL)
6141
0
        return(ctxt->context->node);
6142
0
    return(NULL);
6143
0
}
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
948k
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
948k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
948k
    if (cur == NULL) {
6157
459k
  if (ctxt->context->node == NULL) return(NULL);
6158
459k
  switch (ctxt->context->node->type) {
6159
419k
            case XML_ELEMENT_NODE:
6160
459k
            case XML_TEXT_NODE:
6161
459k
            case XML_CDATA_SECTION_NODE:
6162
459k
            case XML_ENTITY_REF_NODE:
6163
459k
            case XML_ENTITY_NODE:
6164
459k
            case XML_PI_NODE:
6165
459k
            case XML_COMMENT_NODE:
6166
459k
            case XML_NOTATION_NODE:
6167
459k
            case XML_DTD_NODE:
6168
459k
    return(ctxt->context->node->children);
6169
25
            case XML_DOCUMENT_NODE:
6170
25
            case XML_DOCUMENT_TYPE_NODE:
6171
25
            case XML_DOCUMENT_FRAG_NODE:
6172
25
            case XML_HTML_DOCUMENT_NODE:
6173
25
    return(((xmlDocPtr) ctxt->context->node)->children);
6174
0
      case XML_ELEMENT_DECL:
6175
0
      case XML_ATTRIBUTE_DECL:
6176
0
      case XML_ENTITY_DECL:
6177
0
            case XML_ATTRIBUTE_NODE:
6178
0
      case XML_NAMESPACE_DECL:
6179
0
      case XML_XINCLUDE_START:
6180
0
      case XML_XINCLUDE_END:
6181
0
    return(NULL);
6182
459k
  }
6183
0
  return(NULL);
6184
459k
    }
6185
488k
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
488k
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
488k
    return(cur->next);
6189
488k
}
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
74.9k
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
74.9k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
74.9k
    if (cur == NULL) {
6203
10.9k
  cur = ctxt->context->node;
6204
10.9k
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
10.9k
  switch (cur->type) {
6209
7.75k
            case XML_ELEMENT_NODE:
6210
7.75k
      case XML_DOCUMENT_FRAG_NODE:
6211
7.75k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
7.75k
            case XML_ENTITY_NODE:
6213
7.75k
    cur = cur->children;
6214
7.75k
    if (cur != NULL) {
6215
4.34k
        if (cur->type == XML_ELEMENT_NODE)
6216
2.38k
      return(cur);
6217
2.74k
        do {
6218
2.74k
      cur = cur->next;
6219
2.74k
        } while ((cur != NULL) &&
6220
2.74k
      (cur->type != XML_ELEMENT_NODE));
6221
1.96k
        return(cur);
6222
4.34k
    }
6223
3.41k
    return(NULL);
6224
410
            case XML_DOCUMENT_NODE:
6225
410
            case XML_HTML_DOCUMENT_NODE:
6226
410
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
2.81k
      default:
6228
2.81k
    return(NULL);
6229
10.9k
  }
6230
0
  return(NULL);
6231
10.9k
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
63.9k
    switch (cur->type) {
6236
63.9k
  case XML_ELEMENT_NODE:
6237
63.9k
  case XML_TEXT_NODE:
6238
63.9k
  case XML_ENTITY_REF_NODE:
6239
63.9k
  case XML_ENTITY_NODE:
6240
63.9k
  case XML_CDATA_SECTION_NODE:
6241
63.9k
  case XML_PI_NODE:
6242
63.9k
  case XML_COMMENT_NODE:
6243
63.9k
  case XML_XINCLUDE_END:
6244
63.9k
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
63.9k
    }
6249
63.9k
    if (cur->next != NULL) {
6250
60.2k
  if (cur->next->type == XML_ELEMENT_NODE)
6251
47.0k
      return(cur->next);
6252
13.2k
  cur = cur->next;
6253
52.1k
  do {
6254
52.1k
      cur = cur->next;
6255
52.1k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
13.2k
  return(cur);
6257
60.2k
    }
6258
3.66k
    return(NULL);
6259
63.9k
}
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
11.1M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
11.1M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
11.1M
    if (cur == NULL) {
6274
983
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
983
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
983
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
0
      return(NULL);
6279
6280
983
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
983
      return(ctxt->context->doc->children);
6282
0
        return(ctxt->context->node->children);
6283
983
    }
6284
6285
11.1M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
11.1M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
329k
  if (cur->children->type != XML_ENTITY_DECL) {
6292
329k
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
329k
      if (cur->type != XML_DTD_NODE)
6297
329k
    return(cur);
6298
329k
  }
6299
329k
    }
6300
6301
10.8M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
10.8M
    while (cur->next != NULL) {
6304
10.6M
  cur = cur->next;
6305
10.6M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
10.6M
      (cur->type != XML_DTD_NODE))
6307
10.6M
      return(cur);
6308
10.6M
    }
6309
6310
329k
    do {
6311
329k
        cur = cur->parent;
6312
329k
  if (cur == NULL) break;
6313
329k
  if (cur == ctxt->context->node) return(NULL);
6314
325k
  if (cur->next != NULL) {
6315
159k
      cur = cur->next;
6316
159k
      return(cur);
6317
159k
  }
6318
325k
    } while (cur != NULL);
6319
0
    return(cur);
6320
163k
}
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
8.04M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
8.04M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
8.04M
    if (cur == NULL)
6337
8.65k
        return(ctxt->context->node);
6338
6339
8.03M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
8.03M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
8.03M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
5.52k
        return(NULL);
6344
6345
8.03M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
8.03M
}
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
903k
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
903k
    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
903k
    if (cur == NULL) {
6365
452k
  if (ctxt->context->node == NULL) return(NULL);
6366
452k
  switch (ctxt->context->node->type) {
6367
235k
            case XML_ELEMENT_NODE:
6368
437k
            case XML_TEXT_NODE:
6369
446k
            case XML_CDATA_SECTION_NODE:
6370
446k
            case XML_ENTITY_REF_NODE:
6371
446k
            case XML_ENTITY_NODE:
6372
446k
            case XML_PI_NODE:
6373
450k
            case XML_COMMENT_NODE:
6374
450k
            case XML_NOTATION_NODE:
6375
450k
            case XML_DTD_NODE:
6376
450k
      case XML_ELEMENT_DECL:
6377
450k
      case XML_ATTRIBUTE_DECL:
6378
450k
      case XML_XINCLUDE_START:
6379
450k
      case XML_XINCLUDE_END:
6380
450k
      case XML_ENTITY_DECL:
6381
450k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
450k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
450k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
449k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
449k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
450k
    return(ctxt->context->node->parent);
6389
0
            case XML_ATTRIBUTE_NODE: {
6390
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
0
    return(att->parent);
6393
450k
      }
6394
1.50k
            case XML_DOCUMENT_NODE:
6395
1.50k
            case XML_DOCUMENT_TYPE_NODE:
6396
1.50k
            case XML_DOCUMENT_FRAG_NODE:
6397
1.50k
            case XML_HTML_DOCUMENT_NODE:
6398
1.50k
                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
452k
  }
6408
452k
    }
6409
450k
    return(NULL);
6410
903k
}
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
66.5k
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
66.5k
    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
66.5k
    if (cur == NULL) {
6433
9.09k
  if (ctxt->context->node == NULL) return(NULL);
6434
9.09k
  switch (ctxt->context->node->type) {
6435
1.42k
            case XML_ELEMENT_NODE:
6436
3.97k
            case XML_TEXT_NODE:
6437
4.05k
            case XML_CDATA_SECTION_NODE:
6438
4.05k
            case XML_ENTITY_REF_NODE:
6439
4.05k
            case XML_ENTITY_NODE:
6440
5.19k
            case XML_PI_NODE:
6441
5.19k
            case XML_COMMENT_NODE:
6442
5.19k
      case XML_DTD_NODE:
6443
5.19k
      case XML_ELEMENT_DECL:
6444
5.19k
      case XML_ATTRIBUTE_DECL:
6445
5.19k
      case XML_ENTITY_DECL:
6446
5.19k
            case XML_NOTATION_NODE:
6447
5.19k
      case XML_XINCLUDE_START:
6448
5.19k
      case XML_XINCLUDE_END:
6449
5.19k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
5.19k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
5.19k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
5.18k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
5.18k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
5.19k
    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
5.19k
      }
6462
2
            case XML_DOCUMENT_NODE:
6463
2
            case XML_DOCUMENT_TYPE_NODE:
6464
2
            case XML_DOCUMENT_FRAG_NODE:
6465
2
            case XML_HTML_DOCUMENT_NODE:
6466
2
                return(NULL);
6467
3.90k
      case XML_NAMESPACE_DECL: {
6468
3.90k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
3.90k
    if ((ns->next != NULL) &&
6471
3.90k
        (ns->next->type != XML_NAMESPACE_DECL))
6472
3.90k
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
3.90k
      }
6476
9.09k
  }
6477
0
  return(NULL);
6478
9.09k
    }
6479
57.4k
    if (cur == ctxt->context->doc->children)
6480
9.08k
  return((xmlNodePtr) ctxt->context->doc);
6481
48.3k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
9.09k
  return(NULL);
6483
39.2k
    switch (cur->type) {
6484
39.2k
  case XML_ELEMENT_NODE:
6485
39.2k
  case XML_TEXT_NODE:
6486
39.2k
  case XML_CDATA_SECTION_NODE:
6487
39.2k
  case XML_ENTITY_REF_NODE:
6488
39.2k
  case XML_ENTITY_NODE:
6489
39.2k
  case XML_PI_NODE:
6490
39.2k
  case XML_COMMENT_NODE:
6491
39.2k
  case XML_NOTATION_NODE:
6492
39.2k
  case XML_DTD_NODE:
6493
39.2k
        case XML_ELEMENT_DECL:
6494
39.2k
        case XML_ATTRIBUTE_DECL:
6495
39.2k
        case XML_ENTITY_DECL:
6496
39.2k
  case XML_XINCLUDE_START:
6497
39.2k
  case XML_XINCLUDE_END:
6498
39.2k
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
39.2k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
39.2k
    ((cur->parent->name[0] == ' ') ||
6502
39.2k
     (xmlStrEqual(cur->parent->name,
6503
39.2k
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
39.2k
      return(cur->parent);
6506
0
  case XML_ATTRIBUTE_NODE: {
6507
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
0
      return(att->parent);
6510
39.2k
  }
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
39.2k
    }
6526
0
    return(NULL);
6527
39.2k
}
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
0
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
0
  return(NULL);
6563
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6564
0
        return(NULL);
6565
0
    if (cur == NULL)
6566
0
        return(ctxt->context->node->next);
6567
0
    return(cur->next);
6568
0
}
6569
6570
/**
6571
 * Traversal function for the "preceding-sibling" direction
6572
 * The preceding-sibling axis contains the preceding siblings of the context
6573
 * node in reverse document order; the first preceding sibling is first on the
6574
 * axis; the sibling preceding that node is the second on the axis and so on.
6575
 *
6576
 * @param ctxt  the XPath Parser context
6577
 * @param cur  the current node in the traversal
6578
 * @returns the next element following that axis
6579
 */
6580
xmlNode *
6581
26.0k
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6582
26.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6583
26.0k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6584
26.0k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6585
0
  return(NULL);
6586
26.0k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6587
0
        return(NULL);
6588
26.0k
    if (cur == NULL)
6589
4.96k
        return(ctxt->context->node->prev);
6590
21.0k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6591
0
  cur = cur->prev;
6592
0
  if (cur == NULL)
6593
0
      return(ctxt->context->node->prev);
6594
0
    }
6595
21.0k
    return(cur->prev);
6596
21.0k
}
6597
6598
/**
6599
 * Traversal function for the "following" direction
6600
 * The following axis contains all nodes in the same document as the context
6601
 * node that are after the context node in document order, excluding any
6602
 * descendants and excluding attribute nodes and namespace nodes; the nodes
6603
 * are ordered in document order
6604
 *
6605
 * @param ctxt  the XPath Parser context
6606
 * @param cur  the current node in the traversal
6607
 * @returns the next element following that axis
6608
 */
6609
xmlNode *
6610
0
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6611
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6612
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6613
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6614
0
        return(cur->children);
6615
6616
0
    if (cur == NULL) {
6617
0
        cur = ctxt->context->node;
6618
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6619
0
            cur = cur->parent;
6620
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6621
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6622
6623
0
            if ((ns->next == NULL) ||
6624
0
                (ns->next->type == XML_NAMESPACE_DECL))
6625
0
                return (NULL);
6626
0
            cur = (xmlNodePtr) ns->next;
6627
0
        }
6628
0
    }
6629
0
    if (cur == NULL) return(NULL) ; /* ERROR */
6630
0
    if (cur->next != NULL) return(cur->next) ;
6631
0
    do {
6632
0
        cur = cur->parent;
6633
0
        if (cur == NULL) break;
6634
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6635
0
        if (cur->next != NULL) return(cur->next);
6636
0
    } while (cur != NULL);
6637
0
    return(cur);
6638
0
}
6639
6640
/*
6641
 * @param ancestor  the ancestor node
6642
 * @param node  the current node
6643
 *
6644
 * Check that `ancestor` is a `node`'s ancestor
6645
 *
6646
 * @returns 1 if `ancestor` is a `node`'s ancestor, 0 otherwise.
6647
 */
6648
static int
6649
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6650
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
6651
0
    if (node->type == XML_NAMESPACE_DECL)
6652
0
        return(0);
6653
0
    if (ancestor->type == XML_NAMESPACE_DECL)
6654
0
        return(0);
6655
    /* nodes need to be in the same document */
6656
0
    if (ancestor->doc != node->doc) return(0);
6657
    /* avoid searching if ancestor or node is the root node */
6658
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
6659
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
6660
0
    while (node->parent != NULL) {
6661
0
        if (node->parent == ancestor)
6662
0
            return(1);
6663
0
  node = node->parent;
6664
0
    }
6665
0
    return(0);
6666
0
}
6667
6668
/**
6669
 * Traversal function for the "preceding" direction
6670
 * the preceding axis contains all nodes in the same document as the context
6671
 * node that are before the context node in document order, excluding any
6672
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6673
 * ordered in reverse document order
6674
 *
6675
 * @param ctxt  the XPath Parser context
6676
 * @param cur  the current node in the traversal
6677
 * @returns the next element following that axis
6678
 */
6679
xmlNode *
6680
xmlXPathNextPreceding(xmlXPathParserContext *ctxt, xmlNode *cur)
6681
0
{
6682
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6683
0
    if (cur == NULL) {
6684
0
        cur = ctxt->context->node;
6685
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6686
0
            cur = cur->parent;
6687
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6688
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6689
6690
0
            if ((ns->next == NULL) ||
6691
0
                (ns->next->type == XML_NAMESPACE_DECL))
6692
0
                return (NULL);
6693
0
            cur = (xmlNodePtr) ns->next;
6694
0
        }
6695
0
    }
6696
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6697
0
  return (NULL);
6698
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6699
0
  cur = cur->prev;
6700
0
    do {
6701
0
        if (cur->prev != NULL) {
6702
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6703
0
            return (cur);
6704
0
        }
6705
6706
0
        cur = cur->parent;
6707
0
        if (cur == NULL)
6708
0
            return (NULL);
6709
0
        if (cur == ctxt->context->doc->children)
6710
0
            return (NULL);
6711
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6712
0
    return (cur);
6713
0
}
6714
6715
/**
6716
 * Traversal function for the "preceding" direction
6717
 * the preceding axis contains all nodes in the same document as the context
6718
 * node that are before the context node in document order, excluding any
6719
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6720
 * ordered in reverse document order
6721
 * This is a faster implementation but internal only since it requires a
6722
 * state kept in the parser context: ctxt->ancestor.
6723
 *
6724
 * @param ctxt  the XPath Parser context
6725
 * @param cur  the current node in the traversal
6726
 * @returns the next element following that axis
6727
 */
6728
static xmlNodePtr
6729
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6730
                              xmlNodePtr cur)
6731
49.6k
{
6732
49.6k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6733
49.6k
    if (cur == NULL) {
6734
263
        cur = ctxt->context->node;
6735
263
        if (cur == NULL)
6736
0
            return (NULL);
6737
263
        if (cur->type == XML_ATTRIBUTE_NODE) {
6738
0
            cur = cur->parent;
6739
263
        } else if (cur->type == XML_NAMESPACE_DECL) {
6740
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6741
6742
0
            if ((ns->next == NULL) ||
6743
0
                (ns->next->type == XML_NAMESPACE_DECL))
6744
0
                return (NULL);
6745
0
            cur = (xmlNodePtr) ns->next;
6746
0
        }
6747
263
        ctxt->ancestor = cur->parent;
6748
263
    }
6749
49.6k
    if (cur->type == XML_NAMESPACE_DECL)
6750
0
        return(NULL);
6751
49.6k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6752
0
  cur = cur->prev;
6753
63.9k
    while (cur->prev == NULL) {
6754
16.7k
        cur = cur->parent;
6755
16.7k
        if (cur == NULL)
6756
1
            return (NULL);
6757
16.7k
        if (cur == ctxt->context->doc->children)
6758
262
            return (NULL);
6759
16.4k
        if (cur != ctxt->ancestor)
6760
2.17k
            return (cur);
6761
14.3k
        ctxt->ancestor = cur->parent;
6762
14.3k
    }
6763
47.2k
    cur = cur->prev;
6764
49.3k
    while (cur->last != NULL)
6765
2.17k
        cur = cur->last;
6766
47.2k
    return (cur);
6767
49.6k
}
6768
6769
/**
6770
 * Traversal function for the "namespace" direction
6771
 * the namespace axis contains the namespace nodes of the context node;
6772
 * the order of nodes on this axis is implementation-defined; the axis will
6773
 * be empty unless the context node is an element
6774
 *
6775
 * We keep the XML namespace node at the end of the list.
6776
 *
6777
 * @param ctxt  the XPath Parser context
6778
 * @param cur  the current attribute in the traversal
6779
 * @returns the next element following that axis
6780
 */
6781
xmlNode *
6782
281k
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6783
281k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6784
281k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6785
272k
    if (cur == NULL) {
6786
56.8k
        if (ctxt->context->tmpNsList != NULL)
6787
3.74k
      xmlFree(ctxt->context->tmpNsList);
6788
56.8k
  ctxt->context->tmpNsNr = 0;
6789
56.8k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6790
56.8k
                             &ctxt->context->tmpNsList) < 0) {
6791
0
            xmlXPathPErrMemory(ctxt);
6792
0
            return(NULL);
6793
0
        }
6794
56.8k
        if (ctxt->context->tmpNsList != NULL) {
6795
227k
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6796
170k
                ctxt->context->tmpNsNr++;
6797
170k
            }
6798
56.8k
        }
6799
56.8k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6800
56.8k
    }
6801
216k
    if (ctxt->context->tmpNsNr > 0) {
6802
163k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6803
163k
    } else {
6804
52.9k
  if (ctxt->context->tmpNsList != NULL)
6805
52.9k
      xmlFree(ctxt->context->tmpNsList);
6806
52.9k
  ctxt->context->tmpNsList = NULL;
6807
52.9k
  return(NULL);
6808
52.9k
    }
6809
216k
}
6810
6811
/**
6812
 * Traversal function for the "attribute" direction
6813
 * TODO: support DTD inherited default attributes
6814
 *
6815
 * @param ctxt  the XPath Parser context
6816
 * @param cur  the current attribute in the traversal
6817
 * @returns the next element following that axis
6818
 */
6819
xmlNode *
6820
40.9k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6821
40.9k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6822
40.9k
    if (ctxt->context->node == NULL)
6823
0
  return(NULL);
6824
40.9k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6825
3
  return(NULL);
6826
40.9k
    if (cur == NULL) {
6827
20.0k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6828
0
      return(NULL);
6829
20.0k
        return((xmlNodePtr)ctxt->context->node->properties);
6830
20.0k
    }
6831
20.8k
    return((xmlNodePtr)cur->next);
6832
40.9k
}
6833
6834
/************************************************************************
6835
 *                  *
6836
 *    NodeTest Functions          *
6837
 *                  *
6838
 ************************************************************************/
6839
6840
#define IS_FUNCTION     200
6841
6842
6843
/************************************************************************
6844
 *                  *
6845
 *    Implicit tree core function library     *
6846
 *                  *
6847
 ************************************************************************/
6848
6849
/**
6850
 * Initialize the context to the root of the document
6851
 *
6852
 * @param ctxt  the XPath Parser context
6853
 */
6854
void
6855
6.08k
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6856
6.08k
    if ((ctxt == NULL) || (ctxt->context == NULL))
6857
0
  return;
6858
6.08k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6859
6.08k
                                            (xmlNodePtr) ctxt->context->doc));
6860
6.08k
}
6861
6862
/************************************************************************
6863
 *                  *
6864
 *    The explicit core function library      *
6865
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6866
 *                  *
6867
 ************************************************************************/
6868
6869
6870
/**
6871
 * Implement the last() XPath function
6872
 *    number last()
6873
 * The last function returns the number of nodes in the context node list.
6874
 *
6875
 * @param ctxt  the XPath Parser context
6876
 * @param nargs  the number of arguments
6877
 */
6878
void
6879
0
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6880
0
    CHECK_ARITY(0);
6881
0
    if (ctxt->context->contextSize >= 0) {
6882
0
  xmlXPathValuePush(ctxt,
6883
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6884
0
    } else {
6885
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6886
0
    }
6887
0
}
6888
6889
/**
6890
 * Implement the position() XPath function
6891
 *    number position()
6892
 * The position function returns the position of the context node in the
6893
 * context node list. The first position is 1, and so the last position
6894
 * will be equal to last().
6895
 *
6896
 * @param ctxt  the XPath Parser context
6897
 * @param nargs  the number of arguments
6898
 */
6899
void
6900
0
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6901
0
    CHECK_ARITY(0);
6902
0
    if (ctxt->context->proximityPosition >= 0) {
6903
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6904
0
            (double) ctxt->context->proximityPosition));
6905
0
    } else {
6906
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6907
0
    }
6908
0
}
6909
6910
/**
6911
 * Implement the count() XPath function
6912
 *    number count(node-set)
6913
 *
6914
 * @param ctxt  the XPath Parser context
6915
 * @param nargs  the number of arguments
6916
 */
6917
void
6918
0
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6919
0
    xmlXPathObjectPtr cur;
6920
6921
0
    CHECK_ARITY(1);
6922
0
    if ((ctxt->value == NULL) ||
6923
0
  ((ctxt->value->type != XPATH_NODESET) &&
6924
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
6925
0
  XP_ERROR(XPATH_INVALID_TYPE);
6926
0
    cur = xmlXPathValuePop(ctxt);
6927
6928
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
6929
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6930
0
    else
6931
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6932
0
      (double) cur->nodesetval->nodeNr));
6933
0
    xmlXPathReleaseObject(ctxt->context, cur);
6934
0
}
6935
6936
/**
6937
 * Selects elements by their unique ID.
6938
 *
6939
 * @param doc  the document
6940
 * @param ids  a whitespace separated list of IDs
6941
 * @returns a node-set of selected elements.
6942
 */
6943
static xmlNodeSetPtr
6944
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6945
0
    xmlNodeSetPtr ret;
6946
0
    const xmlChar *cur = ids;
6947
0
    xmlChar *ID;
6948
0
    xmlAttrPtr attr;
6949
0
    xmlNodePtr elem = NULL;
6950
6951
0
    if (ids == NULL) return(NULL);
6952
6953
0
    ret = xmlXPathNodeSetCreate(NULL);
6954
0
    if (ret == NULL)
6955
0
        return(ret);
6956
6957
0
    while (IS_BLANK_CH(*cur)) cur++;
6958
0
    while (*cur != 0) {
6959
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6960
0
      cur++;
6961
6962
0
        ID = xmlStrndup(ids, cur - ids);
6963
0
  if (ID == NULL) {
6964
0
            xmlXPathFreeNodeSet(ret);
6965
0
            return(NULL);
6966
0
        }
6967
        /*
6968
         * We used to check the fact that the value passed
6969
         * was an NCName, but this generated much troubles for
6970
         * me and Aleksey Sanin, people blatantly violated that
6971
         * constraint, like Visa3D spec.
6972
         * if (xmlValidateNCName(ID, 1) == 0)
6973
         */
6974
0
        attr = xmlGetID(doc, ID);
6975
0
        xmlFree(ID);
6976
0
        if (attr != NULL) {
6977
0
            if (attr->type == XML_ATTRIBUTE_NODE)
6978
0
                elem = attr->parent;
6979
0
            else if (attr->type == XML_ELEMENT_NODE)
6980
0
                elem = (xmlNodePtr) attr;
6981
0
            else
6982
0
                elem = NULL;
6983
0
            if (elem != NULL) {
6984
0
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
6985
0
                    xmlXPathFreeNodeSet(ret);
6986
0
                    return(NULL);
6987
0
                }
6988
0
            }
6989
0
        }
6990
6991
0
  while (IS_BLANK_CH(*cur)) cur++;
6992
0
  ids = cur;
6993
0
    }
6994
0
    return(ret);
6995
0
}
6996
6997
/**
6998
 * Implement the id() XPath function
6999
 *    node-set id(object)
7000
 * The id function selects elements by their unique ID
7001
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7002
 * then the result is the union of the result of applying id to the
7003
 * string value of each of the nodes in the argument node-set. When the
7004
 * argument to id is of any other type, the argument is converted to a
7005
 * string as if by a call to the string function; the string is split
7006
 * into a whitespace-separated list of tokens (whitespace is any sequence
7007
 * of characters matching the production S); the result is a node-set
7008
 * containing the elements in the same document as the context node that
7009
 * have a unique ID equal to any of the tokens in the list.
7010
 *
7011
 * @param ctxt  the XPath Parser context
7012
 * @param nargs  the number of arguments
7013
 */
7014
void
7015
0
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7016
0
    xmlChar *tokens;
7017
0
    xmlNodeSetPtr ret;
7018
0
    xmlXPathObjectPtr obj;
7019
7020
0
    CHECK_ARITY(1);
7021
0
    obj = xmlXPathValuePop(ctxt);
7022
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7023
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7024
0
  xmlNodeSetPtr ns;
7025
0
  int i;
7026
7027
0
  ret = xmlXPathNodeSetCreate(NULL);
7028
0
        if (ret == NULL)
7029
0
            xmlXPathPErrMemory(ctxt);
7030
7031
0
  if (obj->nodesetval != NULL) {
7032
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7033
0
    tokens =
7034
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7035
0
                if (tokens == NULL)
7036
0
                    xmlXPathPErrMemory(ctxt);
7037
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7038
0
                if (ns == NULL)
7039
0
                    xmlXPathPErrMemory(ctxt);
7040
0
    ret = xmlXPathNodeSetMerge(ret, ns);
7041
0
                if (ret == NULL)
7042
0
                    xmlXPathPErrMemory(ctxt);
7043
0
    xmlXPathFreeNodeSet(ns);
7044
0
    if (tokens != NULL)
7045
0
        xmlFree(tokens);
7046
0
      }
7047
0
  }
7048
0
  xmlXPathReleaseObject(ctxt->context, obj);
7049
0
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7050
0
  return;
7051
0
    }
7052
0
    tokens = xmlXPathCastToString(obj);
7053
0
    if (tokens == NULL)
7054
0
        xmlXPathPErrMemory(ctxt);
7055
0
    xmlXPathReleaseObject(ctxt->context, obj);
7056
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7057
0
    if (ret == NULL)
7058
0
        xmlXPathPErrMemory(ctxt);
7059
0
    xmlFree(tokens);
7060
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7061
0
}
7062
7063
/**
7064
 * Implement the local-name() XPath function
7065
 *    string local-name(node-set?)
7066
 * The local-name function returns a string containing the local part
7067
 * of the name of the node in the argument node-set that is first in
7068
 * document order. If the node-set is empty or the first node has no
7069
 * name, an empty string is returned. If the argument is omitted it
7070
 * defaults to the context node.
7071
 *
7072
 * @param ctxt  the XPath Parser context
7073
 * @param nargs  the number of arguments
7074
 */
7075
void
7076
0
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7077
0
    xmlXPathObjectPtr cur;
7078
7079
0
    if (ctxt == NULL) return;
7080
7081
0
    if (nargs == 0) {
7082
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7083
0
  nargs = 1;
7084
0
    }
7085
7086
0
    CHECK_ARITY(1);
7087
0
    if ((ctxt->value == NULL) ||
7088
0
  ((ctxt->value->type != XPATH_NODESET) &&
7089
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7090
0
  XP_ERROR(XPATH_INVALID_TYPE);
7091
0
    cur = xmlXPathValuePop(ctxt);
7092
7093
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7094
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7095
0
    } else {
7096
0
  int i = 0; /* Should be first in document order !!!!! */
7097
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7098
0
  case XML_ELEMENT_NODE:
7099
0
  case XML_ATTRIBUTE_NODE:
7100
0
  case XML_PI_NODE:
7101
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7102
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7103
0
      else
7104
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7105
0
      cur->nodesetval->nodeTab[i]->name));
7106
0
      break;
7107
0
  case XML_NAMESPACE_DECL:
7108
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7109
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7110
0
      break;
7111
0
  default:
7112
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7113
0
  }
7114
0
    }
7115
0
    xmlXPathReleaseObject(ctxt->context, cur);
7116
0
}
7117
7118
/**
7119
 * Implement the namespace-uri() XPath function
7120
 *    string namespace-uri(node-set?)
7121
 * The namespace-uri function returns a string containing the
7122
 * namespace URI of the expanded name of the node in the argument
7123
 * node-set that is first in document order. If the node-set is empty,
7124
 * the first node has no name, or the expanded name has no namespace
7125
 * URI, an empty string is returned. If the argument is omitted it
7126
 * defaults to the context node.
7127
 *
7128
 * @param ctxt  the XPath Parser context
7129
 * @param nargs  the number of arguments
7130
 */
7131
void
7132
1
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7133
1
    xmlXPathObjectPtr cur;
7134
7135
1
    if (ctxt == NULL) return;
7136
7137
1
    if (nargs == 0) {
7138
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7139
0
  nargs = 1;
7140
0
    }
7141
3
    CHECK_ARITY(1);
7142
3
    if ((ctxt->value == NULL) ||
7143
1
  ((ctxt->value->type != XPATH_NODESET) &&
7144
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7145
1
  XP_ERROR(XPATH_INVALID_TYPE);
7146
0
    cur = xmlXPathValuePop(ctxt);
7147
7148
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7149
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7150
0
    } else {
7151
0
  int i = 0; /* Should be first in document order !!!!! */
7152
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7153
0
  case XML_ELEMENT_NODE:
7154
0
  case XML_ATTRIBUTE_NODE:
7155
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7156
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7157
0
      else
7158
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7159
0
        cur->nodesetval->nodeTab[i]->ns->href));
7160
0
      break;
7161
0
  default:
7162
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7163
0
  }
7164
0
    }
7165
0
    xmlXPathReleaseObject(ctxt->context, cur);
7166
0
}
7167
7168
/**
7169
 * Implement the name() XPath function
7170
 *    string name(node-set?)
7171
 * The name function returns a string containing a QName representing
7172
 * the name of the node in the argument node-set that is first in document
7173
 * order. The QName must represent the name with respect to the namespace
7174
 * declarations in effect on the node whose name is being represented.
7175
 * Typically, this will be the form in which the name occurred in the XML
7176
 * source. This need not be the case if there are namespace declarations
7177
 * in effect on the node that associate multiple prefixes with the same
7178
 * namespace. However, an implementation may include information about
7179
 * the original prefix in its representation of nodes; in this case, an
7180
 * implementation can ensure that the returned string is always the same
7181
 * as the QName used in the XML source. If the argument it omitted it
7182
 * defaults to the context node.
7183
 * Libxml keep the original prefix so the "real qualified name" used is
7184
 * returned.
7185
 *
7186
 * @param ctxt  the XPath Parser context
7187
 * @param nargs  the number of arguments
7188
 */
7189
static void
7190
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7191
0
{
7192
0
    xmlXPathObjectPtr cur;
7193
7194
0
    if (nargs == 0) {
7195
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7196
0
        nargs = 1;
7197
0
    }
7198
7199
0
    CHECK_ARITY(1);
7200
0
    if ((ctxt->value == NULL) ||
7201
0
        ((ctxt->value->type != XPATH_NODESET) &&
7202
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
7203
0
        XP_ERROR(XPATH_INVALID_TYPE);
7204
0
    cur = xmlXPathValuePop(ctxt);
7205
7206
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7207
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7208
0
    } else {
7209
0
        int i = 0;              /* Should be first in document order !!!!! */
7210
7211
0
        switch (cur->nodesetval->nodeTab[i]->type) {
7212
0
            case XML_ELEMENT_NODE:
7213
0
            case XML_ATTRIBUTE_NODE:
7214
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7215
0
        xmlXPathValuePush(ctxt,
7216
0
      xmlXPathCacheNewCString(ctxt, ""));
7217
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7218
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7219
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7220
0
          cur->nodesetval->nodeTab[i]->name));
7221
0
    } else {
7222
0
        xmlChar *fullname;
7223
7224
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7225
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
7226
0
             NULL, 0);
7227
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7228
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7229
0
        if (fullname == NULL)
7230
0
                        xmlXPathPErrMemory(ctxt);
7231
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7232
0
                }
7233
0
                break;
7234
0
            default:
7235
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7236
0
        cur->nodesetval->nodeTab[i]));
7237
0
                xmlXPathLocalNameFunction(ctxt, 1);
7238
0
        }
7239
0
    }
7240
0
    xmlXPathReleaseObject(ctxt->context, cur);
7241
0
}
7242
7243
7244
/**
7245
 * Implement the string() XPath function
7246
 *    string string(object?)
7247
 * The string function converts an object to a string as follows:
7248
 *    - A node-set is converted to a string by returning the value of
7249
 *      the node in the node-set that is first in document order.
7250
 *      If the node-set is empty, an empty string is returned.
7251
 *    - A number is converted to a string as follows
7252
 *      + NaN is converted to the string NaN
7253
 *      + positive zero is converted to the string 0
7254
 *      + negative zero is converted to the string 0
7255
 *      + positive infinity is converted to the string Infinity
7256
 *      + negative infinity is converted to the string -Infinity
7257
 *      + if the number is an integer, the number is represented in
7258
 *        decimal form as a Number with no decimal point and no leading
7259
 *        zeros, preceded by a minus sign (-) if the number is negative
7260
 *      + otherwise, the number is represented in decimal form as a
7261
 *        Number including a decimal point with at least one digit
7262
 *        before the decimal point and at least one digit after the
7263
 *        decimal point, preceded by a minus sign (-) if the number
7264
 *        is negative; there must be no leading zeros before the decimal
7265
 *        point apart possibly from the one required digit immediately
7266
 *        before the decimal point; beyond the one required digit
7267
 *        after the decimal point there must be as many, but only as
7268
 *        many, more digits as are needed to uniquely distinguish the
7269
 *        number from all other IEEE 754 numeric values.
7270
 *    - The boolean false value is converted to the string false.
7271
 *      The boolean true value is converted to the string true.
7272
 *
7273
 * If the argument is omitted, it defaults to a node-set with the
7274
 * context node as its only member.
7275
 *
7276
 * @param ctxt  the XPath Parser context
7277
 * @param nargs  the number of arguments
7278
 */
7279
void
7280
1.92M
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7281
1.92M
    xmlXPathObjectPtr cur;
7282
1.92M
    xmlChar *stringval;
7283
7284
1.92M
    if (ctxt == NULL) return;
7285
1.92M
    if (nargs == 0) {
7286
0
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7287
0
        if (stringval == NULL)
7288
0
            xmlXPathPErrMemory(ctxt);
7289
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7290
0
  return;
7291
0
    }
7292
7293
7.68M
    CHECK_ARITY(1);
7294
7.68M
    cur = xmlXPathValuePop(ctxt);
7295
7.68M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7296
1.92M
    if (cur->type != XPATH_STRING) {
7297
961k
        stringval = xmlXPathCastToString(cur);
7298
961k
        if (stringval == NULL)
7299
0
            xmlXPathPErrMemory(ctxt);
7300
961k
        xmlXPathReleaseObject(ctxt->context, cur);
7301
961k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7302
961k
    }
7303
1.92M
    xmlXPathValuePush(ctxt, cur);
7304
1.92M
}
7305
7306
/**
7307
 * Implement the string-length() XPath function
7308
 *    number string-length(string?)
7309
 * The string-length returns the number of characters in the string
7310
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7311
 * the context node converted to a string, in other words the value
7312
 * of the context node.
7313
 *
7314
 * @param ctxt  the XPath Parser context
7315
 * @param nargs  the number of arguments
7316
 */
7317
void
7318
0
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7319
0
    xmlXPathObjectPtr cur;
7320
7321
0
    if (nargs == 0) {
7322
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7323
0
      return;
7324
0
  if (ctxt->context->node == NULL) {
7325
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7326
0
  } else {
7327
0
      xmlChar *content;
7328
7329
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7330
0
            if (content == NULL)
7331
0
                xmlXPathPErrMemory(ctxt);
7332
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7333
0
    xmlUTF8Strlen(content)));
7334
0
      xmlFree(content);
7335
0
  }
7336
0
  return;
7337
0
    }
7338
0
    CHECK_ARITY(1);
7339
0
    CAST_TO_STRING;
7340
0
    CHECK_TYPE(XPATH_STRING);
7341
0
    cur = xmlXPathValuePop(ctxt);
7342
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7343
0
  xmlUTF8Strlen(cur->stringval)));
7344
0
    xmlXPathReleaseObject(ctxt->context, cur);
7345
0
}
7346
7347
/**
7348
 * Implement the concat() XPath function
7349
 *    string concat(string, string, string*)
7350
 * The concat function returns the concatenation of its arguments.
7351
 *
7352
 * @param ctxt  the XPath Parser context
7353
 * @param nargs  the number of arguments
7354
 */
7355
void
7356
0
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7357
0
    xmlXPathObjectPtr cur, newobj;
7358
0
    xmlChar *tmp;
7359
7360
0
    if (ctxt == NULL) return;
7361
0
    if (nargs < 2) {
7362
0
  CHECK_ARITY(2);
7363
0
    }
7364
7365
0
    CAST_TO_STRING;
7366
0
    cur = xmlXPathValuePop(ctxt);
7367
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7368
0
  xmlXPathReleaseObject(ctxt->context, cur);
7369
0
  return;
7370
0
    }
7371
0
    nargs--;
7372
7373
0
    while (nargs > 0) {
7374
0
  CAST_TO_STRING;
7375
0
  newobj = xmlXPathValuePop(ctxt);
7376
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7377
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7378
0
      xmlXPathReleaseObject(ctxt->context, cur);
7379
0
      XP_ERROR(XPATH_INVALID_TYPE);
7380
0
  }
7381
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7382
0
        if (tmp == NULL)
7383
0
            xmlXPathPErrMemory(ctxt);
7384
0
  newobj->stringval = cur->stringval;
7385
0
  cur->stringval = tmp;
7386
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7387
0
  nargs--;
7388
0
    }
7389
0
    xmlXPathValuePush(ctxt, cur);
7390
0
}
7391
7392
/**
7393
 * Implement the contains() XPath function
7394
 *    boolean contains(string, string)
7395
 * The contains function returns true if the first argument string
7396
 * contains the second argument string, and otherwise returns false.
7397
 *
7398
 * @param ctxt  the XPath Parser context
7399
 * @param nargs  the number of arguments
7400
 */
7401
void
7402
33
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7403
33
    xmlXPathObjectPtr hay, needle;
7404
7405
99
    CHECK_ARITY(2);
7406
99
    CAST_TO_STRING;
7407
99
    CHECK_TYPE(XPATH_STRING);
7408
33
    needle = xmlXPathValuePop(ctxt);
7409
33
    CAST_TO_STRING;
7410
33
    hay = xmlXPathValuePop(ctxt);
7411
7412
33
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7413
0
  xmlXPathReleaseObject(ctxt->context, hay);
7414
0
  xmlXPathReleaseObject(ctxt->context, needle);
7415
0
  XP_ERROR(XPATH_INVALID_TYPE);
7416
0
    }
7417
33
    if (xmlStrstr(hay->stringval, needle->stringval))
7418
18
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7419
15
    else
7420
15
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7421
33
    xmlXPathReleaseObject(ctxt->context, hay);
7422
33
    xmlXPathReleaseObject(ctxt->context, needle);
7423
33
}
7424
7425
/**
7426
 * Implement the starts-with() XPath function
7427
 *    boolean starts-with(string, string)
7428
 * The starts-with function returns true if the first argument string
7429
 * starts with the second argument string, and otherwise returns false.
7430
 *
7431
 * @param ctxt  the XPath Parser context
7432
 * @param nargs  the number of arguments
7433
 */
7434
void
7435
672
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7436
672
    xmlXPathObjectPtr hay, needle;
7437
672
    int n;
7438
7439
2.01k
    CHECK_ARITY(2);
7440
2.01k
    CAST_TO_STRING;
7441
2.01k
    CHECK_TYPE(XPATH_STRING);
7442
672
    needle = xmlXPathValuePop(ctxt);
7443
672
    CAST_TO_STRING;
7444
672
    hay = xmlXPathValuePop(ctxt);
7445
7446
672
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7447
0
  xmlXPathReleaseObject(ctxt->context, hay);
7448
0
  xmlXPathReleaseObject(ctxt->context, needle);
7449
0
  XP_ERROR(XPATH_INVALID_TYPE);
7450
0
    }
7451
672
    n = xmlStrlen(needle->stringval);
7452
672
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7453
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7454
672
    else
7455
672
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7456
672
    xmlXPathReleaseObject(ctxt->context, hay);
7457
672
    xmlXPathReleaseObject(ctxt->context, needle);
7458
672
}
7459
7460
/**
7461
 * Implement the substring() XPath function
7462
 *    string substring(string, number, number?)
7463
 * The substring function returns the substring of the first argument
7464
 * starting at the position specified in the second argument with
7465
 * length specified in the third argument. For example,
7466
 * substring("12345",2,3) returns "234". If the third argument is not
7467
 * specified, it returns the substring starting at the position specified
7468
 * in the second argument and continuing to the end of the string. For
7469
 * example, substring("12345",2) returns "2345".  More precisely, each
7470
 * character in the string (see [3.6 Strings]) is considered to have a
7471
 * numeric position: the position of the first character is 1, the position
7472
 * of the second character is 2 and so on. The returned substring contains
7473
 * those characters for which the position of the character is greater than
7474
 * or equal to the second argument and, if the third argument is specified,
7475
 * less than the sum of the second and third arguments; the comparisons
7476
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7477
 *  - substring("12345", 1.5, 2.6) returns "234"
7478
 *  - substring("12345", 0, 3) returns "12"
7479
 *  - substring("12345", 0 div 0, 3) returns ""
7480
 *  - substring("12345", 1, 0 div 0) returns ""
7481
 *  - substring("12345", -42, 1 div 0) returns "12345"
7482
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
7483
 *
7484
 * @param ctxt  the XPath Parser context
7485
 * @param nargs  the number of arguments
7486
 */
7487
void
7488
0
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7489
0
    xmlXPathObjectPtr str, start, len;
7490
0
    double le=0, in;
7491
0
    int i = 1, j = INT_MAX;
7492
7493
0
    if (nargs < 2) {
7494
0
  CHECK_ARITY(2);
7495
0
    }
7496
0
    if (nargs > 3) {
7497
0
  CHECK_ARITY(3);
7498
0
    }
7499
    /*
7500
     * take care of possible last (position) argument
7501
    */
7502
0
    if (nargs == 3) {
7503
0
  CAST_TO_NUMBER;
7504
0
  CHECK_TYPE(XPATH_NUMBER);
7505
0
  len = xmlXPathValuePop(ctxt);
7506
0
  le = len->floatval;
7507
0
  xmlXPathReleaseObject(ctxt->context, len);
7508
0
    }
7509
7510
0
    CAST_TO_NUMBER;
7511
0
    CHECK_TYPE(XPATH_NUMBER);
7512
0
    start = xmlXPathValuePop(ctxt);
7513
0
    in = start->floatval;
7514
0
    xmlXPathReleaseObject(ctxt->context, start);
7515
0
    CAST_TO_STRING;
7516
0
    CHECK_TYPE(XPATH_STRING);
7517
0
    str = xmlXPathValuePop(ctxt);
7518
7519
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7520
0
        i = INT_MAX;
7521
0
    } else if (in >= 1.0) {
7522
0
        i = (int)in;
7523
0
        if (in - floor(in) >= 0.5)
7524
0
            i += 1;
7525
0
    }
7526
7527
0
    if (nargs == 3) {
7528
0
        double rin, rle, end;
7529
7530
0
        rin = floor(in);
7531
0
        if (in - rin >= 0.5)
7532
0
            rin += 1.0;
7533
7534
0
        rle = floor(le);
7535
0
        if (le - rle >= 0.5)
7536
0
            rle += 1.0;
7537
7538
0
        end = rin + rle;
7539
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7540
0
            j = 1;
7541
0
        } else if (end < INT_MAX) {
7542
0
            j = (int)end;
7543
0
        }
7544
0
    }
7545
7546
0
    i -= 1;
7547
0
    j -= 1;
7548
7549
0
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7550
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7551
0
        if (ret == NULL)
7552
0
            xmlXPathPErrMemory(ctxt);
7553
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7554
0
  xmlFree(ret);
7555
0
    } else {
7556
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7557
0
    }
7558
7559
0
    xmlXPathReleaseObject(ctxt->context, str);
7560
0
}
7561
7562
/**
7563
 * Implement the substring-before() XPath function
7564
 *    string substring-before(string, string)
7565
 * The substring-before function returns the substring of the first
7566
 * argument string that precedes the first occurrence of the second
7567
 * argument string in the first argument string, or the empty string
7568
 * if the first argument string does not contain the second argument
7569
 * string. For example, substring-before("1999/04/01","/") returns 1999.
7570
 *
7571
 * @param ctxt  the XPath Parser context
7572
 * @param nargs  the number of arguments
7573
 */
7574
void
7575
16
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7576
16
    xmlXPathObjectPtr str = NULL;
7577
16
    xmlXPathObjectPtr find = NULL;
7578
16
    const xmlChar *point;
7579
16
    xmlChar *result;
7580
7581
48
    CHECK_ARITY(2);
7582
48
    CAST_TO_STRING;
7583
48
    find = xmlXPathValuePop(ctxt);
7584
48
    CAST_TO_STRING;
7585
48
    str = xmlXPathValuePop(ctxt);
7586
48
    if (ctxt->error != 0)
7587
0
        goto error;
7588
7589
16
    point = xmlStrstr(str->stringval, find->stringval);
7590
16
    if (point == NULL) {
7591
0
        result = xmlStrdup(BAD_CAST "");
7592
16
    } else {
7593
16
        result = xmlStrndup(str->stringval, point - str->stringval);
7594
16
    }
7595
16
    if (result == NULL) {
7596
0
        xmlXPathPErrMemory(ctxt);
7597
0
        goto error;
7598
0
    }
7599
16
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7600
7601
16
error:
7602
16
    xmlXPathReleaseObject(ctxt->context, str);
7603
16
    xmlXPathReleaseObject(ctxt->context, find);
7604
16
}
7605
7606
/**
7607
 * Implement the substring-after() XPath function
7608
 *    string substring-after(string, string)
7609
 * The substring-after function returns the substring of the first
7610
 * argument string that follows the first occurrence of the second
7611
 * argument string in the first argument string, or the empty string
7612
 * if the first argument string does not contain the second argument
7613
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7614
 * and substring-after("1999/04/01","19") returns 99/04/01.
7615
 *
7616
 * @param ctxt  the XPath Parser context
7617
 * @param nargs  the number of arguments
7618
 */
7619
void
7620
0
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7621
0
    xmlXPathObjectPtr str = NULL;
7622
0
    xmlXPathObjectPtr find = NULL;
7623
0
    const xmlChar *point;
7624
0
    xmlChar *result;
7625
7626
0
    CHECK_ARITY(2);
7627
0
    CAST_TO_STRING;
7628
0
    find = xmlXPathValuePop(ctxt);
7629
0
    CAST_TO_STRING;
7630
0
    str = xmlXPathValuePop(ctxt);
7631
0
    if (ctxt->error != 0)
7632
0
        goto error;
7633
7634
0
    point = xmlStrstr(str->stringval, find->stringval);
7635
0
    if (point == NULL) {
7636
0
        result = xmlStrdup(BAD_CAST "");
7637
0
    } else {
7638
0
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7639
0
    }
7640
0
    if (result == NULL) {
7641
0
        xmlXPathPErrMemory(ctxt);
7642
0
        goto error;
7643
0
    }
7644
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7645
7646
0
error:
7647
0
    xmlXPathReleaseObject(ctxt->context, str);
7648
0
    xmlXPathReleaseObject(ctxt->context, find);
7649
0
}
7650
7651
/**
7652
 * Implement the normalize-space() XPath function
7653
 *    string normalize-space(string?)
7654
 * The normalize-space function returns the argument string with white
7655
 * space normalized by stripping leading and trailing whitespace
7656
 * and replacing sequences of whitespace characters by a single
7657
 * space. Whitespace characters are the same allowed by the S production
7658
 * in XML. If the argument is omitted, it defaults to the context
7659
 * node converted to a string, in other words the value of the context node.
7660
 *
7661
 * @param ctxt  the XPath Parser context
7662
 * @param nargs  the number of arguments
7663
 */
7664
void
7665
0
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7666
0
    xmlChar *source, *target;
7667
0
    int blank;
7668
7669
0
    if (ctxt == NULL) return;
7670
0
    if (nargs == 0) {
7671
        /* Use current context node */
7672
0
        source = xmlXPathCastNodeToString(ctxt->context->node);
7673
0
        if (source == NULL)
7674
0
            xmlXPathPErrMemory(ctxt);
7675
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7676
0
        nargs = 1;
7677
0
    }
7678
7679
0
    CHECK_ARITY(1);
7680
0
    CAST_TO_STRING;
7681
0
    CHECK_TYPE(XPATH_STRING);
7682
0
    source = ctxt->value->stringval;
7683
0
    if (source == NULL)
7684
0
        return;
7685
0
    target = source;
7686
7687
    /* Skip leading whitespaces */
7688
0
    while (IS_BLANK_CH(*source))
7689
0
        source++;
7690
7691
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7692
0
    blank = 0;
7693
0
    while (*source) {
7694
0
        if (IS_BLANK_CH(*source)) {
7695
0
      blank = 1;
7696
0
        } else {
7697
0
            if (blank) {
7698
0
                *target++ = 0x20;
7699
0
                blank = 0;
7700
0
            }
7701
0
            *target++ = *source;
7702
0
        }
7703
0
        source++;
7704
0
    }
7705
0
    *target = 0;
7706
0
}
7707
7708
/**
7709
 * Implement the translate() XPath function
7710
 *    string translate(string, string, string)
7711
 * The translate function returns the first argument string with
7712
 * occurrences of characters in the second argument string replaced
7713
 * by the character at the corresponding position in the third argument
7714
 * string. For example, translate("bar","abc","ABC") returns the string
7715
 * BAr. If there is a character in the second argument string with no
7716
 * character at a corresponding position in the third argument string
7717
 * (because the second argument string is longer than the third argument
7718
 * string), then occurrences of that character in the first argument
7719
 * string are removed. For example,
7720
 * translate("--aaa--","abc-","ABC") returns "AAA".
7721
 * If a character occurs more than once in second
7722
 * argument string, then the first occurrence determines the replacement
7723
 * character. If the third argument string is longer than the second
7724
 * argument string, then excess characters are ignored.
7725
 *
7726
 * @param ctxt  the XPath Parser context
7727
 * @param nargs  the number of arguments
7728
 */
7729
void
7730
44
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7731
44
    xmlXPathObjectPtr str = NULL;
7732
44
    xmlXPathObjectPtr from = NULL;
7733
44
    xmlXPathObjectPtr to = NULL;
7734
44
    xmlBufPtr target;
7735
44
    int offset, max;
7736
44
    int ch;
7737
44
    const xmlChar *point;
7738
44
    xmlChar *cptr, *content;
7739
7740
132
    CHECK_ARITY(3);
7741
7742
132
    CAST_TO_STRING;
7743
132
    to = xmlXPathValuePop(ctxt);
7744
132
    CAST_TO_STRING;
7745
132
    from = xmlXPathValuePop(ctxt);
7746
132
    CAST_TO_STRING;
7747
132
    str = xmlXPathValuePop(ctxt);
7748
132
    if (ctxt->error != 0)
7749
0
        goto error;
7750
7751
    /*
7752
     * Account for quadratic runtime
7753
     */
7754
44
    if (ctxt->context->opLimit != 0) {
7755
44
        unsigned long f1 = xmlStrlen(from->stringval);
7756
44
        unsigned long f2 = xmlStrlen(str->stringval);
7757
7758
44
        if ((f1 > 0) && (f2 > 0)) {
7759
44
            unsigned long p;
7760
7761
44
            f1 = f1 / 10 + 1;
7762
44
            f2 = f2 / 10 + 1;
7763
44
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7764
44
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7765
2
                goto error;
7766
44
        }
7767
44
    }
7768
7769
42
    target = xmlBufCreate(50);
7770
42
    if (target == NULL) {
7771
0
        xmlXPathPErrMemory(ctxt);
7772
0
        goto error;
7773
0
    }
7774
7775
42
    max = xmlUTF8Strlen(to->stringval);
7776
168
    for (cptr = str->stringval; (ch=*cptr); ) {
7777
126
        offset = xmlUTF8Strloc(from->stringval, cptr);
7778
126
        if (offset >= 0) {
7779
126
            if (offset < max) {
7780
120
                point = xmlUTF8Strpos(to->stringval, offset);
7781
120
                if (point)
7782
120
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7783
120
            }
7784
126
        } else
7785
0
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7786
7787
        /* Step to next character in input */
7788
126
        cptr++;
7789
126
        if ( ch & 0x80 ) {
7790
            /* if not simple ascii, verify proper format */
7791
0
            if ( (ch & 0xc0) != 0xc0 ) {
7792
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7793
0
                break;
7794
0
            }
7795
            /* then skip over remaining bytes for this char */
7796
0
            while ( (ch <<= 1) & 0x80 )
7797
0
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7798
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7799
0
                    break;
7800
0
                }
7801
0
            if (ch & 0x80) /* must have had error encountered */
7802
0
                break;
7803
0
        }
7804
126
    }
7805
7806
42
    content = xmlBufDetach(target);
7807
42
    if (content == NULL)
7808
0
        xmlXPathPErrMemory(ctxt);
7809
42
    else
7810
42
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7811
42
    xmlBufFree(target);
7812
44
error:
7813
44
    xmlXPathReleaseObject(ctxt->context, str);
7814
44
    xmlXPathReleaseObject(ctxt->context, from);
7815
44
    xmlXPathReleaseObject(ctxt->context, to);
7816
44
}
7817
7818
/**
7819
 * Implement the boolean() XPath function
7820
 *    boolean boolean(object)
7821
 * The boolean function converts its argument to a boolean as follows:
7822
 *    - a number is true if and only if it is neither positive or
7823
 *      negative zero nor NaN
7824
 *    - a node-set is true if and only if it is non-empty
7825
 *    - a string is true if and only if its length is non-zero
7826
 *
7827
 * @param ctxt  the XPath Parser context
7828
 * @param nargs  the number of arguments
7829
 */
7830
void
7831
263
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7832
263
    xmlXPathObjectPtr cur;
7833
7834
789
    CHECK_ARITY(1);
7835
789
    cur = xmlXPathValuePop(ctxt);
7836
789
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7837
263
    if (cur->type != XPATH_BOOLEAN) {
7838
230
        int boolval = xmlXPathCastToBoolean(cur);
7839
7840
230
        xmlXPathReleaseObject(ctxt->context, cur);
7841
230
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7842
230
    }
7843
263
    xmlXPathValuePush(ctxt, cur);
7844
263
}
7845
7846
/**
7847
 * Implement the not() XPath function
7848
 *    boolean not(boolean)
7849
 * The not function returns true if its argument is false,
7850
 * and false otherwise.
7851
 *
7852
 * @param ctxt  the XPath Parser context
7853
 * @param nargs  the number of arguments
7854
 */
7855
void
7856
0
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7857
0
    CHECK_ARITY(1);
7858
0
    CAST_TO_BOOLEAN;
7859
0
    CHECK_TYPE(XPATH_BOOLEAN);
7860
0
    ctxt->value->boolval = ! ctxt->value->boolval;
7861
0
}
7862
7863
/**
7864
 * Implement the true() XPath function
7865
 *    boolean true()
7866
 *
7867
 * @param ctxt  the XPath Parser context
7868
 * @param nargs  the number of arguments
7869
 */
7870
void
7871
0
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7872
0
    CHECK_ARITY(0);
7873
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7874
0
}
7875
7876
/**
7877
 * Implement the false() XPath function
7878
 *    boolean false()
7879
 *
7880
 * @param ctxt  the XPath Parser context
7881
 * @param nargs  the number of arguments
7882
 */
7883
void
7884
0
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7885
0
    CHECK_ARITY(0);
7886
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7887
0
}
7888
7889
/**
7890
 * Implement the lang() XPath function
7891
 *    boolean lang(string)
7892
 * The lang function returns true or false depending on whether the
7893
 * language of the context node as specified by xml:lang attributes
7894
 * is the same as or is a sublanguage of the language specified by
7895
 * the argument string. The language of the context node is determined
7896
 * by the value of the xml:lang attribute on the context node, or, if
7897
 * the context node has no xml:lang attribute, by the value of the
7898
 * xml:lang attribute on the nearest ancestor of the context node that
7899
 * has an xml:lang attribute. If there is no such attribute, then
7900
 * lang returns false. If there is such an attribute, then lang returns
7901
 * true if the attribute value is equal to the argument ignoring case,
7902
 * or if there is some suffix starting with - such that the attribute
7903
 * value is equal to the argument ignoring that suffix of the attribute
7904
 * value and ignoring case.
7905
 *
7906
 * @param ctxt  the XPath Parser context
7907
 * @param nargs  the number of arguments
7908
 */
7909
void
7910
0
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7911
0
    xmlXPathObjectPtr val;
7912
0
    xmlNodePtr cur;
7913
0
    xmlChar *theLang;
7914
0
    const xmlChar *lang;
7915
0
    int ret = 0;
7916
0
    int i;
7917
7918
0
    CHECK_ARITY(1);
7919
0
    CAST_TO_STRING;
7920
0
    CHECK_TYPE(XPATH_STRING);
7921
0
    val = xmlXPathValuePop(ctxt);
7922
0
    lang = val->stringval;
7923
0
    cur = ctxt->context->node;
7924
0
    while (cur != NULL) {
7925
0
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7926
0
                                &theLang) < 0)
7927
0
            xmlXPathPErrMemory(ctxt);
7928
0
        if (theLang != NULL)
7929
0
            break;
7930
0
        cur = cur->parent;
7931
0
    }
7932
0
    if ((theLang != NULL) && (lang != NULL)) {
7933
0
        for (i = 0;lang[i] != 0;i++)
7934
0
            if (toupper(lang[i]) != toupper(theLang[i]))
7935
0
                goto not_equal;
7936
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7937
0
            ret = 1;
7938
0
    }
7939
0
not_equal:
7940
0
    if (theLang != NULL)
7941
0
  xmlFree((void *)theLang);
7942
7943
0
    xmlXPathReleaseObject(ctxt->context, val);
7944
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7945
0
}
7946
7947
/**
7948
 * Implement the number() XPath function
7949
 *    number number(object?)
7950
 *
7951
 * @param ctxt  the XPath Parser context
7952
 * @param nargs  the number of arguments
7953
 */
7954
void
7955
302k
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7956
302k
    xmlXPathObjectPtr cur;
7957
302k
    double res;
7958
7959
302k
    if (ctxt == NULL) return;
7960
302k
    if (nargs == 0) {
7961
0
  if (ctxt->context->node == NULL) {
7962
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7963
0
  } else {
7964
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7965
0
            if (content == NULL)
7966
0
                xmlXPathPErrMemory(ctxt);
7967
7968
0
      res = xmlXPathStringEvalNumber(content);
7969
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
7970
0
      xmlFree(content);
7971
0
  }
7972
0
  return;
7973
0
    }
7974
7975
1.21M
    CHECK_ARITY(1);
7976
1.21M
    cur = xmlXPathValuePop(ctxt);
7977
1.21M
    if (cur->type != XPATH_NUMBER) {
7978
302k
        double floatval;
7979
7980
302k
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
7981
302k
        xmlXPathReleaseObject(ctxt->context, cur);
7982
302k
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
7983
302k
    }
7984
1.21M
    xmlXPathValuePush(ctxt, cur);
7985
1.21M
}
7986
7987
/**
7988
 * Implement the sum() XPath function
7989
 *    number sum(node-set)
7990
 * The sum function returns the sum of the values of the nodes in
7991
 * the argument node-set.
7992
 *
7993
 * @param ctxt  the XPath Parser context
7994
 * @param nargs  the number of arguments
7995
 */
7996
void
7997
0
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
7998
0
    xmlXPathObjectPtr cur;
7999
0
    int i;
8000
0
    double res = 0.0;
8001
8002
0
    CHECK_ARITY(1);
8003
0
    if ((ctxt->value == NULL) ||
8004
0
  ((ctxt->value->type != XPATH_NODESET) &&
8005
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8006
0
  XP_ERROR(XPATH_INVALID_TYPE);
8007
0
    cur = xmlXPathValuePop(ctxt);
8008
8009
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8010
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8011
0
      res += xmlXPathNodeToNumberInternal(ctxt,
8012
0
                                                cur->nodesetval->nodeTab[i]);
8013
0
  }
8014
0
    }
8015
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8016
0
    xmlXPathReleaseObject(ctxt->context, cur);
8017
0
}
8018
8019
/**
8020
 * Implement the floor() XPath function
8021
 *    number floor(number)
8022
 * The floor function returns the largest (closest to positive infinity)
8023
 * number that is not greater than the argument and that is an integer.
8024
 *
8025
 * @param ctxt  the XPath Parser context
8026
 * @param nargs  the number of arguments
8027
 */
8028
void
8029
0
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
0
    CHECK_ARITY(1);
8031
0
    CAST_TO_NUMBER;
8032
0
    CHECK_TYPE(XPATH_NUMBER);
8033
8034
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
8035
0
}
8036
8037
/**
8038
 * Implement the ceiling() XPath function
8039
 *    number ceiling(number)
8040
 * The ceiling function returns the smallest (closest to negative infinity)
8041
 * number that is not less than the argument and that is an integer.
8042
 *
8043
 * @param ctxt  the XPath Parser context
8044
 * @param nargs  the number of arguments
8045
 */
8046
void
8047
0
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8048
0
    CHECK_ARITY(1);
8049
0
    CAST_TO_NUMBER;
8050
0
    CHECK_TYPE(XPATH_NUMBER);
8051
8052
#ifdef _AIX
8053
    /* Work around buggy ceil() function on AIX */
8054
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8055
#else
8056
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8057
0
#endif
8058
0
}
8059
8060
/**
8061
 * Implement the round() XPath function
8062
 *    number round(number)
8063
 * The round function returns the number that is closest to the
8064
 * argument and that is an integer. If there are two such numbers,
8065
 * then the one that is closest to positive infinity is returned.
8066
 *
8067
 * @param ctxt  the XPath Parser context
8068
 * @param nargs  the number of arguments
8069
 */
8070
void
8071
0
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8072
0
    double f;
8073
8074
0
    CHECK_ARITY(1);
8075
0
    CAST_TO_NUMBER;
8076
0
    CHECK_TYPE(XPATH_NUMBER);
8077
8078
0
    f = ctxt->value->floatval;
8079
8080
0
    if ((f >= -0.5) && (f < 0.5)) {
8081
        /* Handles negative zero. */
8082
0
        ctxt->value->floatval *= 0.0;
8083
0
    }
8084
0
    else {
8085
0
        double rounded = floor(f);
8086
0
        if (f - rounded >= 0.5)
8087
0
            rounded += 1.0;
8088
0
        ctxt->value->floatval = rounded;
8089
0
    }
8090
0
}
8091
8092
/************************************************************************
8093
 *                  *
8094
 *      The Parser          *
8095
 *                  *
8096
 ************************************************************************/
8097
8098
/*
8099
 * a few forward declarations since we use a recursive call based
8100
 * implementation.
8101
 */
8102
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8103
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8104
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8105
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8106
8107
/**
8108
 * Parse an XML non-colonized name.
8109
 *
8110
 * @param ctxt  the XPath Parser context
8111
 * @returns the nc name or NULL
8112
 */
8113
8114
xmlChar *
8115
285k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8116
285k
    const xmlChar *end;
8117
285k
    xmlChar *ret;
8118
8119
285k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8120
8121
285k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8122
285k
    if (end == NULL) {
8123
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8124
0
    }
8125
285k
    if (end == ctxt->cur)
8126
83
        return(NULL);
8127
8128
285k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8129
285k
    if (ret == NULL)
8130
1
        xmlXPathPErrMemory(ctxt);
8131
285k
    ctxt->cur = end;
8132
285k
    return(ret);
8133
285k
}
8134
8135
8136
/**
8137
 * Parse an XML qualified name
8138
 *
8139
 * @param ctxt  the XPath Parser context
8140
 * @param prefix  a xmlChar **
8141
 * @returns the function returns the local part, and prefix is updated
8142
 *   to get the Prefix if any.
8143
 */
8144
8145
static xmlChar *
8146
358
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8147
358
    xmlChar *ret = NULL;
8148
8149
358
    *prefix = NULL;
8150
358
    ret = xmlXPathParseNCName(ctxt);
8151
358
    if (ret && CUR == ':') {
8152
135
        *prefix = ret;
8153
135
  NEXT;
8154
135
  ret = xmlXPathParseNCName(ctxt);
8155
135
    }
8156
358
    return(ret);
8157
358
}
8158
8159
/**
8160
 * parse an XML name
8161
 *
8162
 * @param ctxt  the XPath Parser context
8163
 * @returns the name or NULL
8164
 */
8165
8166
xmlChar *
8167
10
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8168
10
    const xmlChar *end;
8169
10
    xmlChar *ret;
8170
8171
10
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8172
8173
10
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8174
10
    if (end == NULL) {
8175
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8176
0
    }
8177
10
    if (end == ctxt->cur)
8178
0
        return(NULL);
8179
8180
10
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8181
10
    if (ret == NULL)
8182
0
        xmlXPathPErrMemory(ctxt);
8183
10
    ctxt->cur = end;
8184
10
    return(ret);
8185
10
}
8186
8187
237
#define MAX_FRAC 20
8188
8189
/**
8190
 *  [30a]  Float  ::= Number ('e' Digits?)?
8191
 *
8192
 *  [30]   Number ::=   Digits ('.' Digits?)?
8193
 *                    | '.' Digits
8194
 *  [31]   Digits ::=   [0-9]+
8195
 *
8196
 * Compile a Number in the string
8197
 * In complement of the Number expression, this function also handles
8198
 * negative values : '-' Number.
8199
 *
8200
 * @param str  A string to scan
8201
 * @returns the double value.
8202
 */
8203
double
8204
317k
xmlXPathStringEvalNumber(const xmlChar *str) {
8205
317k
    const xmlChar *cur = str;
8206
317k
    double ret;
8207
317k
    int ok = 0;
8208
317k
    int isneg = 0;
8209
317k
    int exponent = 0;
8210
317k
    int is_exponent_negative = 0;
8211
317k
#ifdef __GNUC__
8212
317k
    unsigned long tmp = 0;
8213
317k
    double temp;
8214
317k
#endif
8215
317k
    if (cur == NULL) return(0);
8216
317k
    while (IS_BLANK_CH(*cur)) cur++;
8217
317k
    if (*cur == '-') {
8218
1
  isneg = 1;
8219
1
  cur++;
8220
1
    }
8221
317k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8222
310k
        return(xmlXPathNAN);
8223
310k
    }
8224
8225
6.72k
#ifdef __GNUC__
8226
    /*
8227
     * tmp/temp is a workaround against a gcc compiler bug
8228
     * http://veillard.com/gcc.bug
8229
     */
8230
6.72k
    ret = 0;
8231
16.2k
    while ((*cur >= '0') && (*cur <= '9')) {
8232
9.49k
  ret = ret * 10;
8233
9.49k
  tmp = (*cur - '0');
8234
9.49k
  ok = 1;
8235
9.49k
  cur++;
8236
9.49k
  temp = (double) tmp;
8237
9.49k
  ret = ret + temp;
8238
9.49k
    }
8239
#else
8240
    ret = 0;
8241
    while ((*cur >= '0') && (*cur <= '9')) {
8242
  ret = ret * 10 + (*cur - '0');
8243
  ok = 1;
8244
  cur++;
8245
    }
8246
#endif
8247
8248
6.72k
    if (*cur == '.') {
8249
234
  int v, frac = 0, max;
8250
234
  double fraction = 0;
8251
8252
234
        cur++;
8253
234
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8254
0
      return(xmlXPathNAN);
8255
0
  }
8256
234
        while (*cur == '0') {
8257
0
      frac = frac + 1;
8258
0
      cur++;
8259
0
        }
8260
234
        max = frac + MAX_FRAC;
8261
4.76k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8262
4.52k
      v = (*cur - '0');
8263
4.52k
      fraction = fraction * 10 + v;
8264
4.52k
      frac = frac + 1;
8265
4.52k
      cur++;
8266
4.52k
  }
8267
234
  fraction /= pow(10.0, frac);
8268
234
  ret = ret + fraction;
8269
6.78k
  while ((*cur >= '0') && (*cur <= '9'))
8270
6.55k
      cur++;
8271
234
    }
8272
6.72k
    if ((*cur == 'e') || (*cur == 'E')) {
8273
0
      cur++;
8274
0
      if (*cur == '-') {
8275
0
  is_exponent_negative = 1;
8276
0
  cur++;
8277
0
      } else if (*cur == '+') {
8278
0
        cur++;
8279
0
      }
8280
0
      while ((*cur >= '0') && (*cur <= '9')) {
8281
0
        if (exponent < 1000000)
8282
0
    exponent = exponent * 10 + (*cur - '0');
8283
0
  cur++;
8284
0
      }
8285
0
    }
8286
6.72k
    while (IS_BLANK_CH(*cur)) cur++;
8287
6.72k
    if (*cur != 0) return(xmlXPathNAN);
8288
6.17k
    if (isneg) ret = -ret;
8289
6.17k
    if (is_exponent_negative) exponent = -exponent;
8290
6.17k
    ret *= pow(10.0, (double)exponent);
8291
6.17k
    return(ret);
8292
6.72k
}
8293
8294
/**
8295
 *  [30]   Number ::=   Digits ('.' Digits?)?
8296
 *                    | '.' Digits
8297
 *  [31]   Digits ::=   [0-9]+
8298
 *
8299
 * Compile a Number, then push it on the stack
8300
 *
8301
 * @param ctxt  the XPath Parser context
8302
 */
8303
static void
8304
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8305
140
{
8306
140
    double ret = 0.0;
8307
140
    int ok = 0;
8308
140
    int exponent = 0;
8309
140
    int is_exponent_negative = 0;
8310
140
    xmlXPathObjectPtr num;
8311
140
#ifdef __GNUC__
8312
140
    unsigned long tmp = 0;
8313
140
    double temp;
8314
140
#endif
8315
8316
140
    CHECK_ERROR;
8317
140
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8318
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8319
0
    }
8320
140
#ifdef __GNUC__
8321
    /*
8322
     * tmp/temp is a workaround against a gcc compiler bug
8323
     * http://veillard.com/gcc.bug
8324
     */
8325
140
    ret = 0;
8326
350
    while ((CUR >= '0') && (CUR <= '9')) {
8327
210
  ret = ret * 10;
8328
210
  tmp = (CUR - '0');
8329
210
        ok = 1;
8330
210
        NEXT;
8331
210
  temp = (double) tmp;
8332
210
  ret = ret + temp;
8333
210
    }
8334
#else
8335
    ret = 0;
8336
    while ((CUR >= '0') && (CUR <= '9')) {
8337
  ret = ret * 10 + (CUR - '0');
8338
  ok = 1;
8339
  NEXT;
8340
    }
8341
#endif
8342
140
    if (CUR == '.') {
8343
3
  int v, frac = 0, max;
8344
3
  double fraction = 0;
8345
8346
3
        NEXT;
8347
3
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8348
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8349
0
        }
8350
4
        while (CUR == '0') {
8351
1
            frac = frac + 1;
8352
1
            NEXT;
8353
1
        }
8354
3
        max = frac + MAX_FRAC;
8355
5
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8356
2
      v = (CUR - '0');
8357
2
      fraction = fraction * 10 + v;
8358
2
      frac = frac + 1;
8359
2
            NEXT;
8360
2
        }
8361
3
        fraction /= pow(10.0, frac);
8362
3
        ret = ret + fraction;
8363
3
        while ((CUR >= '0') && (CUR <= '9'))
8364
0
            NEXT;
8365
3
    }
8366
140
    if ((CUR == 'e') || (CUR == 'E')) {
8367
0
        NEXT;
8368
0
        if (CUR == '-') {
8369
0
            is_exponent_negative = 1;
8370
0
            NEXT;
8371
0
        } else if (CUR == '+') {
8372
0
      NEXT;
8373
0
  }
8374
0
        while ((CUR >= '0') && (CUR <= '9')) {
8375
0
            if (exponent < 1000000)
8376
0
                exponent = exponent * 10 + (CUR - '0');
8377
0
            NEXT;
8378
0
        }
8379
0
        if (is_exponent_negative)
8380
0
            exponent = -exponent;
8381
0
        ret *= pow(10.0, (double) exponent);
8382
0
    }
8383
140
    num = xmlXPathCacheNewFloat(ctxt, ret);
8384
140
    if (num == NULL) {
8385
0
  ctxt->error = XPATH_MEMORY_ERROR;
8386
140
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8387
140
                              NULL) == -1) {
8388
0
        xmlXPathReleaseObject(ctxt->context, num);
8389
0
    }
8390
140
}
8391
8392
/**
8393
 * Parse a Literal
8394
 *
8395
 *  [29]   Literal ::=   '"' [^"]* '"'
8396
 *                    | "'" [^']* "'"
8397
 *
8398
 * @param ctxt  the XPath Parser context
8399
 * @returns the value found or NULL in case of error
8400
 */
8401
static xmlChar *
8402
245
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8403
245
    const xmlChar *q;
8404
245
    xmlChar *ret = NULL;
8405
245
    int quote;
8406
8407
245
    if (CUR == '"') {
8408
63
        quote = '"';
8409
182
    } else if (CUR == '\'') {
8410
182
        quote = '\'';
8411
182
    } else {
8412
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8413
0
    }
8414
8415
245
    NEXT;
8416
245
    q = CUR_PTR;
8417
39.1k
    while (CUR != quote) {
8418
38.9k
        int ch;
8419
38.9k
        int len = 4;
8420
8421
38.9k
        if (CUR == 0)
8422
38.8k
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8423
38.8k
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8424
38.8k
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8425
38.8k
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8426
38.8k
        CUR_PTR += len;
8427
38.8k
    }
8428
171
    ret = xmlStrndup(q, CUR_PTR - q);
8429
171
    if (ret == NULL)
8430
0
        xmlXPathPErrMemory(ctxt);
8431
171
    NEXT;
8432
171
    return(ret);
8433
245
}
8434
8435
/**
8436
 * Parse a Literal and push it on the stack.
8437
 *
8438
 *  [29]   Literal ::=   '"' [^"]* '"'
8439
 *                    | "'" [^']* "'"
8440
 *
8441
 * TODO: Memory allocation could be improved.
8442
 *
8443
 * @param ctxt  the XPath Parser context
8444
 */
8445
static void
8446
245
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8447
245
    xmlChar *ret = NULL;
8448
245
    xmlXPathObjectPtr lit;
8449
8450
245
    ret = xmlXPathParseLiteral(ctxt);
8451
245
    if (ret == NULL)
8452
74
        return;
8453
171
    lit = xmlXPathCacheNewString(ctxt, ret);
8454
171
    if (lit == NULL) {
8455
0
        ctxt->error = XPATH_MEMORY_ERROR;
8456
171
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8457
171
                              NULL) == -1) {
8458
0
        xmlXPathReleaseObject(ctxt->context, lit);
8459
0
    }
8460
171
    xmlFree(ret);
8461
171
}
8462
8463
/**
8464
 * Parse a VariableReference, evaluate it and push it on the stack.
8465
 *
8466
 * The variable bindings consist of a mapping from variable names
8467
 * to variable values. The value of a variable is an object, which can be
8468
 * of any of the types that are possible for the value of an expression,
8469
 * and may also be of additional types not specified here.
8470
 *
8471
 * Early evaluation is possible since:
8472
 * The variable bindings [...] used to evaluate a subexpression are
8473
 * always the same as those used to evaluate the containing expression.
8474
 *
8475
 *  [36]   VariableReference ::=   '$' QName
8476
 * @param ctxt  the XPath Parser context
8477
 */
8478
static void
8479
34
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8480
34
    xmlChar *name;
8481
34
    xmlChar *prefix;
8482
8483
34
    SKIP_BLANKS;
8484
34
    if (CUR != '$') {
8485
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8486
0
    }
8487
34
    NEXT;
8488
34
    name = xmlXPathParseQName(ctxt, &prefix);
8489
34
    if (name == NULL) {
8490
0
        xmlFree(prefix);
8491
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8492
0
    }
8493
34
    ctxt->comp->last = -1;
8494
34
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8495
0
        xmlFree(prefix);
8496
0
        xmlFree(name);
8497
0
    }
8498
34
    SKIP_BLANKS;
8499
34
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8500
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8501
0
    }
8502
34
}
8503
8504
/**
8505
 * Is the name given a NodeType one.
8506
 *
8507
 *  [38]   NodeType ::=   'comment'
8508
 *                    | 'text'
8509
 *                    | 'processing-instruction'
8510
 *                    | 'node'
8511
 *
8512
 * @param name  a name string
8513
 * @returns 1 if true 0 otherwise
8514
 */
8515
int
8516
324
xmlXPathIsNodeType(const xmlChar *name) {
8517
324
    if (name == NULL)
8518
0
  return(0);
8519
8520
324
    if (xmlStrEqual(name, BAD_CAST "node"))
8521
0
  return(1);
8522
324
    if (xmlStrEqual(name, BAD_CAST "text"))
8523
0
  return(1);
8524
324
    if (xmlStrEqual(name, BAD_CAST "comment"))
8525
0
  return(1);
8526
324
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8527
0
  return(1);
8528
324
    return(0);
8529
324
}
8530
8531
/**
8532
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8533
 *  [17]   Argument ::=   Expr
8534
 *
8535
 * Compile a function call, the evaluation of all arguments are
8536
 * pushed on the stack
8537
 *
8538
 * @param ctxt  the XPath Parser context
8539
 */
8540
static void
8541
324
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8542
324
    xmlChar *name;
8543
324
    xmlChar *prefix;
8544
324
    int nbargs = 0;
8545
324
    int sort = 1;
8546
8547
324
    name = xmlXPathParseQName(ctxt, &prefix);
8548
324
    if (name == NULL) {
8549
0
  xmlFree(prefix);
8550
0
  XP_ERROR(XPATH_EXPR_ERROR);
8551
0
    }
8552
324
    SKIP_BLANKS;
8553
8554
324
    if (CUR != '(') {
8555
0
  xmlFree(name);
8556
0
  xmlFree(prefix);
8557
0
  XP_ERROR(XPATH_EXPR_ERROR);
8558
0
    }
8559
324
    NEXT;
8560
324
    SKIP_BLANKS;
8561
8562
    /*
8563
    * Optimization for count(): we don't need the node-set to be sorted.
8564
    */
8565
324
    if ((prefix == NULL) && (name[0] == 'c') &&
8566
324
  xmlStrEqual(name, BAD_CAST "count"))
8567
0
    {
8568
0
  sort = 0;
8569
0
    }
8570
324
    ctxt->comp->last = -1;
8571
324
    if (CUR != ')') {
8572
460
  while (CUR != 0) {
8573
452
      int op1 = ctxt->comp->last;
8574
452
      ctxt->comp->last = -1;
8575
452
      xmlXPathCompileExpr(ctxt, sort);
8576
452
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8577
162
    xmlFree(name);
8578
162
    xmlFree(prefix);
8579
162
    return;
8580
162
      }
8581
290
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8582
290
      nbargs++;
8583
290
      if (CUR == ')') break;
8584
192
      if (CUR != ',') {
8585
29
    xmlFree(name);
8586
29
    xmlFree(prefix);
8587
29
    XP_ERROR(XPATH_EXPR_ERROR);
8588
0
      }
8589
163
      NEXT;
8590
163
      SKIP_BLANKS;
8591
163
  }
8592
297
    }
8593
133
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8594
0
        xmlFree(prefix);
8595
0
        xmlFree(name);
8596
0
    }
8597
133
    NEXT;
8598
133
    SKIP_BLANKS;
8599
133
}
8600
8601
/**
8602
 *  [15]   PrimaryExpr ::=   VariableReference
8603
 *                | '(' Expr ')'
8604
 *                | Literal
8605
 *                | Number
8606
 *                | FunctionCall
8607
 *
8608
 * Compile a primary expression.
8609
 *
8610
 * @param ctxt  the XPath Parser context
8611
 */
8612
static void
8613
894
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8614
894
    SKIP_BLANKS;
8615
894
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8616
860
    else if (CUR == '(') {
8617
151
  NEXT;
8618
151
  SKIP_BLANKS;
8619
151
  xmlXPathCompileExpr(ctxt, 1);
8620
151
  CHECK_ERROR;
8621
126
  if (CUR != ')') {
8622
9
      XP_ERROR(XPATH_EXPR_ERROR);
8623
0
  }
8624
117
  NEXT;
8625
117
  SKIP_BLANKS;
8626
709
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8627
140
  xmlXPathCompNumber(ctxt);
8628
569
    } else if ((CUR == '\'') || (CUR == '"')) {
8629
245
  xmlXPathCompLiteral(ctxt);
8630
324
    } else {
8631
324
  xmlXPathCompFunctionCall(ctxt);
8632
324
    }
8633
860
    SKIP_BLANKS;
8634
860
}
8635
8636
/**
8637
 *  [20]   FilterExpr ::=   PrimaryExpr
8638
 *               | FilterExpr Predicate
8639
 *
8640
 * Compile a filter expression.
8641
 * Square brackets are used to filter expressions in the same way that
8642
 * they are used in location paths. It is an error if the expression to
8643
 * be filtered does not evaluate to a node-set. The context node list
8644
 * used for evaluating the expression in square brackets is the node-set
8645
 * to be filtered listed in document order.
8646
 *
8647
 * @param ctxt  the XPath Parser context
8648
 */
8649
8650
static void
8651
894
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8652
894
    xmlXPathCompPrimaryExpr(ctxt);
8653
894
    CHECK_ERROR;
8654
593
    SKIP_BLANKS;
8655
8656
671
    while (CUR == '[') {
8657
78
  xmlXPathCompPredicate(ctxt, 1);
8658
78
  SKIP_BLANKS;
8659
78
    }
8660
8661
8662
593
}
8663
8664
/**
8665
 * Trickery: parse an XML name but without consuming the input flow
8666
 * Needed to avoid insanity in the parser state.
8667
 *
8668
 * @param ctxt  the XPath Parser context
8669
 * @returns the Name parsed or NULL
8670
 */
8671
8672
static xmlChar *
8673
284k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8674
284k
    const xmlChar *end;
8675
284k
    xmlChar *ret;
8676
8677
284k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8678
284k
    if (end == NULL) {
8679
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8680
0
    }
8681
284k
    if (end == ctxt->cur)
8682
431
        return(NULL);
8683
8684
284k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8685
284k
    if (ret == NULL)
8686
2
        xmlXPathPErrMemory(ctxt);
8687
284k
    return(ret);
8688
284k
}
8689
8690
/**
8691
 *  [19]   PathExpr ::=   LocationPath
8692
 *               | FilterExpr
8693
 *               | FilterExpr '/' RelativeLocationPath
8694
 *               | FilterExpr '//' RelativeLocationPath
8695
 *
8696
 * Compile a path expression.
8697
 *
8698
 * @param ctxt  the XPath Parser context
8699
 */
8700
8701
static void
8702
286k
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8703
286k
    int lc = 1;           /* Should we branch to LocationPath ?         */
8704
286k
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8705
8706
286k
    SKIP_BLANKS;
8707
286k
    if ((CUR == '$') || (CUR == '(') ||
8708
286k
  (IS_ASCII_DIGIT(CUR)) ||
8709
286k
        (CUR == '\'') || (CUR == '"') ||
8710
286k
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8711
570
  lc = 0;
8712
286k
    } else if (CUR == '*') {
8713
  /* relative or absolute location path */
8714
27
  lc = 1;
8715
286k
    } else if (CUR == '/') {
8716
  /* relative or absolute location path */
8717
1.18k
  lc = 1;
8718
284k
    } else if (CUR == '@') {
8719
  /* relative abbreviated attribute location path */
8720
11
  lc = 1;
8721
284k
    } else if (CUR == '.') {
8722
  /* relative abbreviated attribute location path */
8723
95
  lc = 1;
8724
284k
    } else {
8725
  /*
8726
   * Problem is finding if we have a name here whether it's:
8727
   *   - a nodetype
8728
   *   - a function call in which case it's followed by '('
8729
   *   - an axis in which case it's followed by ':'
8730
   *   - a element name
8731
   * We do an a priori analysis here rather than having to
8732
   * maintain parsed token content through the recursive function
8733
   * calls. This looks uglier but makes the code easier to
8734
   * read/write/debug.
8735
   */
8736
284k
  SKIP_BLANKS;
8737
284k
  name = xmlXPathScanName(ctxt);
8738
284k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8739
2
      lc = 1;
8740
2
      xmlFree(name);
8741
284k
  } else if (name != NULL) {
8742
284k
      int len =xmlStrlen(name);
8743
8744
8745
284k
      while (NXT(len) != 0) {
8746
284k
    if (NXT(len) == '/') {
8747
        /* element name */
8748
78
        lc = 1;
8749
78
        break;
8750
284k
    } else if (IS_BLANK_CH(NXT(len))) {
8751
        /* ignore blanks */
8752
100
        ;
8753
284k
    } else if (NXT(len) == ':') {
8754
0
        lc = 1;
8755
0
        break;
8756
284k
    } else if ((NXT(len) == '(')) {
8757
        /* Node Type or Function */
8758
324
        if (xmlXPathIsNodeType(name)) {
8759
0
      lc = 1;
8760
324
        } else {
8761
324
      lc = 0;
8762
324
        }
8763
324
                    break;
8764
283k
    } else if ((NXT(len) == '[')) {
8765
        /* element name */
8766
87
        lc = 1;
8767
87
        break;
8768
283k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8769
283k
         (NXT(len) == '=')) {
8770
176
        lc = 1;
8771
176
        break;
8772
283k
    } else {
8773
283k
        lc = 1;
8774
283k
        break;
8775
283k
    }
8776
100
    len++;
8777
100
      }
8778
284k
      if (NXT(len) == 0) {
8779
    /* element name */
8780
51
    lc = 1;
8781
51
      }
8782
284k
      xmlFree(name);
8783
284k
  } else {
8784
      /* make sure all cases are covered explicitly */
8785
433
      XP_ERROR(XPATH_EXPR_ERROR);
8786
0
  }
8787
284k
    }
8788
8789
286k
    if (lc) {
8790
285k
  if (CUR == '/') {
8791
1.18k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8792
284k
  } else {
8793
284k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8794
284k
  }
8795
285k
  xmlXPathCompLocationPath(ctxt);
8796
285k
    } else {
8797
894
  xmlXPathCompFilterExpr(ctxt);
8798
894
  CHECK_ERROR;
8799
584
  if ((CUR == '/') && (NXT(1) == '/')) {
8800
5
      SKIP(2);
8801
5
      SKIP_BLANKS;
8802
8803
5
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8804
5
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8805
8806
5
      xmlXPathCompRelativeLocationPath(ctxt);
8807
579
  } else if (CUR == '/') {
8808
29
      xmlXPathCompRelativeLocationPath(ctxt);
8809
29
  }
8810
584
    }
8811
285k
    SKIP_BLANKS;
8812
285k
}
8813
8814
/**
8815
 *  [18]   UnionExpr ::=   PathExpr
8816
 *               | UnionExpr '|' PathExpr
8817
 *
8818
 * Compile an union expression.
8819
 *
8820
 * @param ctxt  the XPath Parser context
8821
 */
8822
8823
static void
8824
2.82k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8825
2.82k
    xmlXPathCompPathExpr(ctxt);
8826
2.82k
    CHECK_ERROR;
8827
2.00k
    SKIP_BLANKS;
8828
285k
    while (CUR == '|') {
8829
283k
  int op1 = ctxt->comp->last;
8830
283k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8831
8832
283k
  NEXT;
8833
283k
  SKIP_BLANKS;
8834
283k
  xmlXPathCompPathExpr(ctxt);
8835
8836
283k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8837
8838
283k
  SKIP_BLANKS;
8839
283k
    }
8840
2.00k
}
8841
8842
/**
8843
 *  [27]   UnaryExpr ::=   UnionExpr
8844
 *                   | '-' UnaryExpr
8845
 *
8846
 * Compile an unary expression.
8847
 *
8848
 * @param ctxt  the XPath Parser context
8849
 */
8850
8851
static void
8852
2.82k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8853
2.82k
    int minus = 0;
8854
2.82k
    int found = 0;
8855
8856
2.82k
    SKIP_BLANKS;
8857
2.83k
    while (CUR == '-') {
8858
19
        minus = 1 - minus;
8859
19
  found = 1;
8860
19
  NEXT;
8861
19
  SKIP_BLANKS;
8862
19
    }
8863
8864
2.82k
    xmlXPathCompUnionExpr(ctxt);
8865
2.82k
    CHECK_ERROR;
8866
2.00k
    if (found) {
8867
19
  if (minus)
8868
19
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8869
0
  else
8870
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8871
19
    }
8872
2.00k
}
8873
8874
/**
8875
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
8876
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
8877
 *                   | MultiplicativeExpr 'div' UnaryExpr
8878
 *                   | MultiplicativeExpr 'mod' UnaryExpr
8879
 *  [34]   MultiplyOperator ::=   '*'
8880
 *
8881
 * Compile an Additive expression.
8882
 *
8883
 * @param ctxt  the XPath Parser context
8884
 */
8885
8886
static void
8887
2.73k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8888
2.73k
    xmlXPathCompUnaryExpr(ctxt);
8889
2.73k
    CHECK_ERROR;
8890
1.93k
    SKIP_BLANKS;
8891
2.00k
    while ((CUR == '*') ||
8892
2.00k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8893
2.00k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8894
86
  int op = -1;
8895
86
  int op1 = ctxt->comp->last;
8896
8897
86
        if (CUR == '*') {
8898
85
      op = 0;
8899
85
      NEXT;
8900
85
  } else if (CUR == 'd') {
8901
1
      op = 1;
8902
1
      SKIP(3);
8903
1
  } else if (CUR == 'm') {
8904
0
      op = 2;
8905
0
      SKIP(3);
8906
0
  }
8907
86
  SKIP_BLANKS;
8908
86
        xmlXPathCompUnaryExpr(ctxt);
8909
86
  CHECK_ERROR;
8910
73
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8911
73
  SKIP_BLANKS;
8912
73
    }
8913
1.93k
}
8914
8915
/**
8916
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
8917
 *                   | AdditiveExpr '+' MultiplicativeExpr
8918
 *                   | AdditiveExpr '-' MultiplicativeExpr
8919
 *
8920
 * Compile an Additive expression.
8921
 *
8922
 * @param ctxt  the XPath Parser context
8923
 */
8924
8925
static void
8926
2.70k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8927
8928
2.70k
    xmlXPathCompMultiplicativeExpr(ctxt);
8929
2.70k
    CHECK_ERROR;
8930
1.90k
    SKIP_BLANKS;
8931
1.92k
    while ((CUR == '+') || (CUR == '-')) {
8932
31
  int plus;
8933
31
  int op1 = ctxt->comp->last;
8934
8935
31
        if (CUR == '+') plus = 1;
8936
20
  else plus = 0;
8937
31
  NEXT;
8938
31
  SKIP_BLANKS;
8939
31
        xmlXPathCompMultiplicativeExpr(ctxt);
8940
31
  CHECK_ERROR;
8941
14
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8942
14
  SKIP_BLANKS;
8943
14
    }
8944
1.90k
}
8945
8946
/**
8947
 *  [24]   RelationalExpr ::=   AdditiveExpr
8948
 *                 | RelationalExpr '<' AdditiveExpr
8949
 *                 | RelationalExpr '>' AdditiveExpr
8950
 *                 | RelationalExpr '<=' AdditiveExpr
8951
 *                 | RelationalExpr '>=' AdditiveExpr
8952
 *
8953
 *  A <= B > C is allowed ? Answer from James, yes with
8954
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8955
 *  which is basically what got implemented.
8956
 *
8957
 * Compile a Relational expression, then push the result
8958
 * on the stack
8959
 *
8960
 * @param ctxt  the XPath Parser context
8961
 */
8962
8963
static void
8964
2.61k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8965
2.61k
    xmlXPathCompAdditiveExpr(ctxt);
8966
2.61k
    CHECK_ERROR;
8967
1.86k
    SKIP_BLANKS;
8968
1.88k
    while ((CUR == '<') || (CUR == '>')) {
8969
90
  int inf, strict;
8970
90
  int op1 = ctxt->comp->last;
8971
8972
90
        if (CUR == '<') inf = 1;
8973
90
  else inf = 0;
8974
90
  if (NXT(1) == '=') strict = 0;
8975
84
  else strict = 1;
8976
90
  NEXT;
8977
90
  if (!strict) NEXT;
8978
90
  SKIP_BLANKS;
8979
90
        xmlXPathCompAdditiveExpr(ctxt);
8980
90
  CHECK_ERROR;
8981
26
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8982
26
  SKIP_BLANKS;
8983
26
    }
8984
1.86k
}
8985
8986
/**
8987
 *  [23]   EqualityExpr ::=   RelationalExpr
8988
 *                 | EqualityExpr '=' RelationalExpr
8989
 *                 | EqualityExpr '!=' RelationalExpr
8990
 *
8991
 *  A != B != C is allowed ? Answer from James, yes with
8992
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
8993
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
8994
 *  which is basically what got implemented.
8995
 *
8996
 * Compile an Equality expression.
8997
 *
8998
 * @param ctxt  the XPath Parser context
8999
 */
9000
static void
9001
2.47k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9002
2.47k
    xmlXPathCompRelationalExpr(ctxt);
9003
2.47k
    CHECK_ERROR;
9004
1.68k
    SKIP_BLANKS;
9005
1.79k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9006
138
  int eq;
9007
138
  int op1 = ctxt->comp->last;
9008
9009
138
        if (CUR == '=') eq = 1;
9010
0
  else eq = 0;
9011
138
  NEXT;
9012
138
  if (!eq) NEXT;
9013
138
  SKIP_BLANKS;
9014
138
        xmlXPathCompRelationalExpr(ctxt);
9015
138
  CHECK_ERROR;
9016
118
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9017
118
  SKIP_BLANKS;
9018
118
    }
9019
1.68k
}
9020
9021
/**
9022
 *  [22]   AndExpr ::=   EqualityExpr
9023
 *                 | AndExpr 'and' EqualityExpr
9024
 *
9025
 * Compile an AND expression.
9026
 *
9027
 * @param ctxt  the XPath Parser context
9028
 */
9029
static void
9030
2.43k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9031
2.43k
    xmlXPathCompEqualityExpr(ctxt);
9032
2.43k
    CHECK_ERROR;
9033
1.65k
    SKIP_BLANKS;
9034
1.66k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9035
38
  int op1 = ctxt->comp->last;
9036
38
        SKIP(3);
9037
38
  SKIP_BLANKS;
9038
38
        xmlXPathCompEqualityExpr(ctxt);
9039
38
  CHECK_ERROR;
9040
9
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9041
9
  SKIP_BLANKS;
9042
9
    }
9043
1.65k
}
9044
9045
/**
9046
 *  [14]   Expr ::=   OrExpr
9047
 *  [21]   OrExpr ::=   AndExpr
9048
 *                 | OrExpr 'or' AndExpr
9049
 *
9050
 * Parse and compile an expression
9051
 *
9052
 * @param ctxt  the XPath Parser context
9053
 * @param sort  whether to sort the resulting node set
9054
 */
9055
static void
9056
2.43k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9057
2.43k
    xmlXPathContextPtr xpctxt = ctxt->context;
9058
9059
2.43k
    if (xpctxt != NULL) {
9060
2.43k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9061
2.43k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9062
        /*
9063
         * Parsing a single '(' pushes about 10 functions on the call stack
9064
         * before recursing!
9065
         */
9066
2.43k
        xpctxt->depth += 10;
9067
2.43k
    }
9068
9069
2.43k
    xmlXPathCompAndExpr(ctxt);
9070
2.43k
    CHECK_ERROR;
9071
1.62k
    SKIP_BLANKS;
9072
1.62k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9073
0
  int op1 = ctxt->comp->last;
9074
0
        SKIP(2);
9075
0
  SKIP_BLANKS;
9076
0
        xmlXPathCompAndExpr(ctxt);
9077
0
  CHECK_ERROR;
9078
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9079
0
  SKIP_BLANKS;
9080
0
    }
9081
1.62k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9082
  /* more ops could be optimized too */
9083
  /*
9084
  * This is the main place to eliminate sorting for
9085
  * operations which don't require a sorted node-set.
9086
  * E.g. count().
9087
  */
9088
1.32k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9089
1.32k
    }
9090
9091
1.62k
    if (xpctxt != NULL)
9092
1.62k
        xpctxt->depth -= 10;
9093
1.62k
}
9094
9095
/**
9096
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9097
 *  [9]   PredicateExpr ::=   Expr
9098
 *
9099
 * Compile a predicate expression
9100
 *
9101
 * @param ctxt  the XPath Parser context
9102
 * @param filter  act as a filter
9103
 */
9104
static void
9105
229
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9106
229
    int op1 = ctxt->comp->last;
9107
9108
229
    SKIP_BLANKS;
9109
229
    if (CUR != '[') {
9110
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9111
0
    }
9112
229
    NEXT;
9113
229
    SKIP_BLANKS;
9114
9115
229
    ctxt->comp->last = -1;
9116
    /*
9117
    * This call to xmlXPathCompileExpr() will deactivate sorting
9118
    * of the predicate result.
9119
    * TODO: Sorting is still activated for filters, since I'm not
9120
    *  sure if needed. Normally sorting should not be needed, since
9121
    *  a filter can only diminish the number of items in a sequence,
9122
    *  but won't change its order; so if the initial sequence is sorted,
9123
    *  subsequent sorting is not needed.
9124
    */
9125
229
    if (! filter)
9126
151
  xmlXPathCompileExpr(ctxt, 0);
9127
78
    else
9128
78
  xmlXPathCompileExpr(ctxt, 1);
9129
229
    CHECK_ERROR;
9130
9131
224
    if (CUR != ']') {
9132
39
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9133
0
    }
9134
9135
185
    if (filter)
9136
67
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9137
118
    else
9138
118
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9139
9140
185
    NEXT;
9141
185
    SKIP_BLANKS;
9142
185
}
9143
9144
/**
9145
 * ```
9146
 * [7] NodeTest ::=   NameTest
9147
 *        | NodeType '(' ')'
9148
 *        | 'processing-instruction' '(' Literal ')'
9149
 *
9150
 * [37] NameTest ::=  '*'
9151
 *        | NCName ':' '*'
9152
 *        | QName
9153
 * [38] NodeType ::= 'comment'
9154
 *       | 'text'
9155
 *       | 'processing-instruction'
9156
 *       | 'node'
9157
 * ```
9158
 *
9159
 * @param ctxt  the XPath Parser context
9160
 * @param test  pointer to a xmlXPathTestVal
9161
 * @param type  pointer to a xmlXPathTypeVal
9162
 * @param prefix  placeholder for a possible name prefix
9163
 * @param name  current name token (optional)
9164
 * @returns the name found and updates `test`, `type` and `prefix` appropriately
9165
 */
9166
static xmlChar *
9167
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9168
               xmlXPathTypeVal *type, xmlChar **prefix,
9169
285k
         xmlChar *name) {
9170
285k
    int blanks;
9171
9172
285k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9173
0
  return(NULL);
9174
0
    }
9175
285k
    *type = (xmlXPathTypeVal) 0;
9176
285k
    *test = (xmlXPathTestVal) 0;
9177
285k
    *prefix = NULL;
9178
285k
    SKIP_BLANKS;
9179
9180
285k
    if ((name == NULL) && (CUR == '*')) {
9181
  /*
9182
   * All elements
9183
   */
9184
1.00k
  NEXT;
9185
1.00k
  *test = NODE_TEST_ALL;
9186
1.00k
  return(NULL);
9187
1.00k
    }
9188
9189
284k
    if (name == NULL)
9190
51
  name = xmlXPathParseNCName(ctxt);
9191
284k
    if (name == NULL) {
9192
35
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9193
0
    }
9194
9195
284k
    blanks = IS_BLANK_CH(CUR);
9196
284k
    SKIP_BLANKS;
9197
284k
    if (CUR == '(') {
9198
380
  NEXT;
9199
  /*
9200
   * NodeType or PI search
9201
   */
9202
380
  if (xmlStrEqual(name, BAD_CAST "comment"))
9203
1
      *type = NODE_TYPE_COMMENT;
9204
379
  else if (xmlStrEqual(name, BAD_CAST "node"))
9205
343
      *type = NODE_TYPE_NODE;
9206
36
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9207
4
      *type = NODE_TYPE_PI;
9208
32
  else if (xmlStrEqual(name, BAD_CAST "text"))
9209
29
      *type = NODE_TYPE_TEXT;
9210
3
  else {
9211
3
      if (name != NULL)
9212
3
    xmlFree(name);
9213
3
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9214
0
  }
9215
9216
377
  *test = NODE_TEST_TYPE;
9217
9218
377
  SKIP_BLANKS;
9219
377
  if (*type == NODE_TYPE_PI) {
9220
      /*
9221
       * Specific case: search a PI by name.
9222
       */
9223
4
      if (name != NULL)
9224
4
    xmlFree(name);
9225
4
      name = NULL;
9226
4
      if (CUR != ')') {
9227
0
    name = xmlXPathParseLiteral(ctxt);
9228
0
    *test = NODE_TEST_PI;
9229
0
    SKIP_BLANKS;
9230
0
      }
9231
4
  }
9232
377
  if (CUR != ')') {
9233
0
      if (name != NULL)
9234
0
    xmlFree(name);
9235
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9236
0
  }
9237
377
  NEXT;
9238
377
  return(name);
9239
377
    }
9240
284k
    *test = NODE_TEST_NAME;
9241
284k
    if ((!blanks) && (CUR == ':')) {
9242
180
  NEXT;
9243
9244
  /*
9245
   * Since currently the parser context don't have a
9246
   * namespace list associated:
9247
   * The namespace name for this prefix can be computed
9248
   * only at evaluation time. The compilation is done
9249
   * outside of any context.
9250
   */
9251
180
  *prefix = name;
9252
9253
180
  if (CUR == '*') {
9254
      /*
9255
       * All elements
9256
       */
9257
0
      NEXT;
9258
0
      *test = NODE_TEST_ALL;
9259
0
      return(NULL);
9260
0
  }
9261
9262
180
  name = xmlXPathParseNCName(ctxt);
9263
180
  if (name == NULL) {
9264
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9265
0
  }
9266
180
    }
9267
284k
    return(name);
9268
284k
}
9269
9270
/**
9271
 * [6] AxisName ::=   'ancestor'
9272
 *                  | 'ancestor-or-self'
9273
 *                  | 'attribute'
9274
 *                  | 'child'
9275
 *                  | 'descendant'
9276
 *                  | 'descendant-or-self'
9277
 *                  | 'following'
9278
 *                  | 'following-sibling'
9279
 *                  | 'namespace'
9280
 *                  | 'parent'
9281
 *                  | 'preceding'
9282
 *                  | 'preceding-sibling'
9283
 *                  | 'self'
9284
 *
9285
 * @param name  a preparsed name token
9286
 * @returns the axis or 0
9287
 */
9288
static xmlXPathAxisVal
9289
284k
xmlXPathIsAxisName(const xmlChar *name) {
9290
284k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9291
284k
    switch (name[0]) {
9292
71
  case 'a':
9293
71
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9294
2
    ret = AXIS_ANCESTOR;
9295
71
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9296
0
    ret = AXIS_ANCESTOR_OR_SELF;
9297
71
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9298
0
    ret = AXIS_ATTRIBUTE;
9299
71
      break;
9300
2
  case 'c':
9301
2
      if (xmlStrEqual(name, BAD_CAST "child"))
9302
0
    ret = AXIS_CHILD;
9303
2
      break;
9304
42
  case 'd':
9305
42
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9306
0
    ret = AXIS_DESCENDANT;
9307
42
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9308
2
    ret = AXIS_DESCENDANT_OR_SELF;
9309
42
      break;
9310
18
  case 'f':
9311
18
      if (xmlStrEqual(name, BAD_CAST "following"))
9312
0
    ret = AXIS_FOLLOWING;
9313
18
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9314
0
    ret = AXIS_FOLLOWING_SIBLING;
9315
18
      break;
9316
676
  case 'n':
9317
676
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9318
305
    ret = AXIS_NAMESPACE;
9319
676
      break;
9320
14
  case 'p':
9321
14
      if (xmlStrEqual(name, BAD_CAST "parent"))
9322
0
    ret = AXIS_PARENT;
9323
14
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9324
1
    ret = AXIS_PRECEDING;
9325
14
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9326
9
    ret = AXIS_PRECEDING_SIBLING;
9327
14
      break;
9328
94
  case 's':
9329
94
      if (xmlStrEqual(name, BAD_CAST "self"))
9330
0
    ret = AXIS_SELF;
9331
94
      break;
9332
284k
    }
9333
284k
    return(ret);
9334
284k
}
9335
9336
/**
9337
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
9338
 *                  | AbbreviatedStep
9339
 *
9340
 * [12] AbbreviatedStep ::=   '.' | '..'
9341
 *
9342
 * [5] AxisSpecifier ::= AxisName '::'
9343
 *                  | AbbreviatedAxisSpecifier
9344
 *
9345
 * [13] AbbreviatedAxisSpecifier ::= '@'?
9346
 *
9347
 * Modified for XPtr range support as:
9348
 *
9349
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9350
 *                     | AbbreviatedStep
9351
 *                     | 'range-to' '(' Expr ')' Predicate*
9352
 *
9353
 * Compile one step in a Location Path
9354
 *
9355
 * @param ctxt  the XPath Parser context
9356
 */
9357
static void
9358
285k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9359
285k
    SKIP_BLANKS;
9360
285k
    if ((CUR == '.') && (NXT(1) == '.')) {
9361
12
  SKIP(2);
9362
12
  SKIP_BLANKS;
9363
12
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9364
12
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9365
285k
    } else if (CUR == '.') {
9366
206
  NEXT;
9367
206
  SKIP_BLANKS;
9368
285k
    } else {
9369
285k
  xmlChar *name = NULL;
9370
285k
  xmlChar *prefix = NULL;
9371
285k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9372
285k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9373
285k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9374
285k
  int op1;
9375
9376
285k
  if (CUR == '*') {
9377
698
      axis = AXIS_CHILD;
9378
284k
  } else {
9379
284k
      if (name == NULL)
9380
284k
    name = xmlXPathParseNCName(ctxt);
9381
284k
      if (name != NULL) {
9382
284k
    axis = xmlXPathIsAxisName(name);
9383
284k
    if (axis != 0) {
9384
319
        SKIP_BLANKS;
9385
319
        if ((CUR == ':') && (NXT(1) == ':')) {
9386
319
      SKIP(2);
9387
319
      xmlFree(name);
9388
319
      name = NULL;
9389
319
        } else {
9390
      /* an element name can conflict with an axis one :-\ */
9391
0
      axis = AXIS_CHILD;
9392
0
        }
9393
284k
    } else {
9394
284k
        axis = AXIS_CHILD;
9395
284k
    }
9396
284k
      } else if (CUR == '@') {
9397
12
    NEXT;
9398
12
    axis = AXIS_ATTRIBUTE;
9399
37
      } else {
9400
37
    axis = AXIS_CHILD;
9401
37
      }
9402
284k
  }
9403
9404
285k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9405
13
            xmlFree(name);
9406
13
            return;
9407
13
        }
9408
9409
285k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9410
285k
  if (test == 0)
9411
38
      return;
9412
9413
285k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9414
285k
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9415
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9416
0
    xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9417
0
                               "Undefined namespace prefix: %s\n", prefix);
9418
0
      }
9419
0
  }
9420
9421
285k
  op1 = ctxt->comp->last;
9422
285k
  ctxt->comp->last = -1;
9423
9424
285k
  SKIP_BLANKS;
9425
285k
  while (CUR == '[') {
9426
151
      xmlXPathCompPredicate(ctxt, 0);
9427
151
  }
9428
9429
285k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9430
285k
                           test, type, (void *)prefix, (void *)name) == -1) {
9431
0
            xmlFree(prefix);
9432
0
            xmlFree(name);
9433
0
        }
9434
285k
    }
9435
285k
}
9436
9437
/**
9438
 *  [3]   RelativeLocationPath ::=   Step
9439
 *                     | RelativeLocationPath '/' Step
9440
 *                     | AbbreviatedRelativeLocationPath
9441
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
9442
 *
9443
 * Compile a relative location path.
9444
 *
9445
 * @param ctxt  the XPath Parser context
9446
 */
9447
static void
9448
xmlXPathCompRelativeLocationPath
9449
285k
(xmlXPathParserContextPtr ctxt) {
9450
285k
    SKIP_BLANKS;
9451
285k
    if ((CUR == '/') && (NXT(1) == '/')) {
9452
2
  SKIP(2);
9453
2
  SKIP_BLANKS;
9454
2
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9455
2
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9456
285k
    } else if (CUR == '/') {
9457
70
      NEXT;
9458
70
  SKIP_BLANKS;
9459
70
    }
9460
285k
    xmlXPathCompStep(ctxt);
9461
285k
    CHECK_ERROR;
9462
284k
    SKIP_BLANKS;
9463
285k
    while (CUR == '/') {
9464
777
  if ((CUR == '/') && (NXT(1) == '/')) {
9465
70
      SKIP(2);
9466
70
      SKIP_BLANKS;
9467
70
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9468
70
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9469
70
      xmlXPathCompStep(ctxt);
9470
707
  } else if (CUR == '/') {
9471
707
      NEXT;
9472
707
      SKIP_BLANKS;
9473
707
      xmlXPathCompStep(ctxt);
9474
707
  }
9475
777
  SKIP_BLANKS;
9476
777
    }
9477
284k
}
9478
9479
/**
9480
 *  [1]   LocationPath ::=   RelativeLocationPath
9481
 *                     | AbsoluteLocationPath
9482
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
9483
 *                     | AbbreviatedAbsoluteLocationPath
9484
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
9485
 *                           '//' RelativeLocationPath
9486
 *
9487
 * Compile a location path
9488
 *
9489
 * @param ctxt  the XPath Parser context
9490
 */
9491
static void
9492
285k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9493
285k
    SKIP_BLANKS;
9494
285k
    if (CUR != '/') {
9495
284k
        xmlXPathCompRelativeLocationPath(ctxt);
9496
284k
    } else {
9497
2.34k
  while (CUR == '/') {
9498
1.18k
      if ((CUR == '/') && (NXT(1) == '/')) {
9499
487
    SKIP(2);
9500
487
    SKIP_BLANKS;
9501
487
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9502
487
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9503
487
    xmlXPathCompRelativeLocationPath(ctxt);
9504
698
      } else if (CUR == '/') {
9505
698
    NEXT;
9506
698
    SKIP_BLANKS;
9507
698
    if ((CUR != 0) &&
9508
698
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9509
697
                     (CUR == '_') || (CUR == '.') ||
9510
697
         (CUR == '@') || (CUR == '*')))
9511
336
        xmlXPathCompRelativeLocationPath(ctxt);
9512
698
      }
9513
1.18k
      CHECK_ERROR;
9514
1.18k
  }
9515
1.18k
    }
9516
285k
}
9517
9518
/************************************************************************
9519
 *                  *
9520
 *    XPath precompiled expression evaluation     *
9521
 *                  *
9522
 ************************************************************************/
9523
9524
static int
9525
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9526
9527
/**
9528
 * Filter a node set, keeping only nodes for which the predicate expression
9529
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
9530
 * filtered result.
9531
 *
9532
 * @param ctxt  the XPath Parser context
9533
 * @param set  the node set to filter
9534
 * @param filterOpIndex  the index of the predicate/filter op
9535
 * @param minPos  minimum position in the filtered set (1-based)
9536
 * @param maxPos  maximum position in the filtered set (1-based)
9537
 * @param hasNsNodes  true if the node set may contain namespace nodes
9538
 */
9539
static void
9540
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
9541
          xmlNodeSetPtr set,
9542
          int filterOpIndex,
9543
                      int minPos, int maxPos,
9544
          int hasNsNodes)
9545
6.10k
{
9546
6.10k
    xmlXPathContextPtr xpctxt;
9547
6.10k
    xmlNodePtr oldnode;
9548
6.10k
    xmlDocPtr olddoc;
9549
6.10k
    xmlXPathStepOpPtr filterOp;
9550
6.10k
    int oldcs, oldpp;
9551
6.10k
    int i, j, pos;
9552
9553
6.10k
    if ((set == NULL) || (set->nodeNr == 0))
9554
0
        return;
9555
9556
    /*
9557
    * Check if the node set contains a sufficient number of nodes for
9558
    * the requested range.
9559
    */
9560
6.10k
    if (set->nodeNr < minPos) {
9561
0
        xmlXPathNodeSetClear(set, hasNsNodes);
9562
0
        return;
9563
0
    }
9564
9565
6.10k
    xpctxt = ctxt->context;
9566
6.10k
    oldnode = xpctxt->node;
9567
6.10k
    olddoc = xpctxt->doc;
9568
6.10k
    oldcs = xpctxt->contextSize;
9569
6.10k
    oldpp = xpctxt->proximityPosition;
9570
6.10k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9571
9572
6.10k
    xpctxt->contextSize = set->nodeNr;
9573
9574
1.06M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9575
1.05M
        xmlNodePtr node = set->nodeTab[i];
9576
1.05M
        int res;
9577
9578
1.05M
        xpctxt->node = node;
9579
1.05M
        xpctxt->proximityPosition = i + 1;
9580
9581
        /*
9582
        * Also set the xpath document in case things like
9583
        * key() are evaluated in the predicate.
9584
        *
9585
        * TODO: Get real doc for namespace nodes.
9586
        */
9587
1.05M
        if ((node->type != XML_NAMESPACE_DECL) &&
9588
1.05M
            (node->doc != NULL))
9589
1.05M
            xpctxt->doc = node->doc;
9590
9591
1.05M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9592
9593
1.05M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9594
51
            break;
9595
1.05M
        if (res < 0) {
9596
            /* Shouldn't happen */
9597
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9598
0
            break;
9599
0
        }
9600
9601
1.05M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9602
711k
            if (i != j) {
9603
207
                set->nodeTab[j] = node;
9604
207
                set->nodeTab[i] = NULL;
9605
207
            }
9606
9607
711k
            j += 1;
9608
711k
        } else {
9609
            /* Remove the entry from the initial node set. */
9610
348k
            set->nodeTab[i] = NULL;
9611
348k
            if (node->type == XML_NAMESPACE_DECL)
9612
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9613
348k
        }
9614
9615
1.05M
        if (res != 0) {
9616
711k
            if (pos == maxPos) {
9617
636
                i += 1;
9618
636
                break;
9619
636
            }
9620
9621
710k
            pos += 1;
9622
710k
        }
9623
1.05M
    }
9624
9625
    /* Free remaining nodes. */
9626
6.10k
    if (hasNsNodes) {
9627
1.85M
        for (; i < set->nodeNr; i++) {
9628
1.85M
            xmlNodePtr node = set->nodeTab[i];
9629
1.85M
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9630
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9631
1.85M
        }
9632
956
    }
9633
9634
6.10k
    set->nodeNr = j;
9635
9636
    /* If too many elements were removed, shrink table to preserve memory. */
9637
6.10k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9638
6.10k
        (set->nodeNr < set->nodeMax / 2)) {
9639
1.60k
        xmlNodePtr *tmp;
9640
1.60k
        int nodeMax = set->nodeNr;
9641
9642
1.60k
        if (nodeMax < XML_NODESET_DEFAULT)
9643
1.59k
            nodeMax = XML_NODESET_DEFAULT;
9644
1.60k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9645
1.60k
                nodeMax * sizeof(xmlNodePtr));
9646
1.60k
        if (tmp == NULL) {
9647
20
            xmlXPathPErrMemory(ctxt);
9648
1.58k
        } else {
9649
1.58k
            set->nodeTab = tmp;
9650
1.58k
            set->nodeMax = nodeMax;
9651
1.58k
        }
9652
1.60k
    }
9653
9654
6.10k
    xpctxt->node = oldnode;
9655
6.10k
    xpctxt->doc = olddoc;
9656
6.10k
    xpctxt->contextSize = oldcs;
9657
6.10k
    xpctxt->proximityPosition = oldpp;
9658
6.10k
}
9659
9660
/**
9661
 * Filter a node set, keeping only nodes for which the sequence of predicate
9662
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
9663
 * in the filtered result.
9664
 *
9665
 * @param ctxt  the XPath Parser context
9666
 * @param op  the predicate op
9667
 * @param set  the node set to filter
9668
 * @param minPos  minimum position in the filtered set (1-based)
9669
 * @param maxPos  maximum position in the filtered set (1-based)
9670
 * @param hasNsNodes  true if the node set may contain namespace nodes
9671
 */
9672
static void
9673
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
9674
          xmlXPathStepOpPtr op,
9675
          xmlNodeSetPtr set,
9676
                            int minPos, int maxPos,
9677
          int hasNsNodes)
9678
5.15k
{
9679
5.15k
    if (op->ch1 != -1) {
9680
0
  xmlXPathCompExprPtr comp = ctxt->comp;
9681
  /*
9682
  * Process inner predicates first.
9683
  */
9684
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9685
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9686
0
  }
9687
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9688
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9689
0
        ctxt->context->depth += 1;
9690
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9691
0
                                    1, set->nodeNr, hasNsNodes);
9692
0
        ctxt->context->depth -= 1;
9693
0
  CHECK_ERROR;
9694
0
    }
9695
9696
5.15k
    if (op->ch2 != -1)
9697
5.15k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9698
5.15k
}
9699
9700
static int
9701
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9702
          xmlXPathStepOpPtr op,
9703
          int *maxPos)
9704
210
{
9705
9706
210
    xmlXPathStepOpPtr exprOp;
9707
9708
    /*
9709
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
9710
    */
9711
9712
    /*
9713
    * If not -1, then ch1 will point to:
9714
    * 1) For predicates (XPATH_OP_PREDICATE):
9715
    *    - an inner predicate operator
9716
    * 2) For filters (XPATH_OP_FILTER):
9717
    *    - an inner filter operator OR
9718
    *    - an expression selecting the node set.
9719
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
9720
    */
9721
210
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9722
0
  return(0);
9723
9724
210
    if (op->ch2 != -1) {
9725
210
  exprOp = &ctxt->comp->steps[op->ch2];
9726
210
    } else
9727
0
  return(0);
9728
9729
210
    if ((exprOp != NULL) &&
9730
210
  (exprOp->op == XPATH_OP_VALUE) &&
9731
210
  (exprOp->value4 != NULL) &&
9732
210
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9733
160
    {
9734
160
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
9735
9736
  /*
9737
  * We have a "[n]" predicate here.
9738
  * TODO: Unfortunately this simplistic test here is not
9739
  * able to detect a position() predicate in compound
9740
  * expressions like "[@attr = 'a" and position() = 1],
9741
  * and even not the usage of position() in
9742
  * "[position() = 1]"; thus - obviously - a position-range,
9743
  * like it "[position() < 5]", is also not detected.
9744
  * Maybe we could rewrite the AST to ease the optimization.
9745
  */
9746
9747
160
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9748
160
      *maxPos = (int) floatval;
9749
160
            if (floatval == (double) *maxPos)
9750
160
                return(1);
9751
160
        }
9752
160
    }
9753
50
    return(0);
9754
210
}
9755
9756
static int
9757
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9758
                           xmlXPathStepOpPtr op,
9759
         xmlNodePtr * first, xmlNodePtr * last,
9760
         int toBool)
9761
31.8k
{
9762
9763
31.8k
#define XP_TEST_HIT \
9764
12.0M
    if (hasAxisRange != 0) { \
9765
783
  if (++pos == maxPos) { \
9766
1
      if (addNode(seq, cur) < 0) \
9767
1
          xmlXPathPErrMemory(ctxt); \
9768
1
      goto axis_range_end; } \
9769
12.0M
    } else { \
9770
12.0M
  if (addNode(seq, cur) < 0) \
9771
12.0M
      xmlXPathPErrMemory(ctxt); \
9772
12.0M
  if (breakOnFirstHit) goto first_hit; }
9773
9774
31.8k
#define XP_TEST_HIT_NS \
9775
215k
    if (hasAxisRange != 0) { \
9776
3.90k
  if (++pos == maxPos) { \
9777
3.90k
      hasNsNodes = 1; \
9778
3.90k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9779
3.90k
          xmlXPathPErrMemory(ctxt); \
9780
3.90k
  goto axis_range_end; } \
9781
211k
    } else { \
9782
211k
  hasNsNodes = 1; \
9783
211k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9784
211k
      xmlXPathPErrMemory(ctxt); \
9785
211k
  if (breakOnFirstHit) goto first_hit; }
9786
9787
31.8k
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9788
31.8k
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9789
31.8k
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9790
31.8k
    const xmlChar *prefix = op->value4;
9791
31.8k
    const xmlChar *name = op->value5;
9792
31.8k
    const xmlChar *URI = NULL;
9793
9794
31.8k
    int total = 0, hasNsNodes = 0;
9795
    /* The popped object holding the context nodes */
9796
31.8k
    xmlXPathObjectPtr obj;
9797
    /* The set of context nodes for the node tests */
9798
31.8k
    xmlNodeSetPtr contextSeq;
9799
31.8k
    int contextIdx;
9800
31.8k
    xmlNodePtr contextNode;
9801
    /* The final resulting node set wrt to all context nodes */
9802
31.8k
    xmlNodeSetPtr outSeq;
9803
    /*
9804
    * The temporary resulting node set wrt 1 context node.
9805
    * Used to feed predicate evaluation.
9806
    */
9807
31.8k
    xmlNodeSetPtr seq;
9808
31.8k
    xmlNodePtr cur;
9809
    /* First predicate operator */
9810
31.8k
    xmlXPathStepOpPtr predOp;
9811
31.8k
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9812
31.8k
    int hasPredicateRange, hasAxisRange, pos;
9813
31.8k
    int breakOnFirstHit;
9814
9815
31.8k
    xmlXPathTraversalFunction next = NULL;
9816
31.8k
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9817
31.8k
    xmlXPathNodeSetMergeFunction mergeAndClear;
9818
31.8k
    xmlNodePtr oldContextNode;
9819
31.8k
    xmlXPathContextPtr xpctxt = ctxt->context;
9820
9821
9822
31.8k
    CHECK_TYPE0(XPATH_NODESET);
9823
31.8k
    obj = xmlXPathValuePop(ctxt);
9824
    /*
9825
    * Setup namespaces.
9826
    */
9827
31.8k
    if (prefix != NULL) {
9828
179
        URI = xmlXPathNsLookup(xpctxt, prefix);
9829
179
        if (URI == NULL) {
9830
0
      xmlXPathReleaseObject(xpctxt, obj);
9831
0
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9832
0
                           "Undefined namespace prefix: %s\n", prefix);
9833
0
            return 0;
9834
0
  }
9835
179
    }
9836
    /*
9837
    * Setup axis.
9838
    *
9839
    * MAYBE FUTURE TODO: merging optimizations:
9840
    * - If the nodes to be traversed wrt to the initial nodes and
9841
    *   the current axis cannot overlap, then we could avoid searching
9842
    *   for duplicates during the merge.
9843
    *   But the question is how/when to evaluate if they cannot overlap.
9844
    *   Example: if we know that for two initial nodes, the one is
9845
    *   not in the ancestor-or-self axis of the other, then we could safely
9846
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
9847
    *   the descendant-or-self axis.
9848
    */
9849
31.8k
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9850
31.8k
    switch (axis) {
9851
156
        case AXIS_ANCESTOR:
9852
156
            first = NULL;
9853
156
            next = xmlXPathNextAncestor;
9854
156
            break;
9855
0
        case AXIS_ANCESTOR_OR_SELF:
9856
0
            first = NULL;
9857
0
            next = xmlXPathNextAncestorOrSelf;
9858
0
            break;
9859
20.0k
        case AXIS_ATTRIBUTE:
9860
20.0k
            first = NULL;
9861
20.0k
      last = NULL;
9862
20.0k
            next = xmlXPathNextAttribute;
9863
20.0k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9864
20.0k
            break;
9865
5.25k
        case AXIS_CHILD:
9866
5.25k
      last = NULL;
9867
5.25k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9868
5.25k
    (type == NODE_TYPE_NODE))
9869
5.22k
      {
9870
    /*
9871
    * Optimization if an element node type is 'element'.
9872
    */
9873
5.22k
    next = xmlXPathNextChildElement;
9874
5.22k
      } else
9875
27
    next = xmlXPathNextChild;
9876
5.25k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9877
5.25k
            break;
9878
983
        case AXIS_DESCENDANT:
9879
983
      last = NULL;
9880
983
            next = xmlXPathNextDescendant;
9881
983
            break;
9882
3.13k
        case AXIS_DESCENDANT_OR_SELF:
9883
3.13k
      last = NULL;
9884
3.13k
            next = xmlXPathNextDescendantOrSelf;
9885
3.13k
            break;
9886
0
        case AXIS_FOLLOWING:
9887
0
      last = NULL;
9888
0
            next = xmlXPathNextFollowing;
9889
0
            break;
9890
0
        case AXIS_FOLLOWING_SIBLING:
9891
0
      last = NULL;
9892
0
            next = xmlXPathNextFollowingSibling;
9893
0
            break;
9894
477
        case AXIS_NAMESPACE:
9895
477
            first = NULL;
9896
477
      last = NULL;
9897
477
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9898
477
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9899
477
            break;
9900
1.70k
        case AXIS_PARENT:
9901
1.70k
            first = NULL;
9902
1.70k
            next = xmlXPathNextParent;
9903
1.70k
            break;
9904
1
        case AXIS_PRECEDING:
9905
1
            first = NULL;
9906
1
            next = xmlXPathNextPrecedingInternal;
9907
1
            break;
9908
9
        case AXIS_PRECEDING_SIBLING:
9909
9
            first = NULL;
9910
9
            next = xmlXPathNextPrecedingSibling;
9911
9
            break;
9912
0
        case AXIS_SELF:
9913
0
            first = NULL;
9914
0
      last = NULL;
9915
0
            next = xmlXPathNextSelf;
9916
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9917
0
            break;
9918
31.8k
    }
9919
9920
31.8k
    if (next == NULL) {
9921
0
  xmlXPathReleaseObject(xpctxt, obj);
9922
0
        return(0);
9923
0
    }
9924
31.8k
    contextSeq = obj->nodesetval;
9925
31.8k
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9926
196
        xmlXPathValuePush(ctxt, obj);
9927
196
        return(0);
9928
196
    }
9929
    /*
9930
    * Predicate optimization ---------------------------------------------
9931
    * If this step has a last predicate, which contains a position(),
9932
    * then we'll optimize (although not exactly "position()", but only
9933
    * the  short-hand form, i.e., "[n]".
9934
    *
9935
    * Example - expression "/foo[parent::bar][1]":
9936
    *
9937
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
9938
    *   ROOT                               -- op->ch1
9939
    *   PREDICATE                          -- op->ch2 (predOp)
9940
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
9941
    *       SORT
9942
    *         COLLECT  'parent' 'name' 'node' bar
9943
    *           NODE
9944
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
9945
    *
9946
    */
9947
31.6k
    maxPos = 0;
9948
31.6k
    predOp = NULL;
9949
31.6k
    hasPredicateRange = 0;
9950
31.6k
    hasAxisRange = 0;
9951
31.6k
    if (op->ch2 != -1) {
9952
  /*
9953
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9954
  */
9955
210
  predOp = &ctxt->comp->steps[op->ch2];
9956
210
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9957
160
      if (predOp->ch1 != -1) {
9958
    /*
9959
    * Use the next inner predicate operator.
9960
    */
9961
0
    predOp = &ctxt->comp->steps[predOp->ch1];
9962
0
    hasPredicateRange = 1;
9963
160
      } else {
9964
    /*
9965
    * There's no other predicate than the [n] predicate.
9966
    */
9967
160
    predOp = NULL;
9968
160
    hasAxisRange = 1;
9969
160
      }
9970
160
  }
9971
210
    }
9972
31.6k
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
9973
    /*
9974
    * Axis traversal -----------------------------------------------------
9975
    */
9976
    /*
9977
     * 2.3 Node Tests
9978
     *  - For the attribute axis, the principal node type is attribute.
9979
     *  - For the namespace axis, the principal node type is namespace.
9980
     *  - For other axes, the principal node type is element.
9981
     *
9982
     * A node test * is true for any node of the
9983
     * principal node type. For example, child::* will
9984
     * select all element children of the context node
9985
     */
9986
31.6k
    oldContextNode = xpctxt->node;
9987
31.6k
    addNode = xmlXPathNodeSetAddUnique;
9988
31.6k
    outSeq = NULL;
9989
31.6k
    seq = NULL;
9990
31.6k
    contextNode = NULL;
9991
31.6k
    contextIdx = 0;
9992
9993
9994
1.06M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
9995
1.06M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
9996
1.03M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
9997
9998
1.03M
  if (seq == NULL) {
9999
33.5k
      seq = xmlXPathNodeSetCreate(NULL);
10000
33.5k
      if (seq == NULL) {
10001
1
                xmlXPathPErrMemory(ctxt);
10002
1
    total = 0;
10003
1
    goto error;
10004
1
      }
10005
33.5k
  }
10006
  /*
10007
  * Traverse the axis and test the nodes.
10008
  */
10009
1.03M
  pos = 0;
10010
1.03M
  cur = NULL;
10011
1.03M
  hasNsNodes = 0;
10012
13.5M
        do {
10013
13.5M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10014
13
                goto error;
10015
10016
13.5M
            cur = next(ctxt, cur);
10017
13.5M
            if (cur == NULL)
10018
1.02M
                break;
10019
10020
      /*
10021
      * QUESTION TODO: What does the "first" and "last" stuff do?
10022
      */
10023
12.5M
            if ((first != NULL) && (*first != NULL)) {
10024
0
    if (*first == cur)
10025
0
        break;
10026
0
    if (((total % 256) == 0) &&
10027
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10028
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10029
#else
10030
        (xmlXPathCmpNodes(*first, cur) >= 0))
10031
#endif
10032
0
    {
10033
0
        break;
10034
0
    }
10035
0
      }
10036
12.5M
      if ((last != NULL) && (*last != NULL)) {
10037
0
    if (*last == cur)
10038
0
        break;
10039
0
    if (((total % 256) == 0) &&
10040
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10041
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10042
#else
10043
        (xmlXPathCmpNodes(cur, *last) >= 0))
10044
#endif
10045
0
    {
10046
0
        break;
10047
0
    }
10048
0
      }
10049
10050
12.5M
            total++;
10051
10052
12.5M
      switch (test) {
10053
0
                case NODE_TEST_NONE:
10054
0
        total = 0;
10055
0
        goto error;
10056
11.8M
                case NODE_TEST_TYPE:
10057
11.8M
        if (type == NODE_TYPE_NODE) {
10058
11.8M
      switch (cur->type) {
10059
4.19k
          case XML_DOCUMENT_NODE:
10060
4.19k
          case XML_HTML_DOCUMENT_NODE:
10061
10.2M
          case XML_ELEMENT_NODE:
10062
10.2M
          case XML_ATTRIBUTE_NODE:
10063
10.3M
          case XML_PI_NODE:
10064
10.3M
          case XML_COMMENT_NODE:
10065
10.3M
          case XML_CDATA_SECTION_NODE:
10066
11.8M
          case XML_TEXT_NODE:
10067
11.8M
        XP_TEST_HIT
10068
11.8M
        break;
10069
11.8M
          case XML_NAMESPACE_DECL: {
10070
5.52k
        if (axis == AXIS_NAMESPACE) {
10071
0
            XP_TEST_HIT_NS
10072
5.52k
        } else {
10073
5.52k
                              hasNsNodes = 1;
10074
5.52k
            XP_TEST_HIT
10075
5.52k
        }
10076
5.52k
        break;
10077
5.52k
                            }
10078
12.9k
          default:
10079
12.9k
        break;
10080
11.8M
      }
10081
11.8M
        } else if (cur->type == (xmlElementType) type) {
10082
803
      if (cur->type == XML_NAMESPACE_DECL)
10083
0
          XP_TEST_HIT_NS
10084
803
      else
10085
803
          XP_TEST_HIT
10086
7.74k
        } else if ((type == NODE_TYPE_TEXT) &&
10087
7.74k
       (cur->type == XML_CDATA_SECTION_NODE))
10088
1
        {
10089
1
      XP_TEST_HIT
10090
1
        }
10091
11.8M
        break;
10092
11.8M
                case NODE_TEST_PI:
10093
0
                    if ((cur->type == XML_PI_NODE) &&
10094
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10095
0
        {
10096
0
      XP_TEST_HIT
10097
0
                    }
10098
0
                    break;
10099
549k
                case NODE_TEST_ALL:
10100
549k
                    if (axis == AXIS_ATTRIBUTE) {
10101
20.8k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10102
20.8k
      {
10103
20.8k
                            if (prefix == NULL)
10104
20.8k
          {
10105
20.8k
        XP_TEST_HIT
10106
20.8k
                            } else if ((cur->ns != NULL) &&
10107
0
        (xmlStrEqual(URI, cur->ns->href)))
10108
0
          {
10109
0
        XP_TEST_HIT
10110
0
                            }
10111
20.8k
                        }
10112
528k
                    } else if (axis == AXIS_NAMESPACE) {
10113
211k
                        if (cur->type == XML_NAMESPACE_DECL)
10114
211k
      {
10115
211k
          XP_TEST_HIT_NS
10116
211k
                        }
10117
316k
                    } else {
10118
316k
                        if (cur->type == XML_ELEMENT_NODE) {
10119
171k
                            if (prefix == NULL)
10120
171k
          {
10121
171k
        XP_TEST_HIT
10122
10123
171k
                            } else if ((cur->ns != NULL) &&
10124
0
        (xmlStrEqual(URI, cur->ns->href)))
10125
0
          {
10126
0
        XP_TEST_HIT
10127
0
                            }
10128
171k
                        }
10129
316k
                    }
10130
549k
                    break;
10131
549k
                case NODE_TEST_NS:{
10132
                        /* TODO */
10133
0
                        break;
10134
549k
                    }
10135
71.6k
                case NODE_TEST_NAME:
10136
71.6k
                    if (axis == AXIS_ATTRIBUTE) {
10137
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
10138
0
          break;
10139
71.6k
        } else if (axis == AXIS_NAMESPACE) {
10140
8.11k
                        if (cur->type != XML_NAMESPACE_DECL)
10141
0
          break;
10142
63.5k
        } else {
10143
63.5k
            if (cur->type != XML_ELEMENT_NODE)
10144
10.1k
          break;
10145
63.5k
        }
10146
61.4k
                    switch (cur->type) {
10147
53.3k
                        case XML_ELEMENT_NODE:
10148
53.3k
                            if (xmlStrEqual(name, cur->name)) {
10149
63
                                if (prefix == NULL) {
10150
63
                                    if (cur->ns == NULL)
10151
63
            {
10152
63
          XP_TEST_HIT
10153
63
                                    }
10154
63
                                } else {
10155
0
                                    if ((cur->ns != NULL) &&
10156
0
                                        (xmlStrEqual(URI, cur->ns->href)))
10157
0
            {
10158
0
          XP_TEST_HIT
10159
0
                                    }
10160
0
                                }
10161
63
                            }
10162
53.3k
                            break;
10163
53.3k
                        case XML_ATTRIBUTE_NODE:{
10164
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10165
10166
0
                                if (xmlStrEqual(name, attr->name)) {
10167
0
                                    if (prefix == NULL) {
10168
0
                                        if ((attr->ns == NULL) ||
10169
0
                                            (attr->ns->prefix == NULL))
10170
0
          {
10171
0
              XP_TEST_HIT
10172
0
                                        }
10173
0
                                    } else {
10174
0
                                        if ((attr->ns != NULL) &&
10175
0
                                            (xmlStrEqual(URI,
10176
0
                attr->ns->href)))
10177
0
          {
10178
0
              XP_TEST_HIT
10179
0
                                        }
10180
0
                                    }
10181
0
                                }
10182
0
                                break;
10183
0
                            }
10184
8.11k
                        case XML_NAMESPACE_DECL:
10185
8.11k
                            if (cur->type == XML_NAMESPACE_DECL) {
10186
8.11k
                                xmlNsPtr ns = (xmlNsPtr) cur;
10187
10188
8.11k
                                if ((ns->prefix != NULL) && (name != NULL)
10189
8.11k
                                    && (xmlStrEqual(ns->prefix, name)))
10190
3.90k
        {
10191
3.90k
            XP_TEST_HIT_NS
10192
3.90k
                                }
10193
8.11k
                            }
10194
4.21k
                            break;
10195
4.21k
                        default:
10196
0
                            break;
10197
61.4k
                    }
10198
57.5k
                    break;
10199
12.5M
      } /* switch(test) */
10200
12.5M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10201
10202
1.02M
  goto apply_predicates;
10203
10204
1.02M
axis_range_end: /* ----------------------------------------------------- */
10205
  /*
10206
  * We have a "/foo[n]", and position() = n was reached.
10207
  * Note that we can have as well "/foo/::parent::foo[1]", so
10208
  * a duplicate-aware merge is still needed.
10209
  * Merge with the result.
10210
  */
10211
3.90k
  if (outSeq == NULL) {
10212
157
      outSeq = seq;
10213
157
      seq = NULL;
10214
3.74k
  } else {
10215
3.74k
      outSeq = mergeAndClear(outSeq, seq);
10216
3.74k
            if (outSeq == NULL)
10217
0
                xmlXPathPErrMemory(ctxt);
10218
3.74k
        }
10219
  /*
10220
  * Break if only a true/false result was requested.
10221
  */
10222
3.90k
  if (toBool)
10223
0
      break;
10224
3.90k
  continue;
10225
10226
3.90k
first_hit: /* ---------------------------------------------------------- */
10227
  /*
10228
  * Break if only a true/false result was requested and
10229
  * no predicates existed and a node test succeeded.
10230
  */
10231
0
  if (outSeq == NULL) {
10232
0
      outSeq = seq;
10233
0
      seq = NULL;
10234
0
  } else {
10235
0
      outSeq = mergeAndClear(outSeq, seq);
10236
0
            if (outSeq == NULL)
10237
0
                xmlXPathPErrMemory(ctxt);
10238
0
        }
10239
0
  break;
10240
10241
1.02M
apply_predicates: /* --------------------------------------------------- */
10242
1.02M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10243
0
      goto error;
10244
10245
        /*
10246
  * Apply predicates.
10247
  */
10248
1.02M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
10249
      /*
10250
      * E.g. when we have a "/foo[some expression][n]".
10251
      */
10252
      /*
10253
      * QUESTION TODO: The old predicate evaluation took into
10254
      *  account location-sets.
10255
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10256
      *  Do we expect such a set here?
10257
      *  All what I learned now from the evaluation semantics
10258
      *  does not indicate that a location-set will be processed
10259
      *  here, so this looks OK.
10260
      */
10261
      /*
10262
      * Iterate over all predicates, starting with the outermost
10263
      * predicate.
10264
      * TODO: Problem: we cannot execute the inner predicates first
10265
      *  since we cannot go back *up* the operator tree!
10266
      *  Options we have:
10267
      *  1) Use of recursive functions (like is it currently done
10268
      *     via xmlXPathCompOpEval())
10269
      *  2) Add a predicate evaluation information stack to the
10270
      *     context struct
10271
      *  3) Change the way the operators are linked; we need a
10272
      *     "parent" field on xmlXPathStepOp
10273
      *
10274
      * For the moment, I'll try to solve this with a recursive
10275
      * function: xmlXPathCompOpEvalPredicate().
10276
      */
10277
5.15k
      if (hasPredicateRange != 0)
10278
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10279
0
              hasNsNodes);
10280
5.15k
      else
10281
5.15k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10282
5.15k
              hasNsNodes);
10283
10284
5.15k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10285
18
    total = 0;
10286
18
    goto error;
10287
18
      }
10288
5.15k
        }
10289
10290
1.02M
        if (seq->nodeNr > 0) {
10291
      /*
10292
      * Add to result set.
10293
      */
10294
523k
      if (outSeq == NULL) {
10295
14.9k
    outSeq = seq;
10296
14.9k
    seq = NULL;
10297
508k
      } else {
10298
508k
    outSeq = mergeAndClear(outSeq, seq);
10299
508k
                if (outSeq == NULL)
10300
0
                    xmlXPathPErrMemory(ctxt);
10301
508k
      }
10302
10303
523k
            if (toBool)
10304
0
                break;
10305
523k
  }
10306
1.02M
    }
10307
10308
31.6k
error:
10309
31.6k
    if ((obj->boolval) && (obj->user != NULL)) {
10310
  /*
10311
  * QUESTION TODO: What does this do and why?
10312
  * TODO: Do we have to do this also for the "error"
10313
  * cleanup further down?
10314
  */
10315
0
  ctxt->value->boolval = 1;
10316
0
  ctxt->value->user = obj->user;
10317
0
  obj->user = NULL;
10318
0
  obj->boolval = 0;
10319
0
    }
10320
31.6k
    xmlXPathReleaseObject(xpctxt, obj);
10321
10322
    /*
10323
    * Ensure we return at least an empty set.
10324
    */
10325
31.6k
    if (outSeq == NULL) {
10326
16.4k
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10327
16.4k
      outSeq = seq;
10328
16.4k
        } else {
10329
14
      outSeq = xmlXPathNodeSetCreate(NULL);
10330
14
            if (outSeq == NULL)
10331
1
                xmlXPathPErrMemory(ctxt);
10332
14
        }
10333
16.4k
    }
10334
31.6k
    if ((seq != NULL) && (seq != outSeq)) {
10335
1.95k
   xmlXPathFreeNodeSet(seq);
10336
1.95k
    }
10337
    /*
10338
    * Hand over the result. Better to push the set also in
10339
    * case of errors.
10340
    */
10341
31.6k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10342
    /*
10343
    * Reset the context node.
10344
    */
10345
31.6k
    xpctxt->node = oldContextNode;
10346
    /*
10347
    * When traversing the namespace axis in "toBool" mode, it's
10348
    * possible that tmpNsList wasn't freed.
10349
    */
10350
31.6k
    if (xpctxt->tmpNsList != NULL) {
10351
156
        xmlFree(xpctxt->tmpNsList);
10352
156
        xpctxt->tmpNsList = NULL;
10353
156
    }
10354
10355
31.6k
    return(total);
10356
31.6k
}
10357
10358
static int
10359
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10360
            xmlXPathStepOpPtr op, xmlNodePtr * first);
10361
10362
/**
10363
 * Evaluate the Precompiled XPath operation searching only the first
10364
 * element in document order
10365
 *
10366
 * @param ctxt  the XPath parser context with the compiled expression
10367
 * @param op  an XPath compiled operation
10368
 * @param first  the first elem found so far
10369
 * @returns the number of examined objects.
10370
 */
10371
static int
10372
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10373
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
10374
823
{
10375
823
    int total = 0, cur;
10376
823
    xmlXPathCompExprPtr comp;
10377
823
    xmlXPathObjectPtr arg1, arg2;
10378
10379
823
    CHECK_ERROR0;
10380
823
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10381
0
        return(0);
10382
823
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10383
823
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10384
823
    ctxt->context->depth += 1;
10385
823
    comp = ctxt->comp;
10386
823
    switch (op->op) {
10387
0
        case XPATH_OP_END:
10388
0
            break;
10389
30
        case XPATH_OP_UNION:
10390
30
            total =
10391
30
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10392
30
                                        first);
10393
30
      CHECK_ERROR0;
10394
25
            if ((ctxt->value != NULL)
10395
25
                && (ctxt->value->type == XPATH_NODESET)
10396
25
                && (ctxt->value->nodesetval != NULL)
10397
25
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10398
                /*
10399
                 * limit tree traversing to first node in the result
10400
                 */
10401
    /*
10402
    * OPTIMIZE TODO: This implicitly sorts
10403
    *  the result, even if not needed. E.g. if the argument
10404
    *  of the count() function, no sorting is needed.
10405
    * OPTIMIZE TODO: How do we know if the node-list wasn't
10406
    *  already sorted?
10407
    */
10408
10
    if (ctxt->value->nodesetval->nodeNr > 1)
10409
10
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10410
10
                *first = ctxt->value->nodesetval->nodeTab[0];
10411
10
            }
10412
25
            cur =
10413
25
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10414
25
                                        first);
10415
25
      CHECK_ERROR0;
10416
10417
20
            arg2 = xmlXPathValuePop(ctxt);
10418
20
            arg1 = xmlXPathValuePop(ctxt);
10419
20
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10420
20
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10421
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10422
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10423
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10424
0
            }
10425
20
            if ((ctxt->context->opLimit != 0) &&
10426
20
                (((arg1->nodesetval != NULL) &&
10427
20
                  (xmlXPathCheckOpLimit(ctxt,
10428
20
                                        arg1->nodesetval->nodeNr) < 0)) ||
10429
20
                 ((arg2->nodesetval != NULL) &&
10430
17
                  (xmlXPathCheckOpLimit(ctxt,
10431
17
                                        arg2->nodesetval->nodeNr) < 0)))) {
10432
3
          xmlXPathReleaseObject(ctxt->context, arg1);
10433
3
          xmlXPathReleaseObject(ctxt->context, arg2);
10434
3
                break;
10435
3
            }
10436
10437
17
            if ((arg2->nodesetval != NULL) &&
10438
17
                (arg2->nodesetval->nodeNr != 0)) {
10439
17
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10440
17
                                                        arg2->nodesetval);
10441
17
                if (arg1->nodesetval == NULL)
10442
0
                    xmlXPathPErrMemory(ctxt);
10443
17
            }
10444
17
            xmlXPathValuePush(ctxt, arg1);
10445
17
      xmlXPathReleaseObject(ctxt->context, arg2);
10446
17
            total += cur;
10447
17
            break;
10448
0
        case XPATH_OP_ROOT:
10449
0
            xmlXPathRoot(ctxt);
10450
0
            break;
10451
10
        case XPATH_OP_NODE:
10452
10
            if (op->ch1 != -1)
10453
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10454
10
      CHECK_ERROR0;
10455
10
            if (op->ch2 != -1)
10456
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10457
10
      CHECK_ERROR0;
10458
10
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10459
10
    ctxt->context->node));
10460
10
            break;
10461
31
        case XPATH_OP_COLLECT:{
10462
31
                if (op->ch1 == -1)
10463
0
                    break;
10464
10465
31
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10466
31
    CHECK_ERROR0;
10467
10468
30
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10469
30
                break;
10470
31
            }
10471
0
        case XPATH_OP_VALUE:
10472
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10473
0
            break;
10474
16
        case XPATH_OP_SORT:
10475
16
            if (op->ch1 != -1)
10476
16
                total +=
10477
16
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10478
16
                                            first);
10479
16
      CHECK_ERROR0;
10480
8
            if ((ctxt->value != NULL)
10481
8
                && (ctxt->value->type == XPATH_NODESET)
10482
8
                && (ctxt->value->nodesetval != NULL)
10483
8
    && (ctxt->value->nodesetval->nodeNr > 1))
10484
7
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10485
8
            break;
10486
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10487
736
  case XPATH_OP_FILTER:
10488
736
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10489
736
            break;
10490
0
#endif
10491
0
        default:
10492
0
            total += xmlXPathCompOpEval(ctxt, op);
10493
0
            break;
10494
823
    }
10495
10496
804
    ctxt->context->depth -= 1;
10497
804
    return(total);
10498
823
}
10499
10500
/**
10501
 * Evaluate the Precompiled XPath operation searching only the last
10502
 * element in document order
10503
 *
10504
 * @param ctxt  the XPath parser context with the compiled expression
10505
 * @param op  an XPath compiled operation
10506
 * @param last  the last elem found so far
10507
 * @returns the number of nodes traversed
10508
 */
10509
static int
10510
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10511
                       xmlNodePtr * last)
10512
0
{
10513
0
    int total = 0, cur;
10514
0
    xmlXPathCompExprPtr comp;
10515
0
    xmlXPathObjectPtr arg1, arg2;
10516
10517
0
    CHECK_ERROR0;
10518
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10519
0
        return(0);
10520
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10521
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10522
0
    ctxt->context->depth += 1;
10523
0
    comp = ctxt->comp;
10524
0
    switch (op->op) {
10525
0
        case XPATH_OP_END:
10526
0
            break;
10527
0
        case XPATH_OP_UNION:
10528
0
            total =
10529
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10530
0
      CHECK_ERROR0;
10531
0
            if ((ctxt->value != NULL)
10532
0
                && (ctxt->value->type == XPATH_NODESET)
10533
0
                && (ctxt->value->nodesetval != NULL)
10534
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10535
                /*
10536
                 * limit tree traversing to first node in the result
10537
                 */
10538
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10539
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10540
0
                *last =
10541
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10542
0
                                                     nodesetval->nodeNr -
10543
0
                                                     1];
10544
0
            }
10545
0
            cur =
10546
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10547
0
      CHECK_ERROR0;
10548
0
            if ((ctxt->value != NULL)
10549
0
                && (ctxt->value->type == XPATH_NODESET)
10550
0
                && (ctxt->value->nodesetval != NULL)
10551
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10552
0
            }
10553
10554
0
            arg2 = xmlXPathValuePop(ctxt);
10555
0
            arg1 = xmlXPathValuePop(ctxt);
10556
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10557
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10558
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10559
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10560
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10561
0
            }
10562
0
            if ((ctxt->context->opLimit != 0) &&
10563
0
                (((arg1->nodesetval != NULL) &&
10564
0
                  (xmlXPathCheckOpLimit(ctxt,
10565
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10566
0
                 ((arg2->nodesetval != NULL) &&
10567
0
                  (xmlXPathCheckOpLimit(ctxt,
10568
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10569
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10570
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10571
0
                break;
10572
0
            }
10573
10574
0
            if ((arg2->nodesetval != NULL) &&
10575
0
                (arg2->nodesetval->nodeNr != 0)) {
10576
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10577
0
                                                        arg2->nodesetval);
10578
0
                if (arg1->nodesetval == NULL)
10579
0
                    xmlXPathPErrMemory(ctxt);
10580
0
            }
10581
0
            xmlXPathValuePush(ctxt, arg1);
10582
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10583
0
            total += cur;
10584
0
            break;
10585
0
        case XPATH_OP_ROOT:
10586
0
            xmlXPathRoot(ctxt);
10587
0
            break;
10588
0
        case XPATH_OP_NODE:
10589
0
            if (op->ch1 != -1)
10590
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10591
0
      CHECK_ERROR0;
10592
0
            if (op->ch2 != -1)
10593
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10594
0
      CHECK_ERROR0;
10595
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10596
0
    ctxt->context->node));
10597
0
            break;
10598
0
        case XPATH_OP_COLLECT:{
10599
0
                if (op->ch1 == -1)
10600
0
                    break;
10601
10602
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10603
0
    CHECK_ERROR0;
10604
10605
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10606
0
                break;
10607
0
            }
10608
0
        case XPATH_OP_VALUE:
10609
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10610
0
            break;
10611
0
        case XPATH_OP_SORT:
10612
0
            if (op->ch1 != -1)
10613
0
                total +=
10614
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10615
0
                                           last);
10616
0
      CHECK_ERROR0;
10617
0
            if ((ctxt->value != NULL)
10618
0
                && (ctxt->value->type == XPATH_NODESET)
10619
0
                && (ctxt->value->nodesetval != NULL)
10620
0
    && (ctxt->value->nodesetval->nodeNr > 1))
10621
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10622
0
            break;
10623
0
        default:
10624
0
            total += xmlXPathCompOpEval(ctxt, op);
10625
0
            break;
10626
0
    }
10627
10628
0
    ctxt->context->depth -= 1;
10629
0
    return (total);
10630
0
}
10631
10632
#ifdef XP_OPTIMIZED_FILTER_FIRST
10633
static int
10634
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10635
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10636
736
{
10637
736
    int total = 0;
10638
736
    xmlXPathCompExprPtr comp;
10639
736
    xmlXPathObjectPtr obj;
10640
736
    xmlNodeSetPtr set;
10641
10642
736
    CHECK_ERROR0;
10643
736
    comp = ctxt->comp;
10644
    /*
10645
    * Optimization for ()[last()] selection i.e. the last elem
10646
    */
10647
736
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10648
736
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10649
736
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10650
736
  int f = comp->steps[op->ch2].ch1;
10651
10652
736
  if ((f != -1) &&
10653
736
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10654
736
      (comp->steps[f].value5 == NULL) &&
10655
736
      (comp->steps[f].value == 0) &&
10656
736
      (comp->steps[f].value4 != NULL) &&
10657
736
      (xmlStrEqual
10658
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
10659
0
      xmlNodePtr last = NULL;
10660
10661
0
      total +=
10662
0
    xmlXPathCompOpEvalLast(ctxt,
10663
0
        &comp->steps[op->ch1],
10664
0
        &last);
10665
0
      CHECK_ERROR0;
10666
      /*
10667
      * The nodeset should be in document order,
10668
      * Keep only the last value
10669
      */
10670
0
      if ((ctxt->value != NULL) &&
10671
0
    (ctxt->value->type == XPATH_NODESET) &&
10672
0
    (ctxt->value->nodesetval != NULL) &&
10673
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10674
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
10675
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10676
0
    *first = *(ctxt->value->nodesetval->nodeTab);
10677
0
      }
10678
0
      return (total);
10679
0
  }
10680
736
    }
10681
10682
736
    if (op->ch1 != -1)
10683
736
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10684
736
    CHECK_ERROR0;
10685
736
    if (op->ch2 == -1)
10686
0
  return (total);
10687
736
    if (ctxt->value == NULL)
10688
0
  return (total);
10689
10690
    /*
10691
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
10692
     * the stack. We have to temporarily remove the nodeset object from the
10693
     * stack to avoid freeing it prematurely.
10694
     */
10695
736
    CHECK_TYPE0(XPATH_NODESET);
10696
736
    obj = xmlXPathValuePop(ctxt);
10697
736
    set = obj->nodesetval;
10698
736
    if (set != NULL) {
10699
736
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10700
736
        if (set->nodeNr > 0)
10701
0
            *first = set->nodeTab[0];
10702
736
    }
10703
736
    xmlXPathValuePush(ctxt, obj);
10704
10705
736
    return (total);
10706
736
}
10707
#endif /* XP_OPTIMIZED_FILTER_FIRST */
10708
10709
/**
10710
 * Evaluate the Precompiled XPath operation
10711
 *
10712
 * @param ctxt  the XPath parser context with the compiled expression
10713
 * @param op  an XPath compiled operation
10714
 * @returns the number of nodes traversed
10715
 */
10716
static int
10717
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10718
1.10M
{
10719
1.10M
    int total = 0;
10720
1.10M
    int equal, ret;
10721
1.10M
    xmlXPathCompExprPtr comp;
10722
1.10M
    xmlXPathObjectPtr arg1, arg2;
10723
10724
1.10M
    CHECK_ERROR0;
10725
1.10M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10726
2
        return(0);
10727
1.10M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10728
1.10M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10729
1.10M
    ctxt->context->depth += 1;
10730
1.10M
    comp = ctxt->comp;
10731
1.10M
    switch (op->op) {
10732
0
        case XPATH_OP_END:
10733
0
            break;
10734
63
        case XPATH_OP_AND:
10735
63
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10736
63
      CHECK_ERROR0;
10737
63
            xmlXPathBooleanFunction(ctxt, 1);
10738
63
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10739
45
                break;
10740
18
            arg2 = xmlXPathValuePop(ctxt);
10741
18
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10742
18
      if (ctxt->error) {
10743
0
    xmlXPathFreeObject(arg2);
10744
0
    break;
10745
0
      }
10746
18
            xmlXPathBooleanFunction(ctxt, 1);
10747
18
            if (ctxt->value != NULL)
10748
18
                ctxt->value->boolval &= arg2->boolval;
10749
18
      xmlXPathReleaseObject(ctxt->context, arg2);
10750
18
            break;
10751
0
        case XPATH_OP_OR:
10752
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10753
0
      CHECK_ERROR0;
10754
0
            xmlXPathBooleanFunction(ctxt, 1);
10755
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10756
0
                break;
10757
0
            arg2 = xmlXPathValuePop(ctxt);
10758
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10759
0
      if (ctxt->error) {
10760
0
    xmlXPathFreeObject(arg2);
10761
0
    break;
10762
0
      }
10763
0
            xmlXPathBooleanFunction(ctxt, 1);
10764
0
            if (ctxt->value != NULL)
10765
0
                ctxt->value->boolval |= arg2->boolval;
10766
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10767
0
            break;
10768
1.23k
        case XPATH_OP_EQUAL:
10769
1.23k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10770
1.23k
      CHECK_ERROR0;
10771
266
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10772
266
      CHECK_ERROR0;
10773
265
      if (op->value)
10774
265
    equal = xmlXPathEqualValues(ctxt);
10775
0
      else
10776
0
    equal = xmlXPathNotEqualValues(ctxt);
10777
265
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10778
265
            break;
10779
514
        case XPATH_OP_CMP:
10780
514
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10781
514
      CHECK_ERROR0;
10782
514
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10783
514
      CHECK_ERROR0;
10784
424
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10785
424
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10786
424
            break;
10787
302k
        case XPATH_OP_PLUS:
10788
302k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10789
302k
      CHECK_ERROR0;
10790
302k
            if (op->ch2 != -1) {
10791
6
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10792
6
      }
10793
302k
      CHECK_ERROR0;
10794
302k
            if (op->value == 0)
10795
0
                xmlXPathSubValues(ctxt);
10796
302k
            else if (op->value == 1)
10797
2
                xmlXPathAddValues(ctxt);
10798
302k
            else if (op->value == 2)
10799
302k
                xmlXPathValueFlipSign(ctxt);
10800
0
            else if (op->value == 3) {
10801
0
                CAST_TO_NUMBER;
10802
0
                CHECK_TYPE0(XPATH_NUMBER);
10803
0
            }
10804
302k
            break;
10805
302k
        case XPATH_OP_MULT:
10806
531
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10807
531
      CHECK_ERROR0;
10808
531
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10809
531
      CHECK_ERROR0;
10810
522
            if (op->value == 0)
10811
522
                xmlXPathMultValues(ctxt);
10812
0
            else if (op->value == 1)
10813
0
                xmlXPathDivValues(ctxt);
10814
0
            else if (op->value == 2)
10815
0
                xmlXPathModValues(ctxt);
10816
522
            break;
10817
22.3k
        case XPATH_OP_UNION:
10818
22.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10819
22.3k
      CHECK_ERROR0;
10820
516
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10821
516
      CHECK_ERROR0;
10822
10823
504
            arg2 = xmlXPathValuePop(ctxt);
10824
504
            arg1 = xmlXPathValuePop(ctxt);
10825
504
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10826
504
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10827
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10828
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10829
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10830
0
            }
10831
504
            if ((ctxt->context->opLimit != 0) &&
10832
504
                (((arg1->nodesetval != NULL) &&
10833
504
                  (xmlXPathCheckOpLimit(ctxt,
10834
504
                                        arg1->nodesetval->nodeNr) < 0)) ||
10835
504
                 ((arg2->nodesetval != NULL) &&
10836
501
                  (xmlXPathCheckOpLimit(ctxt,
10837
501
                                        arg2->nodesetval->nodeNr) < 0)))) {
10838
7
          xmlXPathReleaseObject(ctxt->context, arg1);
10839
7
          xmlXPathReleaseObject(ctxt->context, arg2);
10840
7
                break;
10841
7
            }
10842
10843
497
      if (((arg2->nodesetval != NULL) &&
10844
497
     (arg2->nodesetval->nodeNr != 0)))
10845
378
      {
10846
378
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10847
378
              arg2->nodesetval);
10848
378
                if (arg1->nodesetval == NULL)
10849
0
                    xmlXPathPErrMemory(ctxt);
10850
378
      }
10851
10852
497
            xmlXPathValuePush(ctxt, arg1);
10853
497
      xmlXPathReleaseObject(ctxt->context, arg2);
10854
497
            break;
10855
6.07k
        case XPATH_OP_ROOT:
10856
6.07k
            xmlXPathRoot(ctxt);
10857
6.07k
            break;
10858
27.9k
        case XPATH_OP_NODE:
10859
27.9k
            if (op->ch1 != -1)
10860
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10861
27.9k
      CHECK_ERROR0;
10862
27.9k
            if (op->ch2 != -1)
10863
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10864
27.9k
      CHECK_ERROR0;
10865
27.9k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10866
27.9k
                                                    ctxt->context->node));
10867
27.9k
            break;
10868
31.6k
        case XPATH_OP_COLLECT:{
10869
31.6k
                if (op->ch1 == -1)
10870
0
                    break;
10871
10872
31.6k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10873
31.6k
    CHECK_ERROR0;
10874
10875
31.6k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10876
31.6k
                break;
10877
31.6k
            }
10878
1.42k
        case XPATH_OP_VALUE:
10879
1.42k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10880
1.42k
            break;
10881
0
        case XPATH_OP_VARIABLE:{
10882
0
    xmlXPathObjectPtr val;
10883
10884
0
                if (op->ch1 != -1)
10885
0
                    total +=
10886
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10887
0
                if (op->value5 == NULL) {
10888
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10889
0
        if (val == NULL) {
10890
0
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10891
0
                                       "Undefined variable: %s\n", op->value4);
10892
0
                        return 0;
10893
0
                    }
10894
0
                    xmlXPathValuePush(ctxt, val);
10895
0
    } else {
10896
0
                    const xmlChar *URI;
10897
10898
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10899
0
                    if (URI == NULL) {
10900
0
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10901
0
                                       "Undefined namespace prefix: %s\n",
10902
0
                                       op->value5);
10903
0
                        return 0;
10904
0
                    }
10905
0
        val = xmlXPathVariableLookupNS(ctxt->context,
10906
0
                                                       op->value4, URI);
10907
0
        if (val == NULL) {
10908
0
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10909
0
                                       "Undefined variable: %s:%s\n",
10910
0
                                       op->value5, op->value4);
10911
0
                        return 0;
10912
0
                    }
10913
0
                    xmlXPathValuePush(ctxt, val);
10914
0
                }
10915
0
                break;
10916
0
            }
10917
348k
        case XPATH_OP_FUNCTION:{
10918
348k
                xmlXPathFunction func;
10919
348k
                const xmlChar *oldFunc, *oldFuncURI;
10920
348k
    int i;
10921
348k
                int frame;
10922
10923
348k
                frame = ctxt->valueNr;
10924
348k
                if (op->ch1 != -1) {
10925
25.3k
                    total +=
10926
25.3k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10927
25.3k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10928
106
                        break;
10929
25.3k
                }
10930
348k
    if (ctxt->valueNr < frame + op->value)
10931
348k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10932
378k
    for (i = 0; i < op->value; i++) {
10933
29.8k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10934
29.8k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10935
29.8k
                }
10936
348k
                if (op->cache != NULL)
10937
348k
                    func = op->cache;
10938
187
                else {
10939
187
                    const xmlChar *URI = NULL;
10940
10941
187
                    if (op->value5 == NULL) {
10942
144
                        func = xmlXPathFunctionLookup(ctxt->context,
10943
144
                                                      op->value4);
10944
144
                        if (func == NULL) {
10945
99
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10946
99
                                           "Unregistered function: %s\n",
10947
99
                                           op->value4);
10948
99
                            return 0;
10949
99
                        }
10950
144
                    } else {
10951
43
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10952
43
                        if (URI == NULL) {
10953
0
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10954
0
                                           "Undefined namespace prefix: %s\n",
10955
0
                                           op->value5);
10956
0
                            return 0;
10957
0
                        }
10958
43
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10959
43
                                                        op->value4, URI);
10960
43
                        if (func == NULL) {
10961
1
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10962
1
                                           "Unregistered function: %s:%s\n",
10963
1
                                           op->value5, op->value4);
10964
1
                            return 0;
10965
1
                        }
10966
43
                    }
10967
87
                    op->cache = func;
10968
87
                    op->cacheURI = (void *) URI;
10969
87
                }
10970
348k
                oldFunc = ctxt->context->function;
10971
348k
                oldFuncURI = ctxt->context->functionURI;
10972
348k
                ctxt->context->function = op->value4;
10973
348k
                ctxt->context->functionURI = op->cacheURI;
10974
348k
                func(ctxt, op->value);
10975
348k
                ctxt->context->function = oldFunc;
10976
348k
                ctxt->context->functionURI = oldFuncURI;
10977
348k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
10978
348k
                    (ctxt->valueNr != frame + 1))
10979
348k
                    XP_ERROR0(XPATH_STACK_ERROR);
10980
348k
                break;
10981
348k
            }
10982
30.0k
        case XPATH_OP_ARG:
10983
30.0k
            if (op->ch1 != -1) {
10984
4.76k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10985
4.76k
          CHECK_ERROR0;
10986
4.76k
            }
10987
30.0k
            if (op->ch2 != -1) {
10988
30.0k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10989
30.0k
          CHECK_ERROR0;
10990
30.0k
      }
10991
29.9k
            break;
10992
29.9k
        case XPATH_OP_PREDICATE:
10993
972
        case XPATH_OP_FILTER:{
10994
972
                xmlXPathObjectPtr obj;
10995
972
                xmlNodeSetPtr set;
10996
10997
                /*
10998
                 * Optimization for ()[1] selection i.e. the first elem
10999
                 */
11000
972
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11001
972
#ifdef XP_OPTIMIZED_FILTER_FIRST
11002
        /*
11003
        * FILTER TODO: Can we assume that the inner processing
11004
        *  will result in an ordered list if we have an
11005
        *  XPATH_OP_FILTER?
11006
        *  What about an additional field or flag on
11007
        *  xmlXPathObject like @sorted ? This way we wouldn't need
11008
        *  to assume anything, so it would be more robust and
11009
        *  easier to optimize.
11010
        */
11011
972
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11012
972
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11013
#else
11014
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11015
#endif
11016
972
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11017
910
                    xmlXPathObjectPtr val;
11018
11019
910
                    val = comp->steps[op->ch2].value4;
11020
910
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11021
910
                        (val->floatval == 1.0)) {
11022
752
                        xmlNodePtr first = NULL;
11023
11024
752
                        total +=
11025
752
                            xmlXPathCompOpEvalFirst(ctxt,
11026
752
                                                    &comp->steps[op->ch1],
11027
752
                                                    &first);
11028
752
      CHECK_ERROR0;
11029
                        /*
11030
                         * The nodeset should be in document order,
11031
                         * Keep only the first value
11032
                         */
11033
741
                        if ((ctxt->value != NULL) &&
11034
741
                            (ctxt->value->type == XPATH_NODESET) &&
11035
741
                            (ctxt->value->nodesetval != NULL) &&
11036
741
                            (ctxt->value->nodesetval->nodeNr > 1))
11037
7
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11038
7
                                                        1, 1);
11039
741
                        break;
11040
752
                    }
11041
910
                }
11042
                /*
11043
                 * Optimization for ()[last()] selection i.e. the last elem
11044
                 */
11045
220
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11046
220
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
220
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11048
60
                    int f = comp->steps[op->ch2].ch1;
11049
11050
60
                    if ((f != -1) &&
11051
60
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11052
60
                        (comp->steps[f].value5 == NULL) &&
11053
60
                        (comp->steps[f].value == 0) &&
11054
60
                        (comp->steps[f].value4 != NULL) &&
11055
60
                        (xmlStrEqual
11056
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11057
0
                        xmlNodePtr last = NULL;
11058
11059
0
                        total +=
11060
0
                            xmlXPathCompOpEvalLast(ctxt,
11061
0
                                                   &comp->steps[op->ch1],
11062
0
                                                   &last);
11063
0
      CHECK_ERROR0;
11064
                        /*
11065
                         * The nodeset should be in document order,
11066
                         * Keep only the last value
11067
                         */
11068
0
                        if ((ctxt->value != NULL) &&
11069
0
                            (ctxt->value->type == XPATH_NODESET) &&
11070
0
                            (ctxt->value->nodesetval != NULL) &&
11071
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11072
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11073
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11074
0
                        break;
11075
0
                    }
11076
60
                }
11077
    /*
11078
    * Process inner predicates first.
11079
    * Example "index[parent::book][1]":
11080
    * ...
11081
    *   PREDICATE   <-- we are here "[1]"
11082
    *     PREDICATE <-- process "[parent::book]" first
11083
    *       SORT
11084
    *         COLLECT  'parent' 'name' 'node' book
11085
    *           NODE
11086
    *     ELEM Object is a number : 1
11087
    */
11088
220
                if (op->ch1 != -1)
11089
220
                    total +=
11090
220
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11091
220
    CHECK_ERROR0;
11092
220
                if (op->ch2 == -1)
11093
0
                    break;
11094
220
                if (ctxt->value == NULL)
11095
0
                    break;
11096
11097
                /*
11098
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
11099
                 * nodes from the stack. We have to temporarily remove the
11100
                 * nodeset object from the stack to avoid freeing it
11101
                 * prematurely.
11102
                 */
11103
220
                CHECK_TYPE0(XPATH_NODESET);
11104
220
                obj = xmlXPathValuePop(ctxt);
11105
220
                set = obj->nodesetval;
11106
220
                if (set != NULL)
11107
220
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11108
220
                                          1, set->nodeNr, 1);
11109
220
                xmlXPathValuePush(ctxt, obj);
11110
220
                break;
11111
220
            }
11112
335k
        case XPATH_OP_SORT:
11113
335k
            if (op->ch1 != -1)
11114
335k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11115
335k
      CHECK_ERROR0;
11116
334k
            if ((ctxt->value != NULL) &&
11117
334k
                (ctxt->value->type == XPATH_NODESET) &&
11118
334k
                (ctxt->value->nodesetval != NULL) &&
11119
334k
    (ctxt->value->nodesetval->nodeNr > 1))
11120
7.58k
      {
11121
7.58k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11122
7.58k
      }
11123
334k
            break;
11124
0
        default:
11125
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11126
0
            break;
11127
1.10M
    }
11128
11129
1.08M
    ctxt->context->depth -= 1;
11130
1.08M
    return (total);
11131
1.10M
}
11132
11133
/**
11134
 * Evaluates if the expression evaluates to true.
11135
 *
11136
 * @param ctxt  the XPath parser context
11137
 * @param op  the step operation
11138
 * @param isPredicate  whether a predicate is evaluated
11139
 * @returns 1 if true, 0 if false and -1 on API or internal errors.
11140
 */
11141
static int
11142
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11143
          xmlXPathStepOpPtr op,
11144
          int isPredicate)
11145
1.05M
{
11146
1.05M
    xmlXPathObjectPtr resObj = NULL;
11147
11148
1.36M
start:
11149
1.36M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11150
2
        return(0);
11151
    /* comp = ctxt->comp; */
11152
1.36M
    switch (op->op) {
11153
0
        case XPATH_OP_END:
11154
0
            return (0);
11155
711k
  case XPATH_OP_VALUE:
11156
711k
      resObj = (xmlXPathObjectPtr) op->value4;
11157
711k
      if (isPredicate)
11158
711k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11159
0
      return(xmlXPathCastToBoolean(resObj));
11160
303k
  case XPATH_OP_SORT:
11161
      /*
11162
      * We don't need sorting for boolean results. Skip this one.
11163
      */
11164
303k
            if (op->ch1 != -1) {
11165
303k
    op = &ctxt->comp->steps[op->ch1];
11166
303k
    goto start;
11167
303k
      }
11168
0
      return(0);
11169
157
  case XPATH_OP_COLLECT:
11170
157
      if (op->ch1 == -1)
11171
0
    return(0);
11172
11173
157
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11174
157
      if (ctxt->error != XPATH_EXPRESSION_OK)
11175
0
    return(-1);
11176
11177
157
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11178
157
      if (ctxt->error != XPATH_EXPRESSION_OK)
11179
0
    return(-1);
11180
11181
157
      resObj = xmlXPathValuePop(ctxt);
11182
157
      if (resObj == NULL)
11183
0
    return(-1);
11184
157
      break;
11185
348k
  default:
11186
      /*
11187
      * Fallback to call xmlXPathCompOpEval().
11188
      */
11189
348k
      xmlXPathCompOpEval(ctxt, op);
11190
348k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11191
49
    return(-1);
11192
11193
348k
      resObj = xmlXPathValuePop(ctxt);
11194
348k
      if (resObj == NULL)
11195
0
    return(-1);
11196
348k
      break;
11197
1.36M
    }
11198
11199
348k
    if (resObj) {
11200
348k
  int res;
11201
11202
348k
  if (resObj->type == XPATH_BOOLEAN) {
11203
215
      res = resObj->boolval;
11204
348k
  } else if (isPredicate) {
11205
      /*
11206
      * For predicates a result of type "number" is handled
11207
      * differently:
11208
      * SPEC XPath 1.0:
11209
      * "If the result is a number, the result will be converted
11210
      *  to true if the number is equal to the context position
11211
      *  and will be converted to false otherwise;"
11212
      */
11213
348k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11214
348k
  } else {
11215
0
      res = xmlXPathCastToBoolean(resObj);
11216
0
  }
11217
348k
  xmlXPathReleaseObject(ctxt->context, resObj);
11218
348k
  return(res);
11219
348k
    }
11220
11221
0
    return(0);
11222
348k
}
11223
11224
#ifdef XPATH_STREAMING
11225
/**
11226
 * Evaluate the Precompiled Streamable XPath expression in the given context.
11227
 *
11228
 * @param pctxt  the XPath parser context with the compiled expression
11229
 */
11230
static int
11231
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11232
          xmlXPathObjectPtr *resultSeq, int toBool)
11233
{
11234
    int max_depth, min_depth;
11235
    int from_root;
11236
    int ret, depth;
11237
    int eval_all_nodes;
11238
    xmlNodePtr cur = NULL, limit = NULL;
11239
    xmlStreamCtxtPtr patstream = NULL;
11240
    xmlXPathContextPtr ctxt = pctxt->context;
11241
11242
    if ((ctxt == NULL) || (comp == NULL))
11243
        return(-1);
11244
    max_depth = xmlPatternMaxDepth(comp);
11245
    if (max_depth == -1)
11246
        return(-1);
11247
    if (max_depth == -2)
11248
        max_depth = 10000;
11249
    min_depth = xmlPatternMinDepth(comp);
11250
    if (min_depth == -1)
11251
        return(-1);
11252
    from_root = xmlPatternFromRoot(comp);
11253
    if (from_root < 0)
11254
        return(-1);
11255
11256
    if (! toBool) {
11257
  if (resultSeq == NULL)
11258
      return(-1);
11259
  *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11260
  if (*resultSeq == NULL)
11261
      return(-1);
11262
    }
11263
11264
    /*
11265
     * handle the special cases of "/" amd "." being matched
11266
     */
11267
    if (min_depth == 0) {
11268
        int res;
11269
11270
  if (from_root) {
11271
      /* Select "/" */
11272
      if (toBool)
11273
    return(1);
11274
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11275
                                           (xmlNodePtr) ctxt->doc);
11276
  } else {
11277
      /* Select "self::node()" */
11278
      if (toBool)
11279
    return(1);
11280
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11281
                                           ctxt->node);
11282
  }
11283
11284
        if (res < 0)
11285
            xmlXPathPErrMemory(pctxt);
11286
    }
11287
    if (max_depth == 0) {
11288
  return(0);
11289
    }
11290
11291
    if (from_root) {
11292
        cur = (xmlNodePtr)ctxt->doc;
11293
    } else if (ctxt->node != NULL) {
11294
        switch (ctxt->node->type) {
11295
            case XML_ELEMENT_NODE:
11296
            case XML_DOCUMENT_NODE:
11297
            case XML_DOCUMENT_FRAG_NODE:
11298
            case XML_HTML_DOCUMENT_NODE:
11299
          cur = ctxt->node;
11300
    break;
11301
            case XML_ATTRIBUTE_NODE:
11302
            case XML_TEXT_NODE:
11303
            case XML_CDATA_SECTION_NODE:
11304
            case XML_ENTITY_REF_NODE:
11305
            case XML_ENTITY_NODE:
11306
            case XML_PI_NODE:
11307
            case XML_COMMENT_NODE:
11308
            case XML_NOTATION_NODE:
11309
            case XML_DTD_NODE:
11310
            case XML_DOCUMENT_TYPE_NODE:
11311
            case XML_ELEMENT_DECL:
11312
            case XML_ATTRIBUTE_DECL:
11313
            case XML_ENTITY_DECL:
11314
            case XML_NAMESPACE_DECL:
11315
            case XML_XINCLUDE_START:
11316
            case XML_XINCLUDE_END:
11317
    break;
11318
  }
11319
  limit = cur;
11320
    }
11321
    if (cur == NULL) {
11322
        return(0);
11323
    }
11324
11325
    patstream = xmlPatternGetStreamCtxt(comp);
11326
    if (patstream == NULL) {
11327
        xmlXPathPErrMemory(pctxt);
11328
  return(-1);
11329
    }
11330
11331
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11332
11333
    if (from_root) {
11334
  ret = xmlStreamPush(patstream, NULL, NULL);
11335
  if (ret < 0) {
11336
  } else if (ret == 1) {
11337
      if (toBool)
11338
    goto return_1;
11339
      if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
11340
                xmlXPathPErrMemory(pctxt);
11341
  }
11342
    }
11343
    depth = 0;
11344
    goto scan_children;
11345
next_node:
11346
    do {
11347
        if (ctxt->opLimit != 0) {
11348
            if (ctxt->opCount >= ctxt->opLimit) {
11349
                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
11350
                xmlFreeStreamCtxt(patstream);
11351
                return(-1);
11352
            }
11353
            ctxt->opCount++;
11354
        }
11355
11356
  switch (cur->type) {
11357
      case XML_ELEMENT_NODE:
11358
      case XML_TEXT_NODE:
11359
      case XML_CDATA_SECTION_NODE:
11360
      case XML_COMMENT_NODE:
11361
      case XML_PI_NODE:
11362
    if (cur->type == XML_ELEMENT_NODE) {
11363
        ret = xmlStreamPush(patstream, cur->name,
11364
        (cur->ns ? cur->ns->href : NULL));
11365
    } else if (eval_all_nodes)
11366
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11367
    else
11368
        break;
11369
11370
    if (ret < 0) {
11371
        xmlXPathPErrMemory(pctxt);
11372
    } else if (ret == 1) {
11373
        if (toBool)
11374
      goto return_1;
11375
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11376
                                                 cur) < 0)
11377
                        xmlXPathPErrMemory(pctxt);
11378
    }
11379
    if ((cur->children == NULL) || (depth >= max_depth)) {
11380
        ret = xmlStreamPop(patstream);
11381
        while (cur->next != NULL) {
11382
      cur = cur->next;
11383
      if ((cur->type != XML_ENTITY_DECL) &&
11384
          (cur->type != XML_DTD_NODE))
11385
          goto next_node;
11386
        }
11387
    }
11388
      default:
11389
    break;
11390
  }
11391
11392
scan_children:
11393
  if (cur->type == XML_NAMESPACE_DECL) break;
11394
  if ((cur->children != NULL) && (depth < max_depth)) {
11395
      /*
11396
       * Do not descend on entities declarations
11397
       */
11398
      if (cur->children->type != XML_ENTITY_DECL) {
11399
    cur = cur->children;
11400
    depth++;
11401
    /*
11402
     * Skip DTDs
11403
     */
11404
    if (cur->type != XML_DTD_NODE)
11405
        continue;
11406
      }
11407
  }
11408
11409
  if (cur == limit)
11410
      break;
11411
11412
  while (cur->next != NULL) {
11413
      cur = cur->next;
11414
      if ((cur->type != XML_ENTITY_DECL) &&
11415
    (cur->type != XML_DTD_NODE))
11416
    goto next_node;
11417
  }
11418
11419
  do {
11420
      cur = cur->parent;
11421
      depth--;
11422
      if ((cur == NULL) || (cur == limit) ||
11423
                (cur->type == XML_DOCUMENT_NODE))
11424
          goto done;
11425
      if (cur->type == XML_ELEMENT_NODE) {
11426
    ret = xmlStreamPop(patstream);
11427
      } else if ((eval_all_nodes) &&
11428
    ((cur->type == XML_TEXT_NODE) ||
11429
     (cur->type == XML_CDATA_SECTION_NODE) ||
11430
     (cur->type == XML_COMMENT_NODE) ||
11431
     (cur->type == XML_PI_NODE)))
11432
      {
11433
    ret = xmlStreamPop(patstream);
11434
      }
11435
      if (cur->next != NULL) {
11436
    cur = cur->next;
11437
    break;
11438
      }
11439
  } while (cur != NULL);
11440
11441
    } while ((cur != NULL) && (depth >= 0));
11442
11443
done:
11444
11445
    if (patstream)
11446
  xmlFreeStreamCtxt(patstream);
11447
    return(0);
11448
11449
return_1:
11450
    if (patstream)
11451
  xmlFreeStreamCtxt(patstream);
11452
    return(1);
11453
}
11454
#endif /* XPATH_STREAMING */
11455
11456
/**
11457
 * Evaluate the Precompiled XPath expression in the given context.
11458
 *
11459
 * @param ctxt  the XPath parser context with the compiled expression
11460
 * @param toBool  evaluate to a boolean result
11461
 */
11462
static int
11463
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
11464
3.46k
{
11465
3.46k
    xmlXPathCompExprPtr comp;
11466
3.46k
    int oldDepth;
11467
11468
3.46k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11469
0
  return(-1);
11470
11471
3.46k
    if (ctxt->valueTab == NULL) {
11472
300
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11473
300
        int valueMax = 1;
11474
#else
11475
        int valueMax = 10;
11476
#endif
11477
11478
  /* Allocate the value stack */
11479
300
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11480
300
  if (ctxt->valueTab == NULL) {
11481
0
      xmlXPathPErrMemory(ctxt);
11482
0
      return(-1);
11483
0
  }
11484
300
  ctxt->valueNr = 0;
11485
300
  ctxt->valueMax = valueMax;
11486
300
  ctxt->value = NULL;
11487
300
    }
11488
#ifdef XPATH_STREAMING
11489
    if (ctxt->comp->stream) {
11490
  int res;
11491
11492
  if (toBool) {
11493
      /*
11494
      * Evaluation to boolean result.
11495
      */
11496
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
11497
      if (res != -1)
11498
    return(res);
11499
  } else {
11500
      xmlXPathObjectPtr resObj = NULL;
11501
11502
      /*
11503
      * Evaluation to a sequence.
11504
      */
11505
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
11506
11507
      if ((res != -1) && (resObj != NULL)) {
11508
    xmlXPathValuePush(ctxt, resObj);
11509
    return(0);
11510
      }
11511
      if (resObj != NULL)
11512
    xmlXPathReleaseObject(ctxt->context, resObj);
11513
  }
11514
  /*
11515
  * QUESTION TODO: This falls back to normal XPath evaluation
11516
  * if res == -1. Is this intended?
11517
  */
11518
    }
11519
#endif
11520
3.46k
    comp = ctxt->comp;
11521
3.46k
    if (comp->last < 0) {
11522
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11523
0
  return(-1);
11524
0
    }
11525
3.46k
    oldDepth = ctxt->context->depth;
11526
3.46k
    if (toBool)
11527
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11528
0
      &comp->steps[comp->last], 0));
11529
3.46k
    else
11530
3.46k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11531
3.46k
    ctxt->context->depth = oldDepth;
11532
11533
3.46k
    return(0);
11534
3.46k
}
11535
11536
/************************************************************************
11537
 *                  *
11538
 *      Public interfaces       *
11539
 *                  *
11540
 ************************************************************************/
11541
11542
/**
11543
 * Evaluate a predicate result for the current node.
11544
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11545
 * the result to a boolean. If the result is a number, the result will
11546
 * be converted to true if the number is equal to the position of the
11547
 * context node in the context node list (as returned by the position
11548
 * function) and will be converted to false otherwise; if the result
11549
 * is not a number, then the result will be converted as if by a call
11550
 * to the boolean function.
11551
 *
11552
 * @param ctxt  the XPath context
11553
 * @param res  the Predicate Expression evaluation result
11554
 * @returns 1 if predicate is true, 0 otherwise
11555
 */
11556
int
11557
0
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11558
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
11559
0
    switch (res->type) {
11560
0
        case XPATH_BOOLEAN:
11561
0
      return(res->boolval);
11562
0
        case XPATH_NUMBER:
11563
0
      return(res->floatval == ctxt->proximityPosition);
11564
0
        case XPATH_NODESET:
11565
0
        case XPATH_XSLT_TREE:
11566
0
      if (res->nodesetval == NULL)
11567
0
    return(0);
11568
0
      return(res->nodesetval->nodeNr != 0);
11569
0
        case XPATH_STRING:
11570
0
      return((res->stringval != NULL) &&
11571
0
             (xmlStrlen(res->stringval) != 0));
11572
0
        default:
11573
0
      break;
11574
0
    }
11575
0
    return(0);
11576
0
}
11577
11578
/**
11579
 * Evaluate a predicate result for the current node.
11580
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11581
 * the result to a boolean. If the result is a number, the result will
11582
 * be converted to true if the number is equal to the position of the
11583
 * context node in the context node list (as returned by the position
11584
 * function) and will be converted to false otherwise; if the result
11585
 * is not a number, then the result will be converted as if by a call
11586
 * to the boolean function.
11587
 *
11588
 * @param ctxt  the XPath Parser context
11589
 * @param res  the Predicate Expression evaluation result
11590
 * @returns 1 if predicate is true, 0 otherwise
11591
 */
11592
int
11593
xmlXPathEvaluatePredicateResult(xmlXPathParserContext *ctxt,
11594
1.05M
                                xmlXPathObject *res) {
11595
1.05M
    if ((ctxt == NULL) || (res == NULL)) return(0);
11596
1.05M
    switch (res->type) {
11597
0
        case XPATH_BOOLEAN:
11598
0
      return(res->boolval);
11599
343k
        case XPATH_NUMBER:
11600
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
11601
      return((res->floatval == ctxt->context->proximityPosition) &&
11602
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
11603
#else
11604
343k
      return(res->floatval == ctxt->context->proximityPosition);
11605
0
#endif
11606
2.52k
        case XPATH_NODESET:
11607
2.52k
        case XPATH_XSLT_TREE:
11608
2.52k
      if (res->nodesetval == NULL)
11609
0
    return(0);
11610
2.52k
      return(res->nodesetval->nodeNr != 0);
11611
713k
        case XPATH_STRING:
11612
713k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11613
0
        default:
11614
0
      break;
11615
1.05M
    }
11616
0
    return(0);
11617
1.05M
}
11618
11619
#ifdef XPATH_STREAMING
11620
/**
11621
 * Try to compile the XPath expression as a streamable subset.
11622
 *
11623
 * @param ctxt  an XPath context
11624
 * @param str  the XPath expression
11625
 * @returns the compiled expression or NULL if failed to compile.
11626
 */
11627
static xmlXPathCompExprPtr
11628
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11629
    /*
11630
     * Optimization: use streaming patterns when the XPath expression can
11631
     * be compiled to a stream lookup
11632
     */
11633
    xmlPatternPtr stream;
11634
    xmlXPathCompExprPtr comp;
11635
    xmlDictPtr dict = NULL;
11636
    const xmlChar **namespaces = NULL;
11637
    xmlNsPtr ns;
11638
    int i, j;
11639
11640
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11641
        (!xmlStrchr(str, '@'))) {
11642
  const xmlChar *tmp;
11643
        int res;
11644
11645
  /*
11646
   * We don't try to handle expressions using the verbose axis
11647
   * specifiers ("::"), just the simplified form at this point.
11648
   * Additionally, if there is no list of namespaces available and
11649
   *  there's a ":" in the expression, indicating a prefixed QName,
11650
   *  then we won't try to compile either. xmlPatterncompile() needs
11651
   *  to have a list of namespaces at compilation time in order to
11652
   *  compile prefixed name tests.
11653
   */
11654
  tmp = xmlStrchr(str, ':');
11655
  if ((tmp != NULL) &&
11656
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
11657
      return(NULL);
11658
11659
  if (ctxt != NULL) {
11660
      dict = ctxt->dict;
11661
      if (ctxt->nsNr > 0) {
11662
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
11663
    if (namespaces == NULL) {
11664
        xmlXPathErrMemory(ctxt);
11665
        return(NULL);
11666
    }
11667
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11668
        ns = ctxt->namespaces[j];
11669
        namespaces[i++] = ns->href;
11670
        namespaces[i++] = ns->prefix;
11671
    }
11672
    namespaces[i++] = NULL;
11673
    namespaces[i] = NULL;
11674
      }
11675
  }
11676
11677
  res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
11678
                                    &stream);
11679
  if (namespaces != NULL) {
11680
      xmlFree((xmlChar **)namespaces);
11681
  }
11682
        if (res < 0) {
11683
            xmlXPathErrMemory(ctxt);
11684
            return(NULL);
11685
        }
11686
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11687
      comp = xmlXPathNewCompExpr();
11688
      if (comp == NULL) {
11689
    xmlXPathErrMemory(ctxt);
11690
          xmlFreePattern(stream);
11691
    return(NULL);
11692
      }
11693
      comp->stream = stream;
11694
      comp->dict = dict;
11695
      if (comp->dict)
11696
    xmlDictReference(comp->dict);
11697
      return(comp);
11698
  }
11699
  xmlFreePattern(stream);
11700
    }
11701
    return(NULL);
11702
}
11703
#endif /* XPATH_STREAMING */
11704
11705
static void
11706
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
11707
                           xmlXPathStepOpPtr op)
11708
66.6k
{
11709
66.6k
    xmlXPathCompExprPtr comp = pctxt->comp;
11710
66.6k
    xmlXPathContextPtr ctxt;
11711
11712
    /*
11713
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11714
    * internal representation.
11715
    */
11716
11717
66.6k
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11718
66.6k
        (op->ch1 != -1) &&
11719
66.6k
        (op->ch2 == -1 /* no predicate */))
11720
22.4k
    {
11721
22.4k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11722
11723
22.4k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11724
22.4k
            ((xmlXPathAxisVal) prevop->value ==
11725
1.01k
                AXIS_DESCENDANT_OR_SELF) &&
11726
22.4k
            (prevop->ch2 == -1) &&
11727
22.4k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11728
22.4k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11729
344
        {
11730
            /*
11731
            * This is a "descendant-or-self::node()" without predicates.
11732
            * Try to eliminate it.
11733
            */
11734
11735
344
            switch ((xmlXPathAxisVal) op->value) {
11736
326
                case AXIS_CHILD:
11737
326
                case AXIS_DESCENDANT:
11738
                    /*
11739
                    * Convert "descendant-or-self::node()/child::" or
11740
                    * "descendant-or-self::node()/descendant::" to
11741
                    * "descendant::"
11742
                    */
11743
326
                    op->ch1   = prevop->ch1;
11744
326
                    op->value = AXIS_DESCENDANT;
11745
326
                    break;
11746
0
                case AXIS_SELF:
11747
7
                case AXIS_DESCENDANT_OR_SELF:
11748
                    /*
11749
                    * Convert "descendant-or-self::node()/self::" or
11750
                    * "descendant-or-self::node()/descendant-or-self::" to
11751
                    * to "descendant-or-self::"
11752
                    */
11753
7
                    op->ch1   = prevop->ch1;
11754
7
                    op->value = AXIS_DESCENDANT_OR_SELF;
11755
7
                    break;
11756
11
                default:
11757
11
                    break;
11758
344
            }
11759
344
  }
11760
22.4k
    }
11761
11762
    /* OP_VALUE has invalid ch1. */
11763
66.6k
    if (op->op == XPATH_OP_VALUE)
11764
50
        return;
11765
11766
    /* Recurse */
11767
66.5k
    ctxt = pctxt->context;
11768
66.5k
    if (ctxt != NULL) {
11769
66.5k
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11770
129
            return;
11771
66.4k
        ctxt->depth += 1;
11772
66.4k
    }
11773
66.4k
    if (op->ch1 != -1)
11774
44.6k
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11775
66.4k
    if (op->ch2 != -1)
11776
21.5k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11777
66.4k
    if (ctxt != NULL)
11778
66.4k
        ctxt->depth -= 1;
11779
66.4k
}
11780
11781
/**
11782
 * Compile an XPath expression
11783
 *
11784
 * @param ctxt  an XPath context
11785
 * @param str  the XPath expression
11786
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11787
 *         the caller has to free the object.
11788
 */
11789
xmlXPathCompExpr *
11790
1.30k
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11791
1.30k
    xmlXPathParserContextPtr pctxt;
11792
1.30k
    xmlXPathContextPtr tmpctxt = NULL;
11793
1.30k
    xmlXPathCompExprPtr comp;
11794
1.30k
    int oldDepth = 0;
11795
11796
1.30k
    if (str == NULL)
11797
0
        return(NULL);
11798
11799
#ifdef XPATH_STREAMING
11800
    comp = xmlXPathTryStreamCompile(ctxt, str);
11801
    if (comp != NULL)
11802
        return(comp);
11803
#endif
11804
11805
1.30k
    xmlInitParser();
11806
11807
    /*
11808
     * We need an xmlXPathContext for the depth check.
11809
     */
11810
1.30k
    if (ctxt == NULL) {
11811
0
        tmpctxt = xmlXPathNewContext(NULL);
11812
0
        if (tmpctxt == NULL)
11813
0
            return(NULL);
11814
0
        ctxt = tmpctxt;
11815
0
    }
11816
11817
1.30k
    pctxt = xmlXPathNewParserContext(str, ctxt);
11818
1.30k
    if (pctxt == NULL) {
11819
0
        if (tmpctxt != NULL)
11820
0
            xmlXPathFreeContext(tmpctxt);
11821
0
        return NULL;
11822
0
    }
11823
11824
1.30k
    oldDepth = ctxt->depth;
11825
1.30k
    xmlXPathCompileExpr(pctxt, 1);
11826
1.30k
    ctxt->depth = oldDepth;
11827
11828
1.30k
    if( pctxt->error != XPATH_EXPRESSION_OK )
11829
622
    {
11830
622
        xmlXPathFreeParserContext(pctxt);
11831
622
        if (tmpctxt != NULL)
11832
0
            xmlXPathFreeContext(tmpctxt);
11833
622
        return(NULL);
11834
622
    }
11835
11836
683
    if (*pctxt->cur != 0) {
11837
  /*
11838
   * aleksey: in some cases this line prints *second* error message
11839
   * (see bug #78858) and probably this should be fixed.
11840
   * However, we are not sure that all error messages are printed
11841
   * out in other places. It's not critical so we leave it as-is for now
11842
   */
11843
532
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11844
532
  comp = NULL;
11845
532
    } else {
11846
151
  comp = pctxt->comp;
11847
151
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11848
139
            if (ctxt != NULL)
11849
139
                oldDepth = ctxt->depth;
11850
139
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11851
139
            if (ctxt != NULL)
11852
139
                ctxt->depth = oldDepth;
11853
139
  }
11854
151
  pctxt->comp = NULL;
11855
151
    }
11856
683
    xmlXPathFreeParserContext(pctxt);
11857
683
    if (tmpctxt != NULL)
11858
0
        xmlXPathFreeContext(tmpctxt);
11859
11860
683
    if (comp != NULL) {
11861
151
  comp->expr = xmlStrdup(str);
11862
151
    }
11863
683
    return(comp);
11864
1.30k
}
11865
11866
/**
11867
 * Compile an XPath expression
11868
 *
11869
 * @param str  the XPath expression
11870
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11871
 *         the caller has to free the object.
11872
 */
11873
xmlXPathCompExpr *
11874
0
xmlXPathCompile(const xmlChar *str) {
11875
0
    return(xmlXPathCtxtCompile(NULL, str));
11876
0
}
11877
11878
/**
11879
 * Evaluate the Precompiled XPath expression in the given context.
11880
 * The caller has to free `resObj`.
11881
 *
11882
 * @param comp  the compiled XPath expression
11883
 * @param ctxt  the XPath context
11884
 * @param resObjPtr  the resulting XPath object or NULL
11885
 * @param toBool  1 if only a boolean result is requested
11886
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11887
 *         the caller has to free the object.
11888
 */
11889
static int
11890
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
11891
           xmlXPathContextPtr ctxt,
11892
           xmlXPathObjectPtr *resObjPtr,
11893
           int toBool)
11894
3.16k
{
11895
3.16k
    xmlXPathParserContextPtr pctxt;
11896
3.16k
    xmlXPathObjectPtr resObj = NULL;
11897
3.16k
    int res;
11898
11899
3.16k
    if (comp == NULL)
11900
0
  return(-1);
11901
3.16k
    xmlInitParser();
11902
11903
3.16k
    xmlResetError(&ctxt->lastError);
11904
11905
3.16k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11906
3.16k
    if (pctxt == NULL)
11907
0
        return(-1);
11908
3.16k
    res = xmlXPathRunEval(pctxt, toBool);
11909
11910
3.16k
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11911
2.89k
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11912
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11913
2.89k
        else if (!toBool)
11914
2.89k
            resObj = xmlXPathValuePop(pctxt);
11915
2.89k
    }
11916
11917
3.16k
    if (resObjPtr)
11918
3.16k
        *resObjPtr = resObj;
11919
0
    else
11920
0
        xmlXPathReleaseObject(ctxt, resObj);
11921
11922
3.16k
    pctxt->comp = NULL;
11923
3.16k
    xmlXPathFreeParserContext(pctxt);
11924
11925
3.16k
    return(res);
11926
3.16k
}
11927
11928
/**
11929
 * Evaluate the Precompiled XPath expression in the given context.
11930
 *
11931
 * @param comp  the compiled XPath expression
11932
 * @param ctx  the XPath context
11933
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11934
 *         the caller has to free the object.
11935
 */
11936
xmlXPathObject *
11937
xmlXPathCompiledEval(xmlXPathCompExpr *comp, xmlXPathContext *ctx)
11938
3.16k
{
11939
3.16k
    xmlXPathObjectPtr res = NULL;
11940
11941
3.16k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11942
3.16k
    return(res);
11943
3.16k
}
11944
11945
/**
11946
 * Applies the XPath boolean() function on the result of the given
11947
 * compiled expression.
11948
 *
11949
 * @param comp  the compiled XPath expression
11950
 * @param ctxt  the XPath context
11951
 * @returns 1 if the expression evaluated to true, 0 if to false and
11952
 *         -1 in API and internal errors.
11953
 */
11954
int
11955
xmlXPathCompiledEvalToBoolean(xmlXPathCompExpr *comp,
11956
            xmlXPathContext *ctxt)
11957
0
{
11958
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
11959
0
}
11960
11961
/**
11962
 * Parse and evaluate an XPath expression in the given context,
11963
 * then push the result on the context stack
11964
 *
11965
 * @deprecated Internal function, don't use.
11966
 *
11967
 * @param ctxt  the XPath Parser context
11968
 */
11969
void
11970
300
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
11971
#ifdef XPATH_STREAMING
11972
    xmlXPathCompExprPtr comp;
11973
#endif
11974
300
    int oldDepth = 0;
11975
11976
300
    if ((ctxt == NULL) || (ctxt->context == NULL))
11977
0
        return;
11978
300
    if (ctxt->context->lastError.code != 0)
11979
0
        return;
11980
11981
#ifdef XPATH_STREAMING
11982
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11983
    if ((comp == NULL) &&
11984
        (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
11985
        xmlXPathPErrMemory(ctxt);
11986
        return;
11987
    }
11988
    if (comp != NULL) {
11989
        if (ctxt->comp != NULL)
11990
      xmlXPathFreeCompExpr(ctxt->comp);
11991
        ctxt->comp = comp;
11992
    } else
11993
#endif
11994
300
    {
11995
300
        if (ctxt->context != NULL)
11996
300
            oldDepth = ctxt->context->depth;
11997
300
  xmlXPathCompileExpr(ctxt, 1);
11998
300
        if (ctxt->context != NULL)
11999
300
            ctxt->context->depth = oldDepth;
12000
300
        CHECK_ERROR;
12001
12002
        /* Check for trailing characters. */
12003
300
        if (*ctxt->cur != 0)
12004
300
            XP_ERROR(XPATH_EXPR_ERROR);
12005
12006
300
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12007
300
            if (ctxt->context != NULL)
12008
300
                oldDepth = ctxt->context->depth;
12009
300
      xmlXPathOptimizeExpression(ctxt,
12010
300
    &ctxt->comp->steps[ctxt->comp->last]);
12011
300
            if (ctxt->context != NULL)
12012
300
                ctxt->context->depth = oldDepth;
12013
300
        }
12014
300
    }
12015
12016
0
    xmlXPathRunEval(ctxt, 0);
12017
300
}
12018
12019
/**
12020
 * Evaluate the XPath Location Path in the given context.
12021
 *
12022
 * @param str  the XPath expression
12023
 * @param ctx  the XPath context
12024
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12025
 *         the caller has to free the object.
12026
 */
12027
xmlXPathObject *
12028
300
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12029
300
    xmlXPathParserContextPtr ctxt;
12030
300
    xmlXPathObjectPtr res;
12031
12032
300
    if (ctx == NULL)
12033
0
        return(NULL);
12034
12035
300
    xmlInitParser();
12036
12037
300
    xmlResetError(&ctx->lastError);
12038
12039
300
    ctxt = xmlXPathNewParserContext(str, ctx);
12040
300
    if (ctxt == NULL)
12041
0
        return NULL;
12042
300
    xmlXPathEvalExpr(ctxt);
12043
12044
300
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12045
4
  res = NULL;
12046
296
    } else if (ctxt->valueNr != 1) {
12047
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12048
0
  res = NULL;
12049
296
    } else {
12050
296
  res = xmlXPathValuePop(ctxt);
12051
296
    }
12052
12053
300
    xmlXPathFreeParserContext(ctxt);
12054
300
    return(res);
12055
300
}
12056
12057
/**
12058
 * Sets 'node' as the context node. The node must be in the same
12059
 * document as that associated with the context.
12060
 *
12061
 * @param node  the node to to use as the context node
12062
 * @param ctx  the XPath context
12063
 * @returns -1 in case of error or 0 if successful
12064
 */
12065
int
12066
0
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12067
0
    if ((node == NULL) || (ctx == NULL))
12068
0
        return(-1);
12069
12070
0
    if (node->doc == ctx->doc) {
12071
0
        ctx->node = node;
12072
0
  return(0);
12073
0
    }
12074
0
    return(-1);
12075
0
}
12076
12077
/**
12078
 * Evaluate the XPath Location Path in the given context. The node 'node'
12079
 * is set as the context node. The context node is not restored.
12080
 *
12081
 * @param node  the node to to use as the context node
12082
 * @param str  the XPath expression
12083
 * @param ctx  the XPath context
12084
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12085
 *         the caller has to free the object.
12086
 */
12087
xmlXPathObject *
12088
0
xmlXPathNodeEval(xmlNode *node, const xmlChar *str, xmlXPathContext *ctx) {
12089
0
    if (str == NULL)
12090
0
        return(NULL);
12091
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
12092
0
        return(NULL);
12093
0
    return(xmlXPathEval(str, ctx));
12094
0
}
12095
12096
/**
12097
 * Alias for #xmlXPathEval.
12098
 *
12099
 * @param str  the XPath expression
12100
 * @param ctxt  the XPath context
12101
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12102
 *         the caller has to free the object.
12103
 */
12104
xmlXPathObject *
12105
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12106
0
    return(xmlXPathEval(str, ctxt));
12107
0
}
12108
12109
/**
12110
 * Registers all default XPath functions in this context
12111
 *
12112
 * @deprecated No-op since 2.14.0.
12113
 *
12114
 * @param ctxt  the XPath context
12115
 */
12116
void
12117
xmlXPathRegisterAllFunctions(xmlXPathContext *ctxt ATTRIBUTE_UNUSED)
12118
0
{
12119
0
}
12120
12121
#endif /* LIBXML_XPATH_ENABLED */