Coverage Report

Created: 2025-11-24 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxml2/xpath.c
Line
Count
Source
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: Daniel Veillard
14
 */
15
16
/* To avoid EBCDIC trouble when parsing on zOS */
17
#if defined(__MVS__)
18
#pragma convert("ISO8859-1")
19
#endif
20
21
#define IN_LIBXML
22
#include "libxml.h"
23
24
#include <limits.h>
25
#include <string.h>
26
#include <stddef.h>
27
#include <math.h>
28
#include <float.h>
29
#include <ctype.h>
30
31
#include <libxml/xmlmemory.h>
32
#include <libxml/tree.h>
33
#include <libxml/xpath.h>
34
#include <libxml/xpathInternals.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/hash.h>
37
#ifdef LIBXML_DEBUG_ENABLED
38
#include <libxml/debugXML.h>
39
#endif
40
#include <libxml/xmlerror.h>
41
#include <libxml/threads.h>
42
#ifdef LIBXML_PATTERN_ENABLED
43
#include <libxml/pattern.h>
44
#endif
45
46
#include "private/buf.h"
47
#include "private/error.h"
48
#include "private/memory.h"
49
#include "private/parser.h"
50
#include "private/xpath.h"
51
52
/* Disabled for now */
53
#if 0
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
#endif
58
59
/**
60
 * Use the Timsort algorithm provided in timsort.h to sort
61
 * nodeset as this is a great improvement over the old Shell sort
62
 * used in #xmlXPathNodeSetSort
63
 */
64
#define WITH_TIM_SORT
65
66
/*
67
* If defined, this will use xmlXPathCmpNodesExt() instead of
68
* xmlXPathCmpNodes(). The new function is optimized comparison of
69
* non-element nodes; actually it will speed up comparison only if
70
* xmlXPathOrderDocElems() was called in order to index the elements of
71
* a tree in document order; Libxslt does such an indexing, thus it will
72
* benefit from this optimization.
73
*/
74
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
75
76
/*
77
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
78
* in a way, that it stop evaluation at the first node.
79
*/
80
#define XP_OPTIMIZED_FILTER_FIRST
81
82
/*
83
 * when compiling an XPath expression we arbitrary limit the maximum
84
 * number of step operation in the compiled expression. 1000000 is
85
 * an insanely large value which should never be reached under normal
86
 * circumstances
87
 */
88
55.4k
#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
307
#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
896k
#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
7.13M
#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
9.56k
#define SF_HASH_SIZE 64
169
170
static unsigned char xmlXPathSFHash[SF_HASH_SIZE];
171
172
double xmlXPathNAN = 0.0;
173
double xmlXPathPINF = 0.0;
174
double xmlXPathNINF = 0.0;
175
176
/**
177
 * @deprecated Alias for #xmlInitParser.
178
 */
179
void
180
0
xmlXPathInit(void) {
181
0
    xmlInitParser();
182
0
}
183
184
ATTRIBUTE_NO_SANITIZE_INTEGER
185
static unsigned
186
6.90k
xmlXPathSFComputeHash(const xmlChar *name) {
187
6.90k
    unsigned hashValue = 5381;
188
6.90k
    const xmlChar *ptr;
189
190
40.5k
    for (ptr = name; *ptr; ptr++)
191
33.6k
        hashValue = hashValue * 33 + *ptr;
192
193
6.90k
    return(hashValue);
194
6.90k
}
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
290k
xmlXPathIsNaN(double val) {
251
290k
#ifdef isnan
252
290k
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
290k
}
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
83.2k
xmlXPathIsInf(double val) {
266
83.2k
#ifdef isinf
267
83.2k
    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
83.2k
}
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
6.78M
#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
5.55M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
5.55M
    int depth1, depth2;
311
5.55M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
5.55M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
5.55M
    xmlNodePtr cur, root;
314
5.55M
    XML_INTPTR_T l1, l2;
315
316
5.55M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
5.55M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
5.55M
    switch (node1->type) {
326
4.88M
  case XML_ELEMENT_NODE:
327
4.88M
      if (node2->type == XML_ELEMENT_NODE) {
328
4.37M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
0
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
0
        (node1->doc == node2->doc))
331
0
    {
332
0
        l1 = -XML_NODE_SORT_VALUE(node1);
333
0
        l2 = -XML_NODE_SORT_VALUE(node2);
334
0
        if (l1 < l2)
335
0
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
4.37M
        goto turtle_comparison;
340
4.37M
      }
341
506k
      break;
342
506k
  case XML_ATTRIBUTE_NODE:
343
10.7k
      precedence1 = 1; /* element is owner */
344
10.7k
      miscNode1 = node1;
345
10.7k
      node1 = node1->parent;
346
10.7k
      misc = 1;
347
10.7k
      break;
348
559k
  case XML_TEXT_NODE:
349
586k
  case XML_CDATA_SECTION_NODE:
350
587k
  case XML_COMMENT_NODE:
351
628k
  case XML_PI_NODE: {
352
628k
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
628k
      if (node1->prev != NULL) {
357
644k
    do {
358
644k
        node1 = node1->prev;
359
644k
        if (node1->type == XML_ELEMENT_NODE) {
360
213k
      precedence1 = 3; /* element in prev-sibl axis */
361
213k
      break;
362
213k
        }
363
430k
        if (node1->prev == NULL) {
364
2.69k
      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
2.69k
      node1 = node1->parent;
370
2.69k
      break;
371
2.69k
        }
372
430k
    } while (1);
373
412k
      } else {
374
412k
    precedence1 = 2; /* element is parent */
375
412k
    node1 = node1->parent;
376
412k
      }
377
628k
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
628k
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
628k
    node1 = miscNode1;
383
628k
    precedence1 = 0;
384
628k
      } else
385
0
    misc = 1;
386
628k
  }
387
628k
      break;
388
0
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
0
      return(1);
393
33.8k
  default:
394
33.8k
      break;
395
5.55M
    }
396
1.18M
    switch (node2->type) {
397
455k
  case XML_ELEMENT_NODE:
398
455k
      break;
399
27.3k
  case XML_ATTRIBUTE_NODE:
400
27.3k
      precedence2 = 1; /* element is owner */
401
27.3k
      miscNode2 = node2;
402
27.3k
      node2 = node2->parent;
403
27.3k
      misc = 1;
404
27.3k
      break;
405
548k
  case XML_TEXT_NODE:
406
585k
  case XML_CDATA_SECTION_NODE:
407
586k
  case XML_COMMENT_NODE:
408
627k
  case XML_PI_NODE: {
409
627k
      miscNode2 = node2;
410
627k
      if (node2->prev != NULL) {
411
664k
    do {
412
664k
        node2 = node2->prev;
413
664k
        if (node2->type == XML_ELEMENT_NODE) {
414
234k
      precedence2 = 3; /* element in prev-sibl axis */
415
234k
      break;
416
234k
        }
417
430k
        if (node2->prev == NULL) {
418
2.00k
      precedence2 = 2; /* element is parent */
419
2.00k
      node2 = node2->parent;
420
2.00k
      break;
421
2.00k
        }
422
430k
    } while (1);
423
391k
      } else {
424
391k
    precedence2 = 2; /* element is parent */
425
391k
    node2 = node2->parent;
426
391k
      }
427
627k
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
627k
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
627k
      {
430
627k
    node2 = miscNode2;
431
627k
    precedence2 = 0;
432
627k
      } else
433
0
    misc = 1;
434
627k
  }
435
627k
      break;
436
0
  case XML_NAMESPACE_DECL:
437
0
      return(1);
438
70.7k
  default:
439
70.7k
      break;
440
1.18M
    }
441
1.18M
    if (misc) {
442
34.8k
  if (node1 == node2) {
443
2.06k
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
974
    cur = miscNode2->prev;
449
1.18k
    while (cur != NULL) {
450
466
        if (cur == miscNode1)
451
254
      return(1);
452
212
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
212
        cur = cur->prev;
455
212
    }
456
720
    return (-1);
457
1.09k
      } else {
458
    /*
459
    * Evaluate based on higher precedence wrt to the element.
460
    * TODO: This assumes attributes are sorted before content.
461
    *   Is this 100% correct?
462
    */
463
1.09k
    if (precedence1 < precedence2)
464
775
        return(1);
465
316
    else
466
316
        return(-1);
467
1.09k
      }
468
2.06k
  }
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
32.8k
  if ((precedence2 == 3) && (precedence1 > 1)) {
479
0
      cur = node1->parent;
480
0
      while (cur) {
481
0
    if (cur == node2)
482
0
        return(1);
483
0
    cur = cur->parent;
484
0
      }
485
0
  }
486
32.8k
  if ((precedence1 == 3) && (precedence2 > 1)) {
487
0
      cur = node2->parent;
488
0
      while (cur) {
489
0
    if (cur == node1)
490
0
        return(-1);
491
0
    cur = cur->parent;
492
0
      }
493
0
  }
494
32.8k
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
1.17M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
515k
  (node2->type == XML_ELEMENT_NODE) &&
501
29.8k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
0
  (node1->doc == node2->doc)) {
504
505
0
  l1 = -XML_NODE_SORT_VALUE(node1);
506
0
  l2 = -XML_NODE_SORT_VALUE(node2);
507
0
  if (l1 < l2)
508
0
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
5.55M
turtle_comparison:
514
515
5.55M
    if (node1 == node2->prev)
516
1.33M
  return(1);
517
4.21M
    if (node1 == node2->next)
518
70.3k
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
189M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
186M
  if (cur->parent == node1)
524
1.27M
      return(1);
525
185M
  depth2++;
526
185M
    }
527
2.86M
    root = cur;
528
159M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
156M
  if (cur->parent == node2)
530
433k
      return(-1);
531
156M
  depth1++;
532
156M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
2.43M
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
9.51M
    while (depth1 > depth2) {
543
7.08M
  depth1--;
544
7.08M
  node1 = node1->parent;
545
7.08M
    }
546
16.8M
    while (depth2 > depth1) {
547
14.4M
  depth2--;
548
14.4M
  node2 = node2->parent;
549
14.4M
    }
550
7.58M
    while (node1->parent != node2->parent) {
551
5.14M
  node1 = node1->parent;
552
5.14M
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
5.14M
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
5.14M
    }
557
    /*
558
     * Find who's first.
559
     */
560
2.43M
    if (node1 == node2->prev)
561
599k
  return(1);
562
1.83M
    if (node1 == node2->next)
563
707k
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
1.12M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
1.12M
  (node2->type == XML_ELEMENT_NODE) &&
569
1.12M
  (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
6.23M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
5.81M
  if (cur == node2)
583
702k
      return(1);
584
424k
    return(-1); /* assume there is no sibling list corruption */
585
1.12M
}
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
700k
#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
5.55M
    {
607
5.55M
        int res = xmlXPathCmpNodesExt(x, y);
608
5.55M
        return res == -2 ? res : -res;
609
5.55M
    }
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
5.55M
#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
588
    { xmlXPathErr(ctxt, X); return(NULL); }
634
635
/*
636
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
637
 */
638
static const char* const xmlXPathErrorMessages[] = {
639
    "Ok",
640
    "Number encoding",
641
    "Unfinished literal",
642
    "Start of literal",
643
    "Expected $ for variable reference",
644
    "Undefined variable",
645
    "Invalid predicate",
646
    "Invalid expression",
647
    "Missing closing curly brace",
648
    "Unregistered function",
649
    "Invalid operand",
650
    "Invalid type",
651
    "Invalid number of arguments",
652
    "Invalid context size",
653
    "Invalid context position",
654
    "Memory allocation error",
655
    "Syntax error",
656
    "Resource error",
657
    "Sub resource error",
658
    "Undefined namespace prefix",
659
    "Encoding error",
660
    "Char out of XML range",
661
    "Invalid or incomplete context",
662
    "Stack usage error",
663
    "Forbidden variable",
664
    "Operation limit exceeded",
665
    "Recursion limit exceeded",
666
    "?? Unknown error ??" /* Must be last in the list! */
667
};
668
8.37k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
8.37k
       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
2.58k
{
678
2.58k
    if (ctxt == NULL)
679
0
        return;
680
2.58k
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
2.58k
                        &ctxt->lastError);
682
2.58k
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
2.42k
{
692
2.42k
    if (ctxt == NULL)
693
0
        return;
694
2.42k
    ctxt->error = XPATH_MEMORY_ERROR;
695
2.42k
    xmlXPathErrMemory(ctxt->context);
696
2.42k
}
697
698
/**
699
 * Handle an XPath error
700
 *
701
 * @param ctxt  a XPath parser context
702
 * @param code  the error code
703
 * @param fmt  format string for error message
704
 * @param ...  extra args
705
 */
706
static void
707
8.37k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
8.37k
    va_list ap;
709
8.37k
    xmlStructuredErrorFunc schannel = NULL;
710
8.37k
    xmlGenericErrorFunc channel = NULL;
711
8.37k
    void *data = NULL;
712
8.37k
    xmlNodePtr node = NULL;
713
8.37k
    int res;
714
715
8.37k
    if (ctxt == NULL)
716
0
        return;
717
8.37k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
8.37k
    if (ctxt->error != 0)
721
3.40k
        return;
722
723
4.96k
    ctxt->error = code;
724
725
4.96k
    if (ctxt->context != NULL) {
726
4.96k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
4.96k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
4.96k
        xmlResetError(err);
734
735
4.96k
        err->domain = XML_FROM_XPATH;
736
4.96k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
4.96k
        err->level = XML_ERR_ERROR;
738
4.96k
        if (ctxt->base != NULL) {
739
4.96k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
4.96k
            if (err->str1 == NULL) {
741
26
                xmlXPathPErrMemory(ctxt);
742
26
                return;
743
26
            }
744
4.96k
        }
745
4.94k
        err->int1 = ctxt->cur - ctxt->base;
746
4.94k
        err->node = ctxt->context->debugNode;
747
748
4.94k
        schannel = ctxt->context->error;
749
4.94k
        data = ctxt->context->userData;
750
4.94k
        node = ctxt->context->debugNode;
751
4.94k
    }
752
753
4.94k
    if (schannel == NULL) {
754
0
        channel = xmlGenericError;
755
0
        data = xmlGenericErrorContext;
756
0
    }
757
758
4.94k
    va_start(ap, fmt);
759
4.94k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
4.94k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
4.94k
                         XML_ERR_ERROR, NULL, 0,
762
4.94k
                         (const char *) ctxt->base, NULL, NULL,
763
4.94k
                         ctxt->cur - ctxt->base, 0,
764
4.94k
                         fmt, ap);
765
4.94k
    va_end(ap);
766
4.94k
    if (res < 0)
767
33
        xmlXPathPErrMemory(ctxt);
768
4.94k
}
769
770
/**
771
 * Handle an XPath error
772
 *
773
 * @param ctxt  a XPath parser context
774
 * @param code  the error code
775
 */
776
void
777
7.51k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
7.51k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
7.51k
}
780
781
/**
782
 * Formats an error message.
783
 *
784
 * @param ctxt  the XPath Parser context
785
 * @param file  the file name
786
 * @param line  the line number
787
 * @param no  the error number
788
 */
789
void
790
xmlXPatherror(xmlXPathParserContext *ctxt, const char *file ATTRIBUTE_UNUSED,
791
0
              int line ATTRIBUTE_UNUSED, int no) {
792
0
    xmlXPathErr(ctxt, no);
793
0
}
794
795
/**
796
 * Adds opCount to the running total of operations and returns -1 if the
797
 * operation limit is exceeded. Returns 0 otherwise.
798
 *
799
 * @param ctxt  the XPath Parser context
800
 * @param opCount  the number of operations to be added
801
 */
802
static int
803
13.9M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
13.9M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
13.9M
    if ((opCount > xpctxt->opLimit) ||
807
13.9M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
111
        xpctxt->opCount = xpctxt->opLimit;
809
111
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
111
        return(-1);
811
111
    }
812
813
13.9M
    xpctxt->opCount += opCount;
814
13.9M
    return(0);
815
13.9M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
13.7M
    ((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
10.5k
xmlXPathNewCompExpr(void) {
941
10.5k
    xmlXPathCompExprPtr cur;
942
943
10.5k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
10.5k
    if (cur == NULL)
945
34
  return(NULL);
946
10.5k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
10.5k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
10.5k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
10.5k
    cur->nbStep = 0;
953
10.5k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
10.5k
                                     sizeof(xmlXPathStepOp));
955
10.5k
    if (cur->steps == NULL) {
956
21
  xmlFree(cur);
957
21
  return(NULL);
958
21
    }
959
10.5k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
10.5k
    cur->last = -1;
961
10.5k
    return(cur);
962
10.5k
}
963
964
/**
965
 * Free up the memory allocated by `comp`
966
 *
967
 * @param comp  an XPATH comp
968
 */
969
void
970
xmlXPathFreeCompExpr(xmlXPathCompExpr *comp)
971
10.5k
{
972
10.5k
    xmlXPathStepOpPtr op;
973
10.5k
    int i;
974
975
10.5k
    if (comp == NULL)
976
0
        return;
977
10.5k
    if (comp->dict == NULL) {
978
5.90M
  for (i = 0; i < comp->nbStep; i++) {
979
5.89M
      op = &comp->steps[i];
980
5.89M
      if (op->value4 != NULL) {
981
41.1k
    if (op->op == XPATH_OP_VALUE)
982
26.4k
        xmlXPathFreeObject(op->value4);
983
14.7k
    else
984
14.7k
        xmlFree(op->value4);
985
41.1k
      }
986
5.89M
      if (op->value5 != NULL)
987
101k
    xmlFree(op->value5);
988
5.89M
  }
989
10.5k
    } else {
990
0
  for (i = 0; i < comp->nbStep; i++) {
991
0
      op = &comp->steps[i];
992
0
      if (op->value4 != NULL) {
993
0
    if (op->op == XPATH_OP_VALUE)
994
0
        xmlXPathFreeObject(op->value4);
995
0
      }
996
0
  }
997
0
        xmlDictFree(comp->dict);
998
0
    }
999
10.5k
    if (comp->steps != NULL) {
1000
10.5k
        xmlFree(comp->steps);
1001
10.5k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
10.5k
    if (comp->expr != NULL) {
1008
0
        xmlFree(comp->expr);
1009
0
    }
1010
1011
10.5k
    xmlFree(comp);
1012
10.5k
}
1013
1014
/**
1015
 * Add a step to an XPath Compiled Expression
1016
 *
1017
 * @param ctxt  XPath parser context
1018
 * @param ch1  first child index
1019
 * @param ch2  second child index
1020
 * @param op  an op
1021
 * @param value  the first int value
1022
 * @param value2  the second int value
1023
 * @param value3  the third int value
1024
 * @param value4  the first string value
1025
 * @param value5  the second string value
1026
 * @returns -1 in case of failure, the index otherwise
1027
 */
1028
static int
1029
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1030
   xmlXPathOp op, int value,
1031
5.89M
   int value2, int value3, void *value4, void *value5) {
1032
5.89M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
5.89M
    if (comp->nbStep >= comp->maxStep) {
1034
55.4k
  xmlXPathStepOp *real;
1035
55.4k
        int newSize;
1036
1037
55.4k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
55.4k
                                  10, XPATH_MAX_STEPS);
1039
55.4k
        if (newSize < 0) {
1040
0
      xmlXPathPErrMemory(ctxt);
1041
0
      return(-1);
1042
0
        }
1043
55.4k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
55.4k
  if (real == NULL) {
1045
115
      xmlXPathPErrMemory(ctxt);
1046
115
      return(-1);
1047
115
  }
1048
55.3k
  comp->steps = real;
1049
55.3k
  comp->maxStep = newSize;
1050
55.3k
    }
1051
5.89M
    comp->last = comp->nbStep;
1052
5.89M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
5.89M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
5.89M
    comp->steps[comp->nbStep].op = op;
1055
5.89M
    comp->steps[comp->nbStep].value = value;
1056
5.89M
    comp->steps[comp->nbStep].value2 = value2;
1057
5.89M
    comp->steps[comp->nbStep].value3 = value3;
1058
5.89M
    if ((comp->dict != NULL) &&
1059
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
0
   (op == XPATH_OP_COLLECT))) {
1061
0
        if (value4 != NULL) {
1062
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
0
      xmlFree(value4);
1065
0
  } else
1066
0
      comp->steps[comp->nbStep].value4 = NULL;
1067
0
        if (value5 != NULL) {
1068
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
0
      xmlFree(value5);
1071
0
  } else
1072
0
      comp->steps[comp->nbStep].value5 = NULL;
1073
5.89M
    } else {
1074
5.89M
  comp->steps[comp->nbStep].value4 = value4;
1075
5.89M
  comp->steps[comp->nbStep].value5 = value5;
1076
5.89M
    }
1077
5.89M
    comp->steps[comp->nbStep].cache = NULL;
1078
5.89M
    return(comp->nbStep++);
1079
5.89M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
1.90M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
1.90M
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
63.1k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
63.1k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
1.91M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
1.91M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
84.4k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
84.4k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
1.92M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
1.92M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
1.92M
      (val), (val2), 0 ,NULL ,NULL)
1097
1098
/************************************************************************
1099
 *                  *
1100
 *    XPath object cache structures       *
1101
 *                  *
1102
 ************************************************************************/
1103
1104
/* #define XP_DEFAULT_CACHE_ON */
1105
1106
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1107
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1108
struct _xmlXPathContextCache {
1109
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1110
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1111
    int numNodeset;
1112
    int maxNodeset;
1113
    int numMisc;
1114
    int maxMisc;
1115
};
1116
1117
/************************************************************************
1118
 *                  *
1119
 *    Debugging related functions       *
1120
 *                  *
1121
 ************************************************************************/
1122
1123
#ifdef LIBXML_DEBUG_ENABLED
1124
static void
1125
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1126
    int i;
1127
    char shift[100];
1128
1129
    for (i = 0;((i < depth) && (i < 25));i++)
1130
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
    if (cur == NULL) {
1133
  fprintf(output, "%s", shift);
1134
  fprintf(output, "Node is NULL !\n");
1135
  return;
1136
1137
    }
1138
1139
    if ((cur->type == XML_DOCUMENT_NODE) ||
1140
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1141
  fprintf(output, "%s", shift);
1142
  fprintf(output, " /\n");
1143
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1144
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1145
    else
1146
  xmlDebugDumpOneNode(output, cur, depth);
1147
}
1148
static void
1149
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1150
    xmlNodePtr tmp;
1151
    int i;
1152
    char shift[100];
1153
1154
    for (i = 0;((i < depth) && (i < 25));i++)
1155
        shift[2 * i] = shift[2 * i + 1] = ' ';
1156
    shift[2 * i] = shift[2 * i + 1] = 0;
1157
    if (cur == NULL) {
1158
  fprintf(output, "%s", shift);
1159
  fprintf(output, "Node is NULL !\n");
1160
  return;
1161
1162
    }
1163
1164
    while (cur != NULL) {
1165
  tmp = cur;
1166
  cur = cur->next;
1167
  xmlDebugDumpOneNode(output, tmp, depth);
1168
    }
1169
}
1170
1171
static void
1172
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1173
    int i;
1174
    char shift[100];
1175
1176
    for (i = 0;((i < depth) && (i < 25));i++)
1177
        shift[2 * i] = shift[2 * i + 1] = ' ';
1178
    shift[2 * i] = shift[2 * i + 1] = 0;
1179
1180
    if (cur == NULL) {
1181
  fprintf(output, "%s", shift);
1182
  fprintf(output, "NodeSet is NULL !\n");
1183
  return;
1184
1185
    }
1186
1187
    if (cur != NULL) {
1188
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1189
  for (i = 0;i < cur->nodeNr;i++) {
1190
      fprintf(output, "%s", shift);
1191
      fprintf(output, "%d", i + 1);
1192
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1193
  }
1194
    }
1195
}
1196
1197
static void
1198
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1199
    int i;
1200
    char shift[100];
1201
1202
    for (i = 0;((i < depth) && (i < 25));i++)
1203
        shift[2 * i] = shift[2 * i + 1] = ' ';
1204
    shift[2 * i] = shift[2 * i + 1] = 0;
1205
1206
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1207
  fprintf(output, "%s", shift);
1208
  fprintf(output, "Value Tree is NULL !\n");
1209
  return;
1210
1211
    }
1212
1213
    fprintf(output, "%s", shift);
1214
    fprintf(output, "%d", i + 1);
1215
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1216
}
1217
1218
/**
1219
 * Dump the content of the object for debugging purposes
1220
 *
1221
 * @param output  the FILE * to dump the output
1222
 * @param cur  the object to inspect
1223
 * @param depth  indentation level
1224
 */
1225
void
1226
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1227
    int i;
1228
    char shift[100];
1229
1230
    if (output == NULL) return;
1231
1232
    for (i = 0;((i < depth) && (i < 25));i++)
1233
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
    fprintf(output, "%s", shift);
1238
1239
    if (cur == NULL) {
1240
        fprintf(output, "Object is empty (NULL)\n");
1241
  return;
1242
    }
1243
    switch(cur->type) {
1244
        case XPATH_UNDEFINED:
1245
      fprintf(output, "Object is uninitialized\n");
1246
      break;
1247
        case XPATH_NODESET:
1248
      fprintf(output, "Object is a Node Set :\n");
1249
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
      break;
1251
  case XPATH_XSLT_TREE:
1252
      fprintf(output, "Object is an XSLT value tree :\n");
1253
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
      break;
1255
        case XPATH_BOOLEAN:
1256
      fprintf(output, "Object is a Boolean : ");
1257
      if (cur->boolval) fprintf(output, "true\n");
1258
      else fprintf(output, "false\n");
1259
      break;
1260
        case XPATH_NUMBER:
1261
      switch (xmlXPathIsInf(cur->floatval)) {
1262
      case 1:
1263
    fprintf(output, "Object is a number : Infinity\n");
1264
    break;
1265
      case -1:
1266
    fprintf(output, "Object is a number : -Infinity\n");
1267
    break;
1268
      default:
1269
    if (xmlXPathIsNaN(cur->floatval)) {
1270
        fprintf(output, "Object is a number : NaN\n");
1271
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
        fprintf(output, "Object is a number : 0\n");
1274
    } else {
1275
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
    }
1277
      }
1278
      break;
1279
        case XPATH_STRING:
1280
      fprintf(output, "Object is a string : ");
1281
      xmlDebugDumpString(output, cur->stringval);
1282
      fprintf(output, "\n");
1283
      break;
1284
  case XPATH_USERS:
1285
      fprintf(output, "Object is user defined\n");
1286
      break;
1287
    }
1288
}
1289
1290
static void
1291
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1292
                       xmlXPathStepOpPtr op, int depth) {
1293
    int i;
1294
    char shift[100];
1295
1296
    for (i = 0;((i < depth) && (i < 25));i++)
1297
        shift[2 * i] = shift[2 * i + 1] = ' ';
1298
    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300
    fprintf(output, "%s", shift);
1301
    if (op == NULL) {
1302
  fprintf(output, "Step is NULL\n");
1303
  return;
1304
    }
1305
    switch (op->op) {
1306
        case XPATH_OP_END:
1307
      fprintf(output, "END"); break;
1308
        case XPATH_OP_AND:
1309
      fprintf(output, "AND"); break;
1310
        case XPATH_OP_OR:
1311
      fprintf(output, "OR"); break;
1312
        case XPATH_OP_EQUAL:
1313
       if (op->value)
1314
     fprintf(output, "EQUAL =");
1315
       else
1316
     fprintf(output, "EQUAL !=");
1317
       break;
1318
        case XPATH_OP_CMP:
1319
       if (op->value)
1320
     fprintf(output, "CMP <");
1321
       else
1322
     fprintf(output, "CMP >");
1323
       if (!op->value2)
1324
     fprintf(output, "=");
1325
       break;
1326
        case XPATH_OP_PLUS:
1327
       if (op->value == 0)
1328
     fprintf(output, "PLUS -");
1329
       else if (op->value == 1)
1330
     fprintf(output, "PLUS +");
1331
       else if (op->value == 2)
1332
     fprintf(output, "PLUS unary -");
1333
       else if (op->value == 3)
1334
     fprintf(output, "PLUS unary - -");
1335
       break;
1336
        case XPATH_OP_MULT:
1337
       if (op->value == 0)
1338
     fprintf(output, "MULT *");
1339
       else if (op->value == 1)
1340
     fprintf(output, "MULT div");
1341
       else
1342
     fprintf(output, "MULT mod");
1343
       break;
1344
        case XPATH_OP_UNION:
1345
       fprintf(output, "UNION"); break;
1346
        case XPATH_OP_ROOT:
1347
       fprintf(output, "ROOT"); break;
1348
        case XPATH_OP_NODE:
1349
       fprintf(output, "NODE"); break;
1350
        case XPATH_OP_SORT:
1351
       fprintf(output, "SORT"); break;
1352
        case XPATH_OP_COLLECT: {
1353
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1354
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1355
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1356
      const xmlChar *prefix = op->value4;
1357
      const xmlChar *name = op->value5;
1358
1359
      fprintf(output, "COLLECT ");
1360
      switch (axis) {
1361
    case AXIS_ANCESTOR:
1362
        fprintf(output, " 'ancestors' "); break;
1363
    case AXIS_ANCESTOR_OR_SELF:
1364
        fprintf(output, " 'ancestors-or-self' "); break;
1365
    case AXIS_ATTRIBUTE:
1366
        fprintf(output, " 'attributes' "); break;
1367
    case AXIS_CHILD:
1368
        fprintf(output, " 'child' "); break;
1369
    case AXIS_DESCENDANT:
1370
        fprintf(output, " 'descendant' "); break;
1371
    case AXIS_DESCENDANT_OR_SELF:
1372
        fprintf(output, " 'descendant-or-self' "); break;
1373
    case AXIS_FOLLOWING:
1374
        fprintf(output, " 'following' "); break;
1375
    case AXIS_FOLLOWING_SIBLING:
1376
        fprintf(output, " 'following-siblings' "); break;
1377
    case AXIS_NAMESPACE:
1378
        fprintf(output, " 'namespace' "); break;
1379
    case AXIS_PARENT:
1380
        fprintf(output, " 'parent' "); break;
1381
    case AXIS_PRECEDING:
1382
        fprintf(output, " 'preceding' "); break;
1383
    case AXIS_PRECEDING_SIBLING:
1384
        fprintf(output, " 'preceding-sibling' "); break;
1385
    case AXIS_SELF:
1386
        fprintf(output, " 'self' "); break;
1387
      }
1388
      switch (test) {
1389
                case NODE_TEST_NONE:
1390
        fprintf(output, "'none' "); break;
1391
                case NODE_TEST_TYPE:
1392
        fprintf(output, "'type' "); break;
1393
                case NODE_TEST_PI:
1394
        fprintf(output, "'PI' "); break;
1395
                case NODE_TEST_ALL:
1396
        fprintf(output, "'all' "); break;
1397
                case NODE_TEST_NS:
1398
        fprintf(output, "'namespace' "); break;
1399
                case NODE_TEST_NAME:
1400
        fprintf(output, "'name' "); break;
1401
      }
1402
      switch (type) {
1403
                case NODE_TYPE_NODE:
1404
        fprintf(output, "'node' "); break;
1405
                case NODE_TYPE_COMMENT:
1406
        fprintf(output, "'comment' "); break;
1407
                case NODE_TYPE_TEXT:
1408
        fprintf(output, "'text' "); break;
1409
                case NODE_TYPE_PI:
1410
        fprintf(output, "'PI' "); break;
1411
      }
1412
      if (prefix != NULL)
1413
    fprintf(output, "%s:", prefix);
1414
      if (name != NULL)
1415
    fprintf(output, "%s", (const char *) name);
1416
      break;
1417
1418
        }
1419
  case XPATH_OP_VALUE: {
1420
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1421
1422
      fprintf(output, "ELEM ");
1423
      xmlXPathDebugDumpObject(output, object, 0);
1424
      goto finish;
1425
  }
1426
  case XPATH_OP_VARIABLE: {
1427
      const xmlChar *prefix = op->value5;
1428
      const xmlChar *name = op->value4;
1429
1430
      if (prefix != NULL)
1431
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1432
      else
1433
    fprintf(output, "VARIABLE %s", name);
1434
      break;
1435
  }
1436
  case XPATH_OP_FUNCTION: {
1437
      int nbargs = op->value;
1438
      const xmlChar *prefix = op->value5;
1439
      const xmlChar *name = op->value4;
1440
1441
      if (prefix != NULL)
1442
    fprintf(output, "FUNCTION %s:%s(%d args)",
1443
      prefix, name, nbargs);
1444
      else
1445
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1446
      break;
1447
  }
1448
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1449
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1450
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1451
  default:
1452
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1453
    }
1454
    fprintf(output, "\n");
1455
finish:
1456
    /* OP_VALUE has invalid ch1. */
1457
    if (op->op == XPATH_OP_VALUE)
1458
        return;
1459
1460
    if (op->ch1 >= 0)
1461
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1462
    if (op->ch2 >= 0)
1463
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1464
}
1465
1466
/**
1467
 * Dumps the tree of the compiled XPath expression.
1468
 *
1469
 * @param output  the FILE * for the output
1470
 * @param comp  the precompiled XPath expression
1471
 * @param depth  the indentation level.
1472
 */
1473
void
1474
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExpr *comp,
1475
                    int depth) {
1476
    int i;
1477
    char shift[100];
1478
1479
    if ((output == NULL) || (comp == NULL)) return;
1480
1481
    for (i = 0;((i < depth) && (i < 25));i++)
1482
        shift[2 * i] = shift[2 * i + 1] = ' ';
1483
    shift[2 * i] = shift[2 * i + 1] = 0;
1484
1485
    fprintf(output, "%s", shift);
1486
1487
#ifdef XPATH_STREAMING
1488
    if (comp->stream) {
1489
        fprintf(output, "Streaming Expression\n");
1490
    } else
1491
#endif
1492
    {
1493
        fprintf(output, "Compiled Expression : %d elements\n",
1494
                comp->nbStep);
1495
        i = comp->last;
1496
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1497
    }
1498
}
1499
1500
#endif /* LIBXML_DEBUG_ENABLED */
1501
1502
/************************************************************************
1503
 *                  *
1504
 *      XPath object caching        *
1505
 *                  *
1506
 ************************************************************************/
1507
1508
/**
1509
 * Create a new object cache
1510
 *
1511
 * @returns the xmlXPathCache just allocated.
1512
 */
1513
static xmlXPathContextCachePtr
1514
xmlXPathNewCache(void)
1515
0
{
1516
0
    xmlXPathContextCachePtr ret;
1517
1518
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
0
    if (ret == NULL)
1520
0
  return(NULL);
1521
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
0
    ret->maxNodeset = 100;
1523
0
    ret->maxMisc = 100;
1524
0
    return(ret);
1525
0
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
0
{
1530
0
    while (list != NULL) {
1531
0
        xmlXPathObjectPtr next;
1532
1533
0
        next = (void *) list->stringval;
1534
1535
0
  if (list->nodesetval != NULL) {
1536
0
      if (list->nodesetval->nodeTab != NULL)
1537
0
    xmlFree(list->nodesetval->nodeTab);
1538
0
      xmlFree(list->nodesetval);
1539
0
  }
1540
0
  xmlFree(list);
1541
1542
0
        list = next;
1543
0
    }
1544
0
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
0
{
1549
0
    if (cache == NULL)
1550
0
  return;
1551
0
    if (cache->nodesetObjs)
1552
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
0
    if (cache->miscObjs)
1554
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
0
    xmlFree(cache);
1556
0
}
1557
1558
/**
1559
 * Creates/frees an object cache on the XPath context.
1560
 * If activates XPath objects (xmlXPathObject) will be cached internally
1561
 * to be reused.
1562
 *
1563
 * `options` must be set to 0 to enable XPath object caching.
1564
 * Other values for `options` have currently no effect.
1565
 *
1566
 * `value` sets the maximum number of XPath objects to be cached per slot.
1567
 * There are two slots for node-set and misc objects.
1568
 * Use <0 for the default number (100).
1569
 *
1570
 * @param ctxt  the XPath context
1571
 * @param active  enables/disables (creates/frees) the cache
1572
 * @param value  a value with semantics dependent on `options`
1573
 * @param options  options (currently only the value 0 is used)
1574
 * @returns 0 if the setting succeeded, and -1 on API or internal errors.
1575
 */
1576
int
1577
xmlXPathContextSetCache(xmlXPathContext *ctxt,
1578
      int active,
1579
      int value,
1580
      int options)
1581
0
{
1582
0
    if (ctxt == NULL)
1583
0
  return(-1);
1584
0
    if (active) {
1585
0
  xmlXPathContextCachePtr cache;
1586
1587
0
  if (ctxt->cache == NULL) {
1588
0
      ctxt->cache = xmlXPathNewCache();
1589
0
      if (ctxt->cache == NULL) {
1590
0
                xmlXPathErrMemory(ctxt);
1591
0
    return(-1);
1592
0
            }
1593
0
  }
1594
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
0
  if (options == 0) {
1596
0
      if (value < 0)
1597
0
    value = 100;
1598
0
      cache->maxNodeset = value;
1599
0
      cache->maxMisc = value;
1600
0
  }
1601
0
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
0
    return(0);
1606
0
}
1607
1608
/**
1609
 * This is the cached version of #xmlXPathWrapNodeSet.
1610
 * Wrap the Nodeset `val` in a new xmlXPathObject
1611
 *
1612
 * In case of error the node set is destroyed and NULL is returned.
1613
 *
1614
 * @param pctxt  the XPath context
1615
 * @param val  the NodePtr value
1616
 * @returns the created or reused object.
1617
 */
1618
static xmlXPathObjectPtr
1619
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1620
939k
{
1621
939k
    xmlXPathObjectPtr ret;
1622
939k
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
939k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
0
  xmlXPathContextCachePtr cache =
1626
0
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
0
  if (cache->miscObjs != NULL) {
1629
0
      ret = cache->miscObjs;
1630
0
            cache->miscObjs = (void *) ret->stringval;
1631
0
            cache->numMisc -= 1;
1632
0
            ret->stringval = NULL;
1633
0
      ret->type = XPATH_NODESET;
1634
0
      ret->nodesetval = val;
1635
0
      return(ret);
1636
0
  }
1637
0
    }
1638
1639
939k
    ret = xmlXPathWrapNodeSet(val);
1640
939k
    if (ret == NULL)
1641
126
        xmlXPathPErrMemory(pctxt);
1642
939k
    return(ret);
1643
939k
}
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
9.96k
{
1656
9.96k
    xmlXPathObjectPtr ret;
1657
9.96k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
9.96k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
0
  if (cache->miscObjs != NULL) {
1663
0
      ret = cache->miscObjs;
1664
0
            cache->miscObjs = (void *) ret->stringval;
1665
0
            cache->numMisc -= 1;
1666
0
      ret->type = XPATH_STRING;
1667
0
      ret->stringval = val;
1668
0
      return(ret);
1669
0
  }
1670
0
    }
1671
1672
9.96k
    ret = xmlXPathWrapString(val);
1673
9.96k
    if (ret == NULL)
1674
16
        xmlXPathPErrMemory(pctxt);
1675
9.96k
    return(ret);
1676
9.96k
}
1677
1678
/**
1679
 * This is the cached version of #xmlXPathNewNodeSet.
1680
 * Acquire an xmlXPathObject of type NodeSet and initialize
1681
 * it with the single Node `val`
1682
 *
1683
 * @param pctxt  the XPath context
1684
 * @param val  the NodePtr value
1685
 * @returns the created or reused object.
1686
 */
1687
static xmlXPathObjectPtr
1688
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1689
1.05M
{
1690
1.05M
    xmlXPathObjectPtr ret;
1691
1.05M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
1.05M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
0
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
0
      ret = cache->nodesetObjs;
1701
0
            cache->nodesetObjs = (void *) ret->stringval;
1702
0
            cache->numNodeset -= 1;
1703
0
            ret->stringval = NULL;
1704
0
      ret->type = XPATH_NODESET;
1705
0
      ret->boolval = 0;
1706
0
      if (val) {
1707
0
    if ((ret->nodesetval->nodeMax == 0) ||
1708
0
        (val->type == XML_NAMESPACE_DECL))
1709
0
    {
1710
0
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
0
                        xmlXPathPErrMemory(pctxt);
1712
0
    } else {
1713
0
        ret->nodesetval->nodeTab[0] = val;
1714
0
        ret->nodesetval->nodeNr = 1;
1715
0
    }
1716
0
      }
1717
0
      return(ret);
1718
0
  } else if (cache->miscObjs != NULL) {
1719
0
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
0
      set = xmlXPathNodeSetCreate(val);
1725
0
      if (set == NULL) {
1726
0
                xmlXPathPErrMemory(pctxt);
1727
0
    return(NULL);
1728
0
      }
1729
1730
0
      ret = cache->miscObjs;
1731
0
            cache->miscObjs = (void *) ret->stringval;
1732
0
            cache->numMisc -= 1;
1733
0
            ret->stringval = NULL;
1734
0
      ret->type = XPATH_NODESET;
1735
0
      ret->boolval = 0;
1736
0
      ret->nodesetval = set;
1737
0
      return(ret);
1738
0
  }
1739
0
    }
1740
1.05M
    ret = xmlXPathNewNodeSet(val);
1741
1.05M
    if (ret == NULL)
1742
328
        xmlXPathPErrMemory(pctxt);
1743
1.05M
    return(ret);
1744
1.05M
}
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
125k
{
1757
125k
    xmlXPathObjectPtr ret;
1758
125k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
125k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
0
  if (cache->miscObjs != NULL) {
1764
0
            xmlChar *copy;
1765
1766
0
            if (val == NULL)
1767
0
                val = BAD_CAST "";
1768
0
            copy = xmlStrdup(val);
1769
0
            if (copy == NULL) {
1770
0
                xmlXPathPErrMemory(pctxt);
1771
0
                return(NULL);
1772
0
            }
1773
1774
0
      ret = cache->miscObjs;
1775
0
            cache->miscObjs = (void *) ret->stringval;
1776
0
            cache->numMisc -= 1;
1777
0
      ret->type = XPATH_STRING;
1778
0
            ret->stringval = copy;
1779
0
      return(ret);
1780
0
  }
1781
0
    }
1782
1783
125k
    ret = xmlXPathNewString(val);
1784
125k
    if (ret == NULL)
1785
36
        xmlXPathPErrMemory(pctxt);
1786
125k
    return(ret);
1787
125k
}
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
3.47k
{
1800
3.47k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
3.47k
}
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
560k
{
1814
560k
    xmlXPathObjectPtr ret;
1815
560k
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
560k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
0
  if (cache->miscObjs != NULL) {
1821
0
      ret = cache->miscObjs;
1822
0
            cache->miscObjs = (void *) ret->stringval;
1823
0
            cache->numMisc -= 1;
1824
0
            ret->stringval = NULL;
1825
0
      ret->type = XPATH_BOOLEAN;
1826
0
      ret->boolval = (val != 0);
1827
0
      return(ret);
1828
0
  }
1829
0
    }
1830
1831
560k
    ret = xmlXPathNewBoolean(val);
1832
560k
    if (ret == NULL)
1833
83
        xmlXPathPErrMemory(pctxt);
1834
560k
    return(ret);
1835
560k
}
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
414k
{
1848
414k
    xmlXPathObjectPtr ret;
1849
414k
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
414k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
0
  if (cache->miscObjs != NULL) {
1855
0
      ret = cache->miscObjs;
1856
0
            cache->miscObjs = (void *) ret->stringval;
1857
0
            cache->numMisc -= 1;
1858
0
            ret->stringval = NULL;
1859
0
      ret->type = XPATH_NUMBER;
1860
0
      ret->floatval = val;
1861
0
      return(ret);
1862
0
  }
1863
0
    }
1864
1865
414k
    ret = xmlXPathNewFloat(val);
1866
414k
    if (ret == NULL)
1867
108
        xmlXPathPErrMemory(pctxt);
1868
414k
    return(ret);
1869
414k
}
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
127k
{
1882
127k
    xmlXPathObjectPtr ret;
1883
127k
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
127k
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
127k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
0
  switch (val->type) {
1890
0
            case XPATH_NODESET: {
1891
0
                xmlNodeSetPtr set;
1892
1893
0
                set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1894
0
                if (set == NULL) {
1895
0
                    xmlXPathPErrMemory(pctxt);
1896
0
                    return(NULL);
1897
0
                }
1898
0
                return(xmlXPathCacheWrapNodeSet(pctxt, set));
1899
0
            }
1900
0
      case XPATH_STRING:
1901
0
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
0
      case XPATH_NUMBER:
1905
0
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
0
  }
1909
0
    }
1910
127k
    ret = xmlXPathObjectCopy(val);
1911
127k
    if (ret == NULL)
1912
42
        xmlXPathPErrMemory(pctxt);
1913
127k
    return(ret);
1914
127k
}
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
632k
                             xmlXPathObjectPtr val) {
1932
632k
    double ret = 0.0;
1933
1934
632k
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
632k
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
421k
    case XPATH_NODESET:
1941
421k
    case XPATH_XSLT_TREE: {
1942
421k
        xmlChar *str;
1943
1944
421k
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
421k
        if (str == NULL) {
1946
70
            xmlXPathPErrMemory(ctxt);
1947
70
            ret = xmlXPathNAN;
1948
421k
        } else {
1949
421k
      ret = xmlXPathCastStringToNumber(str);
1950
421k
            xmlFree(str);
1951
421k
        }
1952
421k
  break;
1953
421k
    }
1954
122k
    case XPATH_STRING:
1955
122k
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
122k
  break;
1957
34.4k
    case XPATH_NUMBER:
1958
34.4k
  ret = val->floatval;
1959
34.4k
  break;
1960
54.2k
    case XPATH_BOOLEAN:
1961
54.2k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
54.2k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
632k
    }
1968
632k
    return(ret);
1969
632k
}
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
3.49M
{
1980
3.49M
    xmlXPathObjectPtr ret;
1981
1982
3.49M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
10.1k
        return (NULL);
1984
1985
3.48M
    ctxt->valueNr--;
1986
3.48M
    if (ctxt->valueNr > 0)
1987
3.36M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
117k
    else
1989
117k
        ctxt->value = NULL;
1990
3.48M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
3.48M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
3.48M
    return (ret);
1993
3.49M
}
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
3.48M
{
2008
3.48M
    if (ctxt == NULL) return(-1);
2009
3.48M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
735
        xmlXPathPErrMemory(ctxt);
2014
735
        return(-1);
2015
735
    }
2016
3.48M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
307
        xmlXPathObjectPtr *tmp;
2018
307
        int newSize;
2019
2020
307
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
307
                                  10, XPATH_MAX_STACK_DEPTH);
2022
307
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
307
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
307
        if (tmp == NULL) {
2029
1
            xmlXPathPErrMemory(ctxt);
2030
1
            xmlXPathFreeObject(value);
2031
1
            return (-1);
2032
1
        }
2033
306
  ctxt->valueTab = tmp;
2034
306
        ctxt->valueMax = newSize;
2035
306
    }
2036
3.48M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
3.48M
    ctxt->value = value;
2038
3.48M
    return (ctxt->valueNr++);
2039
3.48M
}
2040
2041
/**
2042
 * Pops a boolean from the stack, handling conversion if needed.
2043
 * Check error with xmlXPathCheckError.
2044
 *
2045
 * @param ctxt  an XPath parser context
2046
 * @returns the boolean
2047
 */
2048
int
2049
0
xmlXPathPopBoolean (xmlXPathParserContext *ctxt) {
2050
0
    xmlXPathObjectPtr obj;
2051
0
    int ret;
2052
2053
0
    obj = xmlXPathValuePop(ctxt);
2054
0
    if (obj == NULL) {
2055
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2056
0
  return(0);
2057
0
    }
2058
0
    if (obj->type != XPATH_BOOLEAN)
2059
0
  ret = xmlXPathCastToBoolean(obj);
2060
0
    else
2061
0
        ret = obj->boolval;
2062
0
    xmlXPathReleaseObject(ctxt->context, obj);
2063
0
    return(ret);
2064
0
}
2065
2066
/**
2067
 * Pops a number from the stack, handling conversion if needed.
2068
 * Check error with xmlXPathCheckError.
2069
 *
2070
 * @param ctxt  an XPath parser context
2071
 * @returns the number
2072
 */
2073
double
2074
0
xmlXPathPopNumber (xmlXPathParserContext *ctxt) {
2075
0
    xmlXPathObjectPtr obj;
2076
0
    double ret;
2077
2078
0
    obj = xmlXPathValuePop(ctxt);
2079
0
    if (obj == NULL) {
2080
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2081
0
  return(0);
2082
0
    }
2083
0
    if (obj->type != XPATH_NUMBER)
2084
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2085
0
    else
2086
0
        ret = obj->floatval;
2087
0
    xmlXPathReleaseObject(ctxt->context, obj);
2088
0
    return(ret);
2089
0
}
2090
2091
/**
2092
 * Pops a string from the stack, handling conversion if needed.
2093
 * Check error with xmlXPathCheckError.
2094
 *
2095
 * @param ctxt  an XPath parser context
2096
 * @returns the string
2097
 */
2098
xmlChar *
2099
0
xmlXPathPopString (xmlXPathParserContext *ctxt) {
2100
0
    xmlXPathObjectPtr obj;
2101
0
    xmlChar * ret;
2102
2103
0
    obj = xmlXPathValuePop(ctxt);
2104
0
    if (obj == NULL) {
2105
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2106
0
  return(NULL);
2107
0
    }
2108
0
    ret = xmlXPathCastToString(obj);
2109
0
    if (ret == NULL)
2110
0
        xmlXPathPErrMemory(ctxt);
2111
0
    xmlXPathReleaseObject(ctxt->context, obj);
2112
0
    return(ret);
2113
0
}
2114
2115
/**
2116
 * Pops a node-set from the stack, handling conversion if needed.
2117
 * Check error with xmlXPathCheckError.
2118
 *
2119
 * @param ctxt  an XPath parser context
2120
 * @returns the node-set
2121
 */
2122
xmlNodeSet *
2123
0
xmlXPathPopNodeSet (xmlXPathParserContext *ctxt) {
2124
0
    xmlXPathObjectPtr obj;
2125
0
    xmlNodeSetPtr ret;
2126
2127
0
    if (ctxt == NULL) return(NULL);
2128
0
    if (ctxt->value == NULL) {
2129
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130
0
  return(NULL);
2131
0
    }
2132
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2133
0
  xmlXPathSetTypeError(ctxt);
2134
0
  return(NULL);
2135
0
    }
2136
0
    obj = xmlXPathValuePop(ctxt);
2137
0
    ret = obj->nodesetval;
2138
0
    obj->nodesetval = NULL;
2139
0
    xmlXPathReleaseObject(ctxt->context, obj);
2140
0
    return(ret);
2141
0
}
2142
2143
/**
2144
 * Pops an external object from the stack, handling conversion if needed.
2145
 * Check error with xmlXPathCheckError.
2146
 *
2147
 * @param ctxt  an XPath parser context
2148
 * @returns the object
2149
 */
2150
void *
2151
0
xmlXPathPopExternal (xmlXPathParserContext *ctxt) {
2152
0
    xmlXPathObjectPtr obj;
2153
0
    void * ret;
2154
2155
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2156
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157
0
  return(NULL);
2158
0
    }
2159
0
    if (ctxt->value->type != XPATH_USERS) {
2160
0
  xmlXPathSetTypeError(ctxt);
2161
0
  return(NULL);
2162
0
    }
2163
0
    obj = xmlXPathValuePop(ctxt);
2164
0
    ret = obj->user;
2165
0
    obj->user = NULL;
2166
0
    xmlXPathReleaseObject(ctxt->context, obj);
2167
0
    return(ret);
2168
0
}
2169
2170
/*
2171
 * Macros for accessing the content. Those should be used only by the parser,
2172
 * and not exported.
2173
 *
2174
 * Dirty macros, i.e. one need to make assumption on the context to use them
2175
 *
2176
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2177
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2178
 *           in ISO-Latin or UTF-8.
2179
 *           This should be used internally by the parser
2180
 *           only to compare to ASCII values otherwise it would break when
2181
 *           running with UTF-8 encoding.
2182
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2183
 *           to compare on ASCII based substring.
2184
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2185
 *           strings within the parser.
2186
 *   CURRENT Returns the current char value, with the full decoding of
2187
 *           UTF-8 if we are using this mode. It returns an int.
2188
 *   NEXT    Skip to the next character, this does the proper decoding
2189
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2190
 *           It returns the pointer to the current xmlChar.
2191
 */
2192
2193
41.5M
#define CUR (*ctxt->cur)
2194
34.5k
#define SKIP(val) ctxt->cur += (val)
2195
2.20M
#define NXT(val) ctxt->cur[(val)]
2196
114k
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
24.0M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
17.5M
#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
3.20k
#define UPPER_DOUBLE 1E9
2213
599
#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
2.67k
#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
3.71k
{
2230
3.71k
    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
3.71k
    default:
2240
3.71k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
3.71k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
3.71k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
1.11k
                   (number == (int) number)) {
2248
515
      char work[30];
2249
515
      char *ptr, *cur;
2250
515
      int value = (int) number;
2251
2252
515
            ptr = &buffer[0];
2253
515
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
515
      } else {
2256
515
    snprintf(work, 29, "%d", value);
2257
515
    cur = &work[0];
2258
3.77k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
3.26k
        *ptr++ = *cur++;
2260
3.26k
    }
2261
515
      }
2262
515
      if (ptr - buffer < buffersize) {
2263
515
    *ptr = 0;
2264
515
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
3.20k
  } 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
3.20k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
3.20k
      int integer_place, fraction_place;
2280
3.20k
      char *ptr;
2281
3.20k
      char *after_fraction;
2282
3.20k
      double absolute_value;
2283
3.20k
      int size;
2284
2285
3.20k
      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
3.20k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
599
      (absolute_value < LOWER_DOUBLE)) &&
2294
2.67k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
2.67k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
2.67k
    fraction_place = DBL_DIG - 1;
2298
2.67k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
2.67k
       integer_place, fraction_place, number);
2300
13.6k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
2.67k
      }
2303
531
      else {
2304
    /* Use regular notation */
2305
531
    if (absolute_value > 0.0) {
2306
531
        integer_place = (int)log10(absolute_value);
2307
531
        if (integer_place > 0)
2308
330
            fraction_place = DBL_DIG - integer_place - 1;
2309
201
        else
2310
201
            fraction_place = DBL_DIG - integer_place;
2311
531
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
531
    size = snprintf(work, sizeof(work), "%0.*f",
2315
531
        fraction_place, number);
2316
531
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
3.52k
      while (work[0] == ' ') {
2320
6.86k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
327
    size--;
2322
327
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
3.20k
      after_fraction = work + size;
2326
3.20k
      ptr = after_fraction;
2327
14.3k
      while (*(--ptr) == '0')
2328
11.1k
    ;
2329
3.20k
      if (*ptr != '.')
2330
2.51k
          ptr++;
2331
14.1k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
3.20k
      size = strlen(work) + 1;
2335
3.20k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
3.20k
      memmove(buffer, work, size);
2340
3.20k
  }
2341
3.71k
  break;
2342
3.71k
    }
2343
3.71k
}
2344
2345
2346
/************************************************************************
2347
 *                  *
2348
 *      Routines to handle NodeSets     *
2349
 *                  *
2350
 ************************************************************************/
2351
2352
/**
2353
 * Call this routine to speed up XPath computation on static documents.
2354
 * This stamps all the element nodes with the document order
2355
 * Like for line information, the order is kept in the element->content
2356
 * field, the value stored is actually - the node number (starting at -1)
2357
 * to be able to differentiate from line numbers.
2358
 *
2359
 * @param doc  an input document
2360
 * @returns the number of elements found in the document or -1 in case
2361
 *    of error.
2362
 */
2363
long
2364
0
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
0
    XML_INTPTR_T count = 0;
2366
0
    xmlNodePtr cur;
2367
2368
0
    if (doc == NULL)
2369
0
  return(-1);
2370
0
    cur = doc->children;
2371
0
    while (cur != NULL) {
2372
0
  if (cur->type == XML_ELEMENT_NODE) {
2373
0
            count += 1;
2374
0
            cur->content = XML_INT_TO_PTR(-count);
2375
0
      if (cur->children != NULL) {
2376
0
    cur = cur->children;
2377
0
    continue;
2378
0
      }
2379
0
  }
2380
0
  if (cur->next != NULL) {
2381
0
      cur = cur->next;
2382
0
      continue;
2383
0
  }
2384
0
  do {
2385
0
      cur = cur->parent;
2386
0
      if (cur == NULL)
2387
0
    break;
2388
0
      if (cur == (xmlNodePtr) doc) {
2389
0
    cur = NULL;
2390
0
    break;
2391
0
      }
2392
0
      if (cur->next != NULL) {
2393
0
    cur = cur->next;
2394
0
    break;
2395
0
      }
2396
0
  } while (cur != NULL);
2397
0
    }
2398
0
    return(count);
2399
0
}
2400
2401
/**
2402
 * Compare two nodes w.r.t document order
2403
 *
2404
 * @param node1  the first node
2405
 * @param node2  the second node
2406
 * @returns -2 in case of error 1 if first point < second point, 0 if
2407
 *         it's the same node, -1 otherwise
2408
 */
2409
int
2410
0
xmlXPathCmpNodes(xmlNode *node1, xmlNode *node2) {
2411
0
    int depth1, depth2;
2412
0
    int attr1 = 0, attr2 = 0;
2413
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2414
0
    xmlNodePtr cur, root;
2415
2416
0
    if ((node1 == NULL) || (node2 == NULL))
2417
0
  return(-2);
2418
    /*
2419
     * a couple of optimizations which will avoid computations in most cases
2420
     */
2421
0
    if (node1 == node2)   /* trivial case */
2422
0
  return(0);
2423
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2424
0
  attr1 = 1;
2425
0
  attrNode1 = node1;
2426
0
  node1 = node1->parent;
2427
0
    }
2428
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2429
0
  attr2 = 1;
2430
0
  attrNode2 = node2;
2431
0
  node2 = node2->parent;
2432
0
    }
2433
0
    if (node1 == node2) {
2434
0
  if (attr1 == attr2) {
2435
      /* not required, but we keep attributes in order */
2436
0
      if (attr1 != 0) {
2437
0
          cur = attrNode2->prev;
2438
0
    while (cur != NULL) {
2439
0
        if (cur == attrNode1)
2440
0
            return (1);
2441
0
        cur = cur->prev;
2442
0
    }
2443
0
    return (-1);
2444
0
      }
2445
0
      return(0);
2446
0
  }
2447
0
  if (attr2 == 1)
2448
0
      return(1);
2449
0
  return(-1);
2450
0
    }
2451
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2452
0
        (node2->type == XML_NAMESPACE_DECL))
2453
0
  return(1);
2454
0
    if (node1 == node2->prev)
2455
0
  return(1);
2456
0
    if (node1 == node2->next)
2457
0
  return(-1);
2458
2459
    /*
2460
     * Speedup using document order if available.
2461
     */
2462
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2463
0
  (node2->type == XML_ELEMENT_NODE) &&
2464
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2465
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2466
0
  (node1->doc == node2->doc)) {
2467
0
  XML_INTPTR_T l1, l2;
2468
2469
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2470
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2471
0
  if (l1 < l2)
2472
0
      return(1);
2473
0
  if (l1 > l2)
2474
0
      return(-1);
2475
0
    }
2476
2477
    /*
2478
     * compute depth to root
2479
     */
2480
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2481
0
  if (cur->parent == node1)
2482
0
      return(1);
2483
0
  depth2++;
2484
0
    }
2485
0
    root = cur;
2486
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2487
0
  if (cur->parent == node2)
2488
0
      return(-1);
2489
0
  depth1++;
2490
0
    }
2491
    /*
2492
     * Distinct document (or distinct entities :-( ) case.
2493
     */
2494
0
    if (root != cur) {
2495
0
  return(-2);
2496
0
    }
2497
    /*
2498
     * get the nearest common ancestor.
2499
     */
2500
0
    while (depth1 > depth2) {
2501
0
  depth1--;
2502
0
  node1 = node1->parent;
2503
0
    }
2504
0
    while (depth2 > depth1) {
2505
0
  depth2--;
2506
0
  node2 = node2->parent;
2507
0
    }
2508
0
    while (node1->parent != node2->parent) {
2509
0
  node1 = node1->parent;
2510
0
  node2 = node2->parent;
2511
  /* should not happen but just in case ... */
2512
0
  if ((node1 == NULL) || (node2 == NULL))
2513
0
      return(-2);
2514
0
    }
2515
    /*
2516
     * Find who's first.
2517
     */
2518
0
    if (node1 == node2->prev)
2519
0
  return(1);
2520
0
    if (node1 == node2->next)
2521
0
  return(-1);
2522
    /*
2523
     * Speedup using document order if available.
2524
     */
2525
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2526
0
  (node2->type == XML_ELEMENT_NODE) &&
2527
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2528
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2529
0
  (node1->doc == node2->doc)) {
2530
0
  XML_INTPTR_T l1, l2;
2531
2532
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2533
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2534
0
  if (l1 < l2)
2535
0
      return(1);
2536
0
  if (l1 > l2)
2537
0
      return(-1);
2538
0
    }
2539
2540
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2541
0
  if (cur == node2)
2542
0
      return(1);
2543
0
    return(-1); /* assume there is no sibling list corruption */
2544
0
}
2545
2546
/**
2547
 * Sort the node set in document order
2548
 *
2549
 * @param set  the node set
2550
 */
2551
void
2552
38.0k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
38.0k
    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
38.0k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
38.0k
#endif /* WITH_TIM_SORT */
2591
38.0k
}
2592
2593
4.13M
#define XML_NODESET_DEFAULT 10
2594
/**
2595
 * Namespace node in libxml don't match the XPath semantic. In a node set
2596
 * the namespace nodes are duplicated and the next pointer is set to the
2597
 * parent node in the XPath semantic.
2598
 *
2599
 * @param node  the parent node of the namespace XPath node
2600
 * @param ns  the libxml namespace declaration node.
2601
 * @returns the newly created object.
2602
 */
2603
static xmlNodePtr
2604
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
0
    xmlNsPtr cur;
2606
2607
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2610
0
  return((xmlNodePtr) ns);
2611
2612
    /*
2613
     * Allocate a new Namespace and fill the fields.
2614
     */
2615
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
0
    if (cur == NULL)
2617
0
  return(NULL);
2618
0
    memset(cur, 0, sizeof(xmlNs));
2619
0
    cur->type = XML_NAMESPACE_DECL;
2620
0
    if (ns->href != NULL) {
2621
0
  cur->href = xmlStrdup(ns->href);
2622
0
        if (cur->href == NULL) {
2623
0
            xmlFree(cur);
2624
0
            return(NULL);
2625
0
        }
2626
0
    }
2627
0
    if (ns->prefix != NULL) {
2628
0
  cur->prefix = xmlStrdup(ns->prefix);
2629
0
        if (cur->prefix == NULL) {
2630
0
            xmlFree((xmlChar *) cur->href);
2631
0
            xmlFree(cur);
2632
0
            return(NULL);
2633
0
        }
2634
0
    }
2635
0
    cur->next = (xmlNsPtr) node;
2636
0
    return((xmlNodePtr) cur);
2637
0
}
2638
2639
/**
2640
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2641
 * the namespace nodes are duplicated and the next pointer is set to the
2642
 * parent node in the XPath semantic. Check if such a node needs to be freed
2643
 *
2644
 * @param ns  the XPath namespace node found in a nodeset.
2645
 */
2646
void
2647
0
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
0
  if (ns->href != NULL)
2653
0
      xmlFree((xmlChar *)ns->href);
2654
0
  if (ns->prefix != NULL)
2655
0
      xmlFree((xmlChar *)ns->prefix);
2656
0
  xmlFree(ns);
2657
0
    }
2658
0
}
2659
2660
/**
2661
 * Create a new xmlNodeSet of type double and of value `val`
2662
 *
2663
 * @param val  an initial xmlNode, or NULL
2664
 * @returns the newly created object.
2665
 */
2666
xmlNodeSet *
2667
2.01M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
2.01M
    xmlNodeSetPtr ret;
2669
2670
2.01M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
2.01M
    if (ret == NULL)
2672
243
  return(NULL);
2673
2.01M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
2.01M
    if (val != NULL) {
2675
1.05M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
1.05M
               sizeof(xmlNodePtr));
2677
1.05M
  if (ret->nodeTab == NULL) {
2678
109
      xmlFree(ret);
2679
109
      return(NULL);
2680
109
  }
2681
1.05M
  memset(ret->nodeTab, 0 ,
2682
1.05M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
1.05M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
1.05M
  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.05M
      ret->nodeTab[ret->nodeNr++] = val;
2695
1.05M
    }
2696
2.01M
    return(ret);
2697
2.01M
}
2698
2699
/**
2700
 * checks whether `cur` contains `val`
2701
 *
2702
 * @param cur  the node-set
2703
 * @param val  the node
2704
 * @returns true (1) if `cur` contains `val`, false (0) otherwise
2705
 */
2706
int
2707
0
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
0
    int i;
2709
2710
0
    if ((cur == NULL) || (val == NULL)) return(0);
2711
0
    if (val->type == XML_NAMESPACE_DECL) {
2712
0
  for (i = 0; i < cur->nodeNr; i++) {
2713
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2714
0
    xmlNsPtr ns1, ns2;
2715
2716
0
    ns1 = (xmlNsPtr) val;
2717
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2718
0
    if (ns1 == ns2)
2719
0
        return(1);
2720
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2721
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2722
0
        return(1);
2723
0
      }
2724
0
  }
2725
0
    } else {
2726
0
  for (i = 0; i < cur->nodeNr; i++) {
2727
0
      if (cur->nodeTab[i] == val)
2728
0
    return(1);
2729
0
  }
2730
0
    }
2731
0
    return(0);
2732
0
}
2733
2734
static int
2735
896k
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
896k
    xmlNodePtr *temp;
2737
896k
    int newSize;
2738
2739
896k
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
896k
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
896k
    if (newSize < 0)
2742
0
        return(-1);
2743
896k
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
896k
    if (temp == NULL)
2745
216
        return(-1);
2746
896k
    cur->nodeMax = newSize;
2747
896k
    cur->nodeTab = temp;
2748
2749
896k
    return(0);
2750
896k
}
2751
2752
/**
2753
 * add a new namespace node to an existing NodeSet
2754
 *
2755
 * @param cur  the initial node set
2756
 * @param node  the hosting node
2757
 * @param ns  a the namespace node
2758
 * @returns 0 in case of success and -1 in case of error
2759
 */
2760
int
2761
0
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
0
    int i;
2763
0
    xmlNodePtr nsNode;
2764
2765
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
0
        (ns->type != XML_NAMESPACE_DECL) ||
2767
0
  (node->type != XML_ELEMENT_NODE))
2768
0
  return(-1);
2769
2770
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2771
    /*
2772
     * prevent duplicates
2773
     */
2774
0
    for (i = 0;i < cur->nodeNr;i++) {
2775
0
        if ((cur->nodeTab[i] != NULL) &&
2776
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
0
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
0
    if (cur->nodeNr >= cur->nodeMax) {
2786
0
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
0
            return(-1);
2788
0
    }
2789
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
0
    if(nsNode == NULL)
2791
0
        return(-1);
2792
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
0
    return(0);
2794
0
}
2795
2796
/**
2797
 * add a new xmlNode to an existing NodeSet
2798
 *
2799
 * @param cur  the initial node set
2800
 * @param val  a new xmlNode
2801
 * @returns 0 in case of success, and -1 in case of error
2802
 */
2803
int
2804
865
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
865
    int i;
2806
2807
865
    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
865
    for (i = 0;i < cur->nodeNr;i++)
2814
335
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
530
    if (cur->nodeNr >= cur->nodeMax) {
2820
530
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
2
            return(-1);
2822
530
    }
2823
2824
528
    if (val->type == XML_NAMESPACE_DECL) {
2825
0
  xmlNsPtr ns = (xmlNsPtr) val;
2826
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828
0
        if (nsNode == NULL)
2829
0
            return(-1);
2830
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2831
0
    } else
2832
528
  cur->nodeTab[cur->nodeNr++] = val;
2833
528
    return(0);
2834
528
}
2835
2836
/**
2837
 * add a new xmlNode to an existing NodeSet, optimized version
2838
 * when we are sure the node is not already in the set.
2839
 *
2840
 * @param cur  the initial node set
2841
 * @param val  a new xmlNode
2842
 * @returns 0 in case of success and -1 in case of failure
2843
 */
2844
int
2845
5.10M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
5.10M
    if ((cur == NULL) || (val == NULL)) return(-1);
2847
2848
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2849
    /*
2850
     * grow the nodeTab if needed
2851
     */
2852
5.10M
    if (cur->nodeNr >= cur->nodeMax) {
2853
763k
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
137
            return(-1);
2855
763k
    }
2856
2857
5.10M
    if (val->type == XML_NAMESPACE_DECL) {
2858
0
  xmlNsPtr ns = (xmlNsPtr) val;
2859
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
0
        if (nsNode == NULL)
2862
0
            return(-1);
2863
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
0
    } else
2865
5.10M
  cur->nodeTab[cur->nodeNr++] = val;
2866
5.10M
    return(0);
2867
5.10M
}
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
55.0k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
55.0k
    int i, j, initNr, skip;
2882
55.0k
    xmlNodePtr n1, n2;
2883
2884
55.0k
    if (val1 == NULL) {
2885
4
  val1 = xmlXPathNodeSetCreate(NULL);
2886
4
        if (val1 == NULL)
2887
0
            return (NULL);
2888
4
    }
2889
55.0k
    if (val2 == NULL)
2890
30
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
54.9k
    initNr = val1->nodeNr;
2894
2895
742k
    for (i = 0;i < val2->nodeNr;i++) {
2896
687k
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
687k
  skip = 0;
2901
2.19M
  for (j = 0; j < initNr; j++) {
2902
1.53M
      n1 = val1->nodeTab[j];
2903
1.53M
      if (n1 == n2) {
2904
26.5k
    skip = 1;
2905
26.5k
    break;
2906
1.50M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
0
           (n2->type == XML_NAMESPACE_DECL)) {
2908
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
0
      ((xmlNsPtr) n2)->prefix)))
2911
0
    {
2912
0
        skip = 1;
2913
0
        break;
2914
0
    }
2915
0
      }
2916
1.53M
  }
2917
687k
  if (skip)
2918
26.5k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
660k
        if (val1->nodeNr >= val1->nodeMax) {
2924
74.3k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
18
                goto error;
2926
74.3k
        }
2927
660k
  if (n2->type == XML_NAMESPACE_DECL) {
2928
0
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
0
            if (nsNode == NULL)
2932
0
                goto error;
2933
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
0
  } else
2935
660k
      val1->nodeTab[val1->nodeNr++] = n2;
2936
660k
    }
2937
2938
54.9k
    return(val1);
2939
2940
18
error:
2941
18
    xmlXPathFreeNodeSet(val1);
2942
18
    return(NULL);
2943
54.9k
}
2944
2945
2946
/**
2947
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
2948
 * Checks for duplicate nodes. Clears set2.
2949
 *
2950
 * Frees `set1` in case of error.
2951
 *
2952
 * @param set1  the first NodeSet or NULL
2953
 * @param set2  the second NodeSet
2954
 * @returns `set1` once extended or NULL in case of error.
2955
 */
2956
static xmlNodeSetPtr
2957
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2958
364k
{
2959
364k
    {
2960
364k
  int i, j, initNbSet1;
2961
364k
  xmlNodePtr n1, n2;
2962
2963
364k
  initNbSet1 = set1->nodeNr;
2964
772k
  for (i = 0;i < set2->nodeNr;i++) {
2965
407k
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
26.6M
      for (j = 0; j < initNbSet1; j++) {
2970
26.4M
    n1 = set1->nodeTab[j];
2971
26.4M
    if (n1 == n2) {
2972
247k
        goto skip_node;
2973
26.2M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
0
        (n2->type == XML_NAMESPACE_DECL))
2975
0
    {
2976
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
0
      ((xmlNsPtr) n2)->prefix)))
2979
0
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
0
      goto skip_node;
2985
0
        }
2986
0
    }
2987
26.4M
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
160k
            if (set1->nodeNr >= set1->nodeMax) {
2992
30.4k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
30
                    goto error;
2994
30.4k
            }
2995
160k
      set1->nodeTab[set1->nodeNr++] = n2;
2996
407k
skip_node:
2997
407k
            set2->nodeTab[i] = NULL;
2998
407k
  }
2999
364k
    }
3000
364k
    set2->nodeNr = 0;
3001
364k
    return(set1);
3002
3003
30
error:
3004
30
    xmlXPathFreeNodeSet(set1);
3005
30
    xmlXPathNodeSetClear(set2, 1);
3006
30
    return(NULL);
3007
364k
}
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
284k
{
3022
284k
    {
3023
284k
  int i;
3024
284k
  xmlNodePtr n2;
3025
3026
800k
  for (i = 0;i < set2->nodeNr;i++) {
3027
515k
      n2 = set2->nodeTab[i];
3028
515k
            if (set1->nodeNr >= set1->nodeMax) {
3029
27.8k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
29
                    goto error;
3031
27.8k
            }
3032
515k
      set1->nodeTab[set1->nodeNr++] = n2;
3033
515k
            set2->nodeTab[i] = NULL;
3034
515k
  }
3035
284k
    }
3036
284k
    set2->nodeNr = 0;
3037
284k
    return(set1);
3038
3039
29
error:
3040
29
    xmlXPathFreeNodeSet(set1);
3041
29
    xmlXPathNodeSetClear(set2, 1);
3042
29
    return(NULL);
3043
284k
}
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.01M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
2.01M
    if (obj == NULL) return;
3103
2.01M
    if (obj->nodeTab != NULL) {
3104
1.30M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
7.75M
  for (i = 0;i < obj->nodeNr;i++)
3108
6.44M
      if ((obj->nodeTab[i] != NULL) &&
3109
6.44M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
1.30M
  xmlFree(obj->nodeTab);
3112
1.30M
    }
3113
2.01M
    xmlFree(obj);
3114
2.01M
}
3115
3116
/**
3117
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3118
 * are feed) starting with the entry at `pos`, but does *not* free the list
3119
 * itself. Sets the length of the list to `pos`.
3120
 *
3121
 * @param set  the node set to be cleared
3122
 * @param pos  the start position to clear from
3123
 * @param hasNsNodes  the node set might contain namespace nodes
3124
 */
3125
static void
3126
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3127
2.14k
{
3128
2.14k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
2.14k
    else if ((hasNsNodes)) {
3131
216
  int i;
3132
216
  xmlNodePtr node;
3133
3134
2.34k
  for (i = pos; i < set->nodeNr; i++) {
3135
2.12k
      node = set->nodeTab[i];
3136
2.12k
      if ((node != NULL) &&
3137
1.56k
    (node->type == XML_NAMESPACE_DECL))
3138
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
2.12k
  }
3140
216
    }
3141
2.14k
    set->nodeNr = pos;
3142
2.14k
}
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
1.98k
{
3155
1.98k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
1.98k
}
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
1.05M
xmlXPathNewNodeSet(xmlNode *val) {
3192
1.05M
    xmlXPathObjectPtr ret;
3193
3194
1.05M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
1.05M
    if (ret == NULL)
3196
117
  return(NULL);
3197
1.05M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
1.05M
    ret->type = XPATH_NODESET;
3199
1.05M
    ret->boolval = 0;
3200
1.05M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
1.05M
    if (ret->nodesetval == NULL) {
3202
227
        xmlFree(ret);
3203
227
        return(NULL);
3204
227
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
1.05M
    return(ret);
3207
1.05M
}
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
939k
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
939k
    xmlXPathObjectPtr ret;
3269
3270
939k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
939k
    if (ret == NULL) {
3272
126
        xmlXPathFreeNodeSet(val);
3273
126
  return(NULL);
3274
126
    }
3275
939k
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
939k
    ret->type = XPATH_NODESET;
3277
939k
    ret->nodesetval = val;
3278
939k
    return(ret);
3279
939k
}
3280
3281
/**
3282
 * Free up the xmlXPathObject `obj` but don't deallocate the objects in
3283
 * the list contrary to #xmlXPathFreeObject.
3284
 *
3285
 * @param obj  an existing NodeSetList object
3286
 */
3287
void
3288
0
xmlXPathFreeNodeSetList(xmlXPathObject *obj) {
3289
0
    if (obj == NULL) return;
3290
0
    xmlFree(obj);
3291
0
}
3292
3293
/**
3294
 * Implements the EXSLT - Sets difference() function:
3295
 *    node-set set:difference (node-set, node-set)
3296
 *
3297
 * @param nodes1  a node-set
3298
 * @param nodes2  a node-set
3299
 * @returns the difference between the two node sets, or nodes1 if
3300
 *         nodes2 is empty
3301
 */
3302
xmlNodeSet *
3303
0
xmlXPathDifference (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3304
0
    xmlNodeSetPtr ret;
3305
0
    int i, l1;
3306
0
    xmlNodePtr cur;
3307
3308
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3309
0
  return(nodes1);
3310
3311
0
    ret = xmlXPathNodeSetCreate(NULL);
3312
0
    if (ret == NULL)
3313
0
        return(NULL);
3314
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3315
0
  return(ret);
3316
3317
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3318
3319
0
    for (i = 0; i < l1; i++) {
3320
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3321
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3322
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3323
0
                xmlXPathFreeNodeSet(ret);
3324
0
          return(NULL);
3325
0
            }
3326
0
  }
3327
0
    }
3328
0
    return(ret);
3329
0
}
3330
3331
/**
3332
 * Implements the EXSLT - Sets intersection() function:
3333
 *    node-set set:intersection (node-set, node-set)
3334
 *
3335
 * @param nodes1  a node-set
3336
 * @param nodes2  a node-set
3337
 * @returns a node set comprising the nodes that are within both the
3338
 *         node sets passed as arguments
3339
 */
3340
xmlNodeSet *
3341
0
xmlXPathIntersection (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3342
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3343
0
    int i, l1;
3344
0
    xmlNodePtr cur;
3345
3346
0
    if (ret == NULL)
3347
0
        return(ret);
3348
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3349
0
  return(ret);
3350
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3351
0
  return(ret);
3352
3353
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3354
3355
0
    for (i = 0; i < l1; i++) {
3356
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3357
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3358
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3359
0
                xmlXPathFreeNodeSet(ret);
3360
0
          return(NULL);
3361
0
            }
3362
0
  }
3363
0
    }
3364
0
    return(ret);
3365
0
}
3366
3367
/**
3368
 * Implements the EXSLT - Sets distinct() function:
3369
 *    node-set set:distinct (node-set)
3370
 *
3371
 * @param nodes  a node-set, sorted by document order
3372
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3373
 *         it is empty
3374
 */
3375
xmlNodeSet *
3376
0
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3377
0
    xmlNodeSetPtr ret;
3378
0
    xmlHashTablePtr hash;
3379
0
    int i, l;
3380
0
    xmlChar * strval;
3381
0
    xmlNodePtr cur;
3382
3383
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3384
0
  return(nodes);
3385
3386
0
    ret = xmlXPathNodeSetCreate(NULL);
3387
0
    if (ret == NULL)
3388
0
        return(ret);
3389
0
    l = xmlXPathNodeSetGetLength(nodes);
3390
0
    hash = xmlHashCreate (l);
3391
0
    for (i = 0; i < l; i++) {
3392
0
  cur = xmlXPathNodeSetItem(nodes, i);
3393
0
  strval = xmlXPathCastNodeToString(cur);
3394
0
  if (xmlHashLookup(hash, strval) == NULL) {
3395
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3396
0
                xmlFree(strval);
3397
0
                goto error;
3398
0
            }
3399
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3400
0
          goto error;
3401
0
  } else {
3402
0
      xmlFree(strval);
3403
0
  }
3404
0
    }
3405
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3406
0
    return(ret);
3407
3408
0
error:
3409
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3410
0
    xmlXPathFreeNodeSet(ret);
3411
0
    return(NULL);
3412
0
}
3413
3414
/**
3415
 * Implements the EXSLT - Sets distinct() function:
3416
 *    node-set set:distinct (node-set)
3417
 * `nodes` is sorted by document order, then exslSetsDistinctSorted
3418
 * is called with the sorted node-set
3419
 *
3420
 * @param nodes  a node-set
3421
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3422
 *         it is empty
3423
 */
3424
xmlNodeSet *
3425
0
xmlXPathDistinct (xmlNodeSet *nodes) {
3426
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3427
0
  return(nodes);
3428
3429
0
    xmlXPathNodeSetSort(nodes);
3430
0
    return(xmlXPathDistinctSorted(nodes));
3431
0
}
3432
3433
/**
3434
 * Implements the EXSLT - Sets has-same-nodes function:
3435
 *    boolean set:has-same-node(node-set, node-set)
3436
 *
3437
 * @param nodes1  a node-set
3438
 * @param nodes2  a node-set
3439
 * @returns true (1) if `nodes1` shares any node with `nodes2`, false (0)
3440
 *         otherwise
3441
 */
3442
int
3443
0
xmlXPathHasSameNodes (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3444
0
    int i, l;
3445
0
    xmlNodePtr cur;
3446
3447
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3448
0
  xmlXPathNodeSetIsEmpty(nodes2))
3449
0
  return(0);
3450
3451
0
    l = xmlXPathNodeSetGetLength(nodes1);
3452
0
    for (i = 0; i < l; i++) {
3453
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3454
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3455
0
      return(1);
3456
0
    }
3457
0
    return(0);
3458
0
}
3459
3460
/**
3461
 * Implements the EXSLT - Sets leading() function:
3462
 *    node-set set:leading (node-set, node-set)
3463
 *
3464
 * @param nodes  a node-set, sorted by document order
3465
 * @param node  a node
3466
 * @returns the nodes in `nodes` that precede `node` in document order,
3467
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3468
 *         doesn't contain `node`
3469
 */
3470
xmlNodeSet *
3471
0
xmlXPathNodeLeadingSorted (xmlNodeSet *nodes, xmlNode *node) {
3472
0
    int i, l;
3473
0
    xmlNodePtr cur;
3474
0
    xmlNodeSetPtr ret;
3475
3476
0
    if (node == NULL)
3477
0
  return(nodes);
3478
3479
0
    ret = xmlXPathNodeSetCreate(NULL);
3480
0
    if (ret == NULL)
3481
0
        return(ret);
3482
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3483
0
  (!xmlXPathNodeSetContains(nodes, node)))
3484
0
  return(ret);
3485
3486
0
    l = xmlXPathNodeSetGetLength(nodes);
3487
0
    for (i = 0; i < l; i++) {
3488
0
  cur = xmlXPathNodeSetItem(nodes, i);
3489
0
  if (cur == node)
3490
0
      break;
3491
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3492
0
            xmlXPathFreeNodeSet(ret);
3493
0
      return(NULL);
3494
0
        }
3495
0
    }
3496
0
    return(ret);
3497
0
}
3498
3499
/**
3500
 * Implements the EXSLT - Sets leading() function:
3501
 *    node-set set:leading (node-set, node-set)
3502
 * `nodes` is sorted by document order, then exslSetsNodeLeadingSorted
3503
 * is called.
3504
 *
3505
 * @param nodes  a node-set
3506
 * @param node  a node
3507
 * @returns the nodes in `nodes` that precede `node` in document order,
3508
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3509
 *         doesn't contain `node`
3510
 */
3511
xmlNodeSet *
3512
0
xmlXPathNodeLeading (xmlNodeSet *nodes, xmlNode *node) {
3513
0
    xmlXPathNodeSetSort(nodes);
3514
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3515
0
}
3516
3517
/**
3518
 * Implements the EXSLT - Sets leading() function:
3519
 *    node-set set:leading (node-set, node-set)
3520
 *
3521
 * @param nodes1  a node-set, sorted by document order
3522
 * @param nodes2  a node-set, sorted by document order
3523
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3524
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3525
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3526
 */
3527
xmlNodeSet *
3528
0
xmlXPathLeadingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3529
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3530
0
  return(nodes1);
3531
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3532
0
             xmlXPathNodeSetItem(nodes2, 1)));
3533
0
}
3534
3535
/**
3536
 * Implements the EXSLT - Sets leading() function:
3537
 *    node-set set:leading (node-set, node-set)
3538
 * `nodes1` and `nodes2` are sorted by document order, then
3539
 * exslSetsLeadingSorted is called.
3540
 *
3541
 * @param nodes1  a node-set
3542
 * @param nodes2  a node-set
3543
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3544
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3545
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3546
 */
3547
xmlNodeSet *
3548
0
xmlXPathLeading (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3549
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3550
0
  return(nodes1);
3551
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3552
0
  return(xmlXPathNodeSetCreate(NULL));
3553
0
    xmlXPathNodeSetSort(nodes1);
3554
0
    xmlXPathNodeSetSort(nodes2);
3555
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3556
0
             xmlXPathNodeSetItem(nodes2, 1)));
3557
0
}
3558
3559
/**
3560
 * Implements the EXSLT - Sets trailing() function:
3561
 *    node-set set:trailing (node-set, node-set)
3562
 *
3563
 * @param nodes  a node-set, sorted by document order
3564
 * @param node  a node
3565
 * @returns the nodes in `nodes` that follow `node` in document order,
3566
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3567
 *         doesn't contain `node`
3568
 */
3569
xmlNodeSet *
3570
0
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3571
0
    int i, l;
3572
0
    xmlNodePtr cur;
3573
0
    xmlNodeSetPtr ret;
3574
3575
0
    if (node == NULL)
3576
0
  return(nodes);
3577
3578
0
    ret = xmlXPathNodeSetCreate(NULL);
3579
0
    if (ret == NULL)
3580
0
        return(ret);
3581
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3582
0
  (!xmlXPathNodeSetContains(nodes, node)))
3583
0
  return(ret);
3584
3585
0
    l = xmlXPathNodeSetGetLength(nodes);
3586
0
    for (i = l - 1; i >= 0; i--) {
3587
0
  cur = xmlXPathNodeSetItem(nodes, i);
3588
0
  if (cur == node)
3589
0
      break;
3590
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3591
0
            xmlXPathFreeNodeSet(ret);
3592
0
      return(NULL);
3593
0
        }
3594
0
    }
3595
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3596
0
    return(ret);
3597
0
}
3598
3599
/**
3600
 * Implements the EXSLT - Sets trailing() function:
3601
 *    node-set set:trailing (node-set, node-set)
3602
 * `nodes` is sorted by document order, then #xmlXPathNodeTrailingSorted
3603
 * is called.
3604
 *
3605
 * @param nodes  a node-set
3606
 * @param node  a node
3607
 * @returns the nodes in `nodes` that follow `node` in document order,
3608
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3609
 *         doesn't contain `node`
3610
 */
3611
xmlNodeSet *
3612
0
xmlXPathNodeTrailing (xmlNodeSet *nodes, xmlNode *node) {
3613
0
    xmlXPathNodeSetSort(nodes);
3614
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3615
0
}
3616
3617
/**
3618
 * Implements the EXSLT - Sets trailing() function:
3619
 *    node-set set:trailing (node-set, node-set)
3620
 *
3621
 * @param nodes1  a node-set, sorted by document order
3622
 * @param nodes2  a node-set, sorted by document order
3623
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3624
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3625
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3626
 */
3627
xmlNodeSet *
3628
0
xmlXPathTrailingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3629
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3630
0
  return(nodes1);
3631
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3632
0
              xmlXPathNodeSetItem(nodes2, 0)));
3633
0
}
3634
3635
/**
3636
 * Implements the EXSLT - Sets trailing() function:
3637
 *    node-set set:trailing (node-set, node-set)
3638
 * `nodes1` and `nodes2` are sorted by document order, then
3639
 * #xmlXPathTrailingSorted is called.
3640
 *
3641
 * @param nodes1  a node-set
3642
 * @param nodes2  a node-set
3643
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3644
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3645
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3646
 */
3647
xmlNodeSet *
3648
0
xmlXPathTrailing (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3649
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3650
0
  return(nodes1);
3651
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3652
0
  return(xmlXPathNodeSetCreate(NULL));
3653
0
    xmlXPathNodeSetSort(nodes1);
3654
0
    xmlXPathNodeSetSort(nodes2);
3655
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3656
0
              xmlXPathNodeSetItem(nodes2, 0)));
3657
0
}
3658
3659
/************************************************************************
3660
 *                  *
3661
 *    Routines to handle extra functions      *
3662
 *                  *
3663
 ************************************************************************/
3664
3665
/**
3666
 * Register a new function. If `f` is NULL it unregisters the function
3667
 *
3668
 * @param ctxt  the XPath context
3669
 * @param name  the function name
3670
 * @param f  the function implementation or NULL
3671
 * @returns 0 in case of success, -1 in case of error
3672
 */
3673
int
3674
xmlXPathRegisterFunc(xmlXPathContext *ctxt, const xmlChar *name,
3675
0
         xmlXPathFunction f) {
3676
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
0
}
3678
3679
/**
3680
 * Register a new function. If `f` is NULL it unregisters the function
3681
 *
3682
 * @param ctxt  the XPath context
3683
 * @param name  the function name
3684
 * @param ns_uri  the function namespace URI
3685
 * @param f  the function implementation or NULL
3686
 * @returns 0 in case of success, -1 in case of error
3687
 */
3688
int
3689
xmlXPathRegisterFuncNS(xmlXPathContext *ctxt, const xmlChar *name,
3690
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
0
    int ret;
3692
0
    void *payload;
3693
3694
0
    if (ctxt == NULL)
3695
0
  return(-1);
3696
0
    if (name == NULL)
3697
0
  return(-1);
3698
3699
0
    if (ctxt->funcHash == NULL)
3700
0
  ctxt->funcHash = xmlHashCreate(0);
3701
0
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
0
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
0
    memcpy(&payload, &f, sizeof(f));
3708
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
0
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
0
    return(0);
3715
0
}
3716
3717
/**
3718
 * Registers an external mechanism to do function lookup.
3719
 *
3720
 * @param ctxt  the XPath context
3721
 * @param f  the lookup function
3722
 * @param funcCtxt  the lookup data
3723
 */
3724
void
3725
xmlXPathRegisterFuncLookup (xmlXPathContext *ctxt,
3726
          xmlXPathFuncLookupFunc f,
3727
0
          void *funcCtxt) {
3728
0
    if (ctxt == NULL)
3729
0
  return;
3730
0
    ctxt->funcLookupFunc = f;
3731
0
    ctxt->funcLookupData = funcCtxt;
3732
0
}
3733
3734
/**
3735
 * Search in the Function array of the context for the given
3736
 * function.
3737
 *
3738
 * @param ctxt  the XPath context
3739
 * @param name  the function name
3740
 * @returns the xmlXPathFunction or NULL if not found
3741
 */
3742
xmlXPathFunction
3743
6.84k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
6.84k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
6.84k
}
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
6.86k
       const xmlChar *ns_uri) {
3759
6.86k
    xmlXPathFunction ret;
3760
6.86k
    void *payload;
3761
3762
6.86k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
6.86k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
6.86k
    if (ns_uri == NULL) {
3768
6.84k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
9.37k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
8.91k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
8.91k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
8.91k
                       (char *) name) == 0)
3775
6.38k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
2.52k
            bucketIndex += 1;
3778
2.52k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
2.52k
        }
3781
6.84k
    }
3782
3783
473
    if (ctxt->funcLookupFunc != NULL) {
3784
0
  xmlXPathFuncLookupFunc f;
3785
3786
0
  f = ctxt->funcLookupFunc;
3787
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
0
  if (ret != NULL)
3789
0
      return(ret);
3790
0
    }
3791
3792
473
    if (ctxt->funcHash == NULL)
3793
473
  return(NULL);
3794
3795
0
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
0
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
0
    return(ret);
3799
473
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
6.12k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
6.12k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
6.12k
    xmlHashFree(ctxt->funcHash, NULL);
3812
6.12k
    ctxt->funcHash = NULL;
3813
6.12k
}
3814
3815
/************************************************************************
3816
 *                  *
3817
 *      Routines to handle Variables      *
3818
 *                  *
3819
 ************************************************************************/
3820
3821
/**
3822
 * Register a new variable value. If `value` is NULL it unregisters
3823
 * the variable
3824
 *
3825
 * @param ctxt  the XPath context
3826
 * @param name  the variable name
3827
 * @param value  the variable value or NULL
3828
 * @returns 0 in case of success, -1 in case of error
3829
 */
3830
int
3831
xmlXPathRegisterVariable(xmlXPathContext *ctxt, const xmlChar *name,
3832
0
       xmlXPathObject *value) {
3833
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
0
}
3835
3836
/**
3837
 * Register a new variable value. If `value` is NULL it unregisters
3838
 * the variable
3839
 *
3840
 * @param ctxt  the XPath context
3841
 * @param name  the variable name
3842
 * @param ns_uri  the variable namespace URI
3843
 * @param value  the variable value or NULL
3844
 * @returns 0 in case of success, -1 in case of error
3845
 */
3846
int
3847
xmlXPathRegisterVariableNS(xmlXPathContext *ctxt, const xmlChar *name,
3848
         const xmlChar *ns_uri,
3849
0
         xmlXPathObject *value) {
3850
0
    if (ctxt == NULL)
3851
0
  return(-1);
3852
0
    if (name == NULL)
3853
0
  return(-1);
3854
3855
0
    if (ctxt->varHash == NULL)
3856
0
  ctxt->varHash = xmlHashCreate(0);
3857
0
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
0
    if (value == NULL)
3860
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
0
                             xmlXPathFreeObjectEntry));
3862
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
0
             (void *) value, xmlXPathFreeObjectEntry));
3864
0
}
3865
3866
/**
3867
 * register an external mechanism to do variable lookup
3868
 *
3869
 * @param ctxt  the XPath context
3870
 * @param f  the lookup function
3871
 * @param data  the lookup data
3872
 */
3873
void
3874
xmlXPathRegisterVariableLookup(xmlXPathContext *ctxt,
3875
0
   xmlXPathVariableLookupFunc f, void *data) {
3876
0
    if (ctxt == NULL)
3877
0
  return;
3878
0
    ctxt->varLookupFunc = f;
3879
0
    ctxt->varLookupData = data;
3880
0
}
3881
3882
/**
3883
 * Search in the Variable array of the context for the given
3884
 * variable value.
3885
 *
3886
 * @param ctxt  the XPath context
3887
 * @param name  the variable name
3888
 * @returns a copy of the value or NULL if not found
3889
 */
3890
xmlXPathObject *
3891
35
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
35
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
35
    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
35
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
35
}
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
59
       const xmlChar *ns_uri) {
3917
59
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
59
    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
59
    if (ctxt->varHash == NULL)
3929
59
  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
6.12k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
6.12k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
6.12k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
6.12k
    ctxt->varHash = NULL;
3948
6.12k
}
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
76
         const xmlChar *ns_uri) {
3962
76
    xmlChar *copy;
3963
3964
76
    if (ctxt == NULL)
3965
0
  return(-1);
3966
76
    if (prefix == NULL)
3967
0
  return(-1);
3968
76
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
76
    if (ctxt->nsHash == NULL)
3972
32
  ctxt->nsHash = xmlHashCreate(10);
3973
76
    if (ctxt->nsHash == NULL) {
3974
1
        xmlXPathErrMemory(ctxt);
3975
1
  return(-1);
3976
1
    }
3977
75
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
75
    copy = xmlStrdup(ns_uri);
3982
75
    if (copy == NULL) {
3983
1
        xmlXPathErrMemory(ctxt);
3984
1
        return(-1);
3985
1
    }
3986
74
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
74
                           xmlHashDefaultDeallocator) < 0) {
3988
1
        xmlXPathErrMemory(ctxt);
3989
1
        xmlFree(copy);
3990
1
        return(-1);
3991
1
    }
3992
3993
73
    return(0);
3994
74
}
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
12.4k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
12.4k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
12.4k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
12.4k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
12.0k
  return(XML_XML_NAMESPACE);
4013
4014
323
    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
323
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
323
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
6.12k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
6.12k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
6.12k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
6.12k
    ctxt->nsHash = NULL;
4039
6.12k
}
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
414k
xmlXPathNewFloat(double val) {
4057
414k
    xmlXPathObjectPtr ret;
4058
4059
414k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
414k
    if (ret == NULL)
4061
108
  return(NULL);
4062
414k
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
414k
    ret->type = XPATH_NUMBER;
4064
414k
    ret->floatval = val;
4065
414k
    return(ret);
4066
414k
}
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
560k
xmlXPathNewBoolean(int val) {
4076
560k
    xmlXPathObjectPtr ret;
4077
4078
560k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
560k
    if (ret == NULL)
4080
83
  return(NULL);
4081
560k
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
560k
    ret->type = XPATH_BOOLEAN;
4083
560k
    ret->boolval = (val != 0);
4084
560k
    return(ret);
4085
560k
}
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
125k
xmlXPathNewString(const xmlChar *val) {
4095
125k
    xmlXPathObjectPtr ret;
4096
4097
125k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
125k
    if (ret == NULL)
4099
19
  return(NULL);
4100
125k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
125k
    ret->type = XPATH_STRING;
4102
125k
    if (val == NULL)
4103
2
        val = BAD_CAST "";
4104
125k
    ret->stringval = xmlStrdup(val);
4105
125k
    if (ret->stringval == NULL) {
4106
24
        xmlFree(ret);
4107
24
        return(NULL);
4108
24
    }
4109
125k
    return(ret);
4110
125k
}
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
9.96k
xmlXPathWrapString (xmlChar *val) {
4122
9.96k
    xmlXPathObjectPtr ret;
4123
4124
9.96k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
9.96k
    if (ret == NULL) {
4126
16
        xmlFree(val);
4127
16
  return(NULL);
4128
16
    }
4129
9.94k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
9.94k
    ret->type = XPATH_STRING;
4131
9.94k
    ret->stringval = val;
4132
9.94k
    return(ret);
4133
9.96k
}
4134
4135
/**
4136
 * Create a new xmlXPathObject of type string and of value `val`
4137
 *
4138
 * @param val  the char * value
4139
 * @returns the newly created object.
4140
 */
4141
xmlXPathObject *
4142
0
xmlXPathNewCString(const char *val) {
4143
0
    return(xmlXPathNewString(BAD_CAST val));
4144
0
}
4145
4146
/**
4147
 * Wraps a string into an XPath object.
4148
 *
4149
 * @param val  the char * value
4150
 * @returns the newly created object.
4151
 */
4152
xmlXPathObject *
4153
0
xmlXPathWrapCString (char * val) {
4154
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4155
0
}
4156
4157
/**
4158
 * Wraps the `val` data into an XPath object.
4159
 *
4160
 * @param val  the user data
4161
 * @returns the newly created object.
4162
 */
4163
xmlXPathObject *
4164
0
xmlXPathWrapExternal (void *val) {
4165
0
    xmlXPathObjectPtr ret;
4166
4167
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4168
0
    if (ret == NULL)
4169
0
  return(NULL);
4170
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4171
0
    ret->type = XPATH_USERS;
4172
0
    ret->user = val;
4173
0
    return(ret);
4174
0
}
4175
4176
/**
4177
 * allocate a new copy of a given object
4178
 *
4179
 * @param val  the original object
4180
 * @returns the newly created object.
4181
 */
4182
xmlXPathObject *
4183
127k
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
127k
    xmlXPathObjectPtr ret;
4185
4186
127k
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
127k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
127k
    if (ret == NULL)
4191
38
  return(NULL);
4192
127k
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
127k
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
115k
  case XPATH_NUMBER:
4196
115k
      break;
4197
11.1k
  case XPATH_STRING:
4198
11.1k
      ret->stringval = xmlStrdup(val->stringval);
4199
11.1k
            if (ret->stringval == NULL) {
4200
4
                xmlFree(ret);
4201
4
                return(NULL);
4202
4
            }
4203
11.1k
      break;
4204
11.1k
  case XPATH_XSLT_TREE:
4205
0
  case XPATH_NODESET:
4206
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4207
0
            if (ret->nodesetval == NULL) {
4208
0
                xmlFree(ret);
4209
0
                return(NULL);
4210
0
            }
4211
      /* Do not deallocate the copied tree value */
4212
0
      ret->boolval = 0;
4213
0
      break;
4214
0
        case XPATH_USERS:
4215
0
      ret->user = val->user;
4216
0
      break;
4217
0
        default:
4218
0
            xmlFree(ret);
4219
0
            ret = NULL;
4220
0
      break;
4221
127k
    }
4222
127k
    return(ret);
4223
127k
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
3.22M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
3.22M
    if (obj == NULL) return;
4233
3.22M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
1.99M
        if (obj->nodesetval != NULL)
4235
1.99M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
1.99M
    } else if (obj->type == XPATH_STRING) {
4237
146k
  if (obj->stringval != NULL)
4238
146k
      xmlFree(obj->stringval);
4239
146k
    }
4240
3.22M
    xmlFree(obj);
4241
3.22M
}
4242
4243
static void
4244
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4245
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4246
0
}
4247
4248
/**
4249
 * Depending on the state of the cache this frees the given
4250
 * XPath object or stores it in the cache.
4251
 *
4252
 * @param ctxt  XPath context
4253
 * @param obj  the xmlXPathObject to free or to cache
4254
 */
4255
static void
4256
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4257
3.00M
{
4258
3.00M
    if (obj == NULL)
4259
14
  return;
4260
3.00M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
3.00M
   xmlXPathFreeObject(obj);
4262
3.00M
    } else {
4263
0
  xmlXPathContextCachePtr cache =
4264
0
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
0
  switch (obj->type) {
4267
0
      case XPATH_NODESET:
4268
0
      case XPATH_XSLT_TREE:
4269
0
    if (obj->nodesetval != NULL) {
4270
0
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
0
      (cache->numNodeset < cache->maxNodeset)) {
4272
0
                        obj->stringval = (void *) cache->nodesetObjs;
4273
0
                        cache->nodesetObjs = obj;
4274
0
                        cache->numNodeset += 1;
4275
0
      goto obj_cached;
4276
0
        } else {
4277
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
0
      obj->nodesetval = NULL;
4279
0
        }
4280
0
    }
4281
0
    break;
4282
0
      case XPATH_STRING:
4283
0
    if (obj->stringval != NULL)
4284
0
        xmlFree(obj->stringval);
4285
0
                obj->stringval = NULL;
4286
0
    break;
4287
0
      case XPATH_BOOLEAN:
4288
0
      case XPATH_NUMBER:
4289
0
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
0
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
0
        if (cache->numMisc >= cache->maxMisc)
4298
0
      goto free_obj;
4299
0
        obj->stringval = (void *) cache->miscObjs;
4300
0
        cache->miscObjs = obj;
4301
0
        cache->numMisc += 1;
4302
4303
0
obj_cached:
4304
0
        obj->boolval = 0;
4305
0
  if (obj->nodesetval != NULL) {
4306
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
4307
4308
      /*
4309
      * Due to those nasty ns-nodes, we need to traverse
4310
      * the list and free the ns-nodes.
4311
      */
4312
0
      if (tmpset->nodeNr > 0) {
4313
0
    int i;
4314
0
    xmlNodePtr node;
4315
4316
0
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
0
        node = tmpset->nodeTab[i];
4318
0
        if ((node != NULL) &&
4319
0
      (node->type == XML_NAMESPACE_DECL))
4320
0
        {
4321
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
0
        }
4323
0
    }
4324
0
      }
4325
0
      tmpset->nodeNr = 0;
4326
0
        }
4327
4328
0
  return;
4329
4330
0
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
0
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
0
  xmlFree(obj);
4337
0
    }
4338
3.00M
}
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
6.70k
xmlXPathCastBooleanToString (int val) {
4355
6.70k
    xmlChar *ret;
4356
6.70k
    if (val)
4357
1.51k
  ret = xmlStrdup((const xmlChar *) "true");
4358
5.19k
    else
4359
5.19k
  ret = xmlStrdup((const xmlChar *) "false");
4360
6.70k
    return(ret);
4361
6.70k
}
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
4.89k
xmlXPathCastNumberToString (double val) {
4371
4.89k
    xmlChar *ret;
4372
4.89k
    switch (xmlXPathIsInf(val)) {
4373
306
    case 1:
4374
306
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
306
  break;
4376
321
    case -1:
4377
321
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
321
  break;
4379
4.26k
    default:
4380
4.26k
  if (xmlXPathIsNaN(val)) {
4381
455
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
3.81k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
96
      ret = xmlStrdup((const xmlChar *) "0");
4385
3.71k
  } else {
4386
      /* could be improved */
4387
3.71k
      char buf[100];
4388
3.71k
      xmlXPathFormatNumber(val, buf, 99);
4389
3.71k
      buf[99] = 0;
4390
3.71k
      ret = xmlStrdup((const xmlChar *) buf);
4391
3.71k
  }
4392
4.89k
    }
4393
4.89k
    return(ret);
4394
4.89k
}
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
279k
xmlXPathCastNodeToString (xmlNode *node) {
4404
279k
    return(xmlNodeGetContent(node));
4405
279k
}
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
430k
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
430k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
292k
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
137k
    if (ns->nodeNr > 1)
4419
28.6k
  xmlXPathNodeSetSort(ns);
4420
137k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
430k
}
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
20.3k
xmlXPathCastToString(xmlXPathObject *val) {
4432
20.3k
    xmlChar *ret = NULL;
4433
4434
20.3k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
20.3k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
8.23k
        case XPATH_NODESET:
4441
8.23k
        case XPATH_XSLT_TREE:
4442
8.23k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
8.23k
      break;
4444
494
  case XPATH_STRING:
4445
494
      return(xmlStrdup(val->stringval));
4446
6.70k
        case XPATH_BOOLEAN:
4447
6.70k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
6.70k
      break;
4449
4.89k
  case XPATH_NUMBER: {
4450
4.89k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
4.89k
      break;
4452
8.23k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
20.3k
    }
4458
19.8k
    return(ret);
4459
20.3k
}
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
54.2k
xmlXPathCastBooleanToNumber(int val) {
4508
54.2k
    if (val)
4509
9.93k
  return(1.0);
4510
44.3k
    return(0.0);
4511
54.2k
}
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
561k
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
561k
    return(xmlXPathStringEvalNumber(val));
4522
561k
}
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
16.9k
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
16.9k
    xmlChar *strval;
4534
16.9k
    double ret;
4535
4536
16.9k
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
16.9k
    strval = xmlXPathCastNodeToString(node);
4539
16.9k
    if (strval == NULL) {
4540
14
        xmlXPathPErrMemory(ctxt);
4541
14
  return(xmlXPathNAN);
4542
14
    }
4543
16.9k
    ret = xmlXPathCastStringToNumber(strval);
4544
16.9k
    xmlFree(strval);
4545
4546
16.9k
    return(ret);
4547
16.9k
}
4548
4549
/**
4550
 * Converts a node to its number value
4551
 *
4552
 * @param node  a node
4553
 * @returns the number value
4554
 */
4555
double
4556
0
xmlXPathCastNodeToNumber (xmlNode *node) {
4557
0
    return(xmlXPathNodeToNumberInternal(NULL, node));
4558
0
}
4559
4560
/**
4561
 * Converts a node-set to its number value
4562
 *
4563
 * @param ns  a node-set
4564
 * @returns the number value
4565
 */
4566
double
4567
0
xmlXPathCastNodeSetToNumber (xmlNodeSet *ns) {
4568
0
    xmlChar *str;
4569
0
    double ret;
4570
4571
0
    if (ns == NULL)
4572
0
  return(xmlXPathNAN);
4573
0
    str = xmlXPathCastNodeSetToString(ns);
4574
0
    ret = xmlXPathCastStringToNumber(str);
4575
0
    xmlFree(str);
4576
0
    return(ret);
4577
0
}
4578
4579
/**
4580
 * Converts an XPath object to its number value
4581
 *
4582
 * @param val  an XPath object
4583
 * @returns the number value
4584
 */
4585
double
4586
0
xmlXPathCastToNumber(xmlXPathObject *val) {
4587
0
    return(xmlXPathCastToNumberInternal(NULL, val));
4588
0
}
4589
4590
/**
4591
 * Converts an existing object to its number() equivalent
4592
 *
4593
 * @param val  an XPath object
4594
 * @returns the new object, the old one is freed (or the operation
4595
 *         is done directly on `val`)
4596
 */
4597
xmlXPathObject *
4598
0
xmlXPathConvertNumber(xmlXPathObject *val) {
4599
0
    xmlXPathObjectPtr ret;
4600
4601
0
    if (val == NULL)
4602
0
  return(xmlXPathNewFloat(0.0));
4603
0
    if (val->type == XPATH_NUMBER)
4604
0
  return(val);
4605
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4606
0
    xmlXPathFreeObject(val);
4607
0
    return(ret);
4608
0
}
4609
4610
/**
4611
 * Converts a number to its boolean value
4612
 *
4613
 * @param val  a number
4614
 * @returns the boolean value
4615
 */
4616
int
4617
60.5k
xmlXPathCastNumberToBoolean (double val) {
4618
60.5k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
54.6k
   return(0);
4620
5.89k
     return(1);
4621
60.5k
}
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
64
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
64
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
21
  return(0);
4633
43
    return(1);
4634
64
}
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
19.6k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
19.6k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
14.7k
  return(0);
4646
4.93k
    return(1);
4647
19.6k
}
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
21.1k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
21.1k
    int ret = 0;
4658
4659
21.1k
    if (val == NULL)
4660
0
  return(0);
4661
21.1k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
19.6k
    case XPATH_NODESET:
4666
19.6k
    case XPATH_XSLT_TREE:
4667
19.6k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
19.6k
  break;
4669
64
    case XPATH_STRING:
4670
64
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
64
  break;
4672
1.45k
    case XPATH_NUMBER:
4673
1.45k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
1.45k
  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
21.1k
    }
4683
21.1k
    return(ret);
4684
21.1k
}
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
6.15k
xmlXPathNewContext(xmlDoc *doc) {
4721
6.15k
    xmlXPathContextPtr ret;
4722
4723
6.15k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
6.15k
    if (ret == NULL)
4725
30
  return(NULL);
4726
6.12k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
6.12k
    ret->doc = doc;
4728
6.12k
    ret->node = NULL;
4729
4730
6.12k
    ret->varHash = NULL;
4731
4732
6.12k
    ret->nb_types = 0;
4733
6.12k
    ret->max_types = 0;
4734
6.12k
    ret->types = NULL;
4735
4736
6.12k
    ret->nb_axis = 0;
4737
6.12k
    ret->max_axis = 0;
4738
6.12k
    ret->axis = NULL;
4739
4740
6.12k
    ret->nsHash = NULL;
4741
6.12k
    ret->user = NULL;
4742
4743
6.12k
    ret->contextSize = -1;
4744
6.12k
    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
6.12k
    return(ret);
4754
6.15k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
6.12k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
6.12k
    if (ctxt == NULL) return;
4764
4765
6.12k
    if (ctxt->cache != NULL)
4766
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
6.12k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
6.12k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
6.12k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
6.12k
    xmlResetError(&ctxt->lastError);
4771
6.12k
    xmlFree(ctxt);
4772
6.12k
}
4773
4774
/**
4775
 * Register a callback function that will be called on errors and
4776
 * warnings. If handler is NULL, the error handler will be deactivated.
4777
 *
4778
 * @since 2.13.0
4779
 * @param ctxt  the XPath context
4780
 * @param handler  error handler
4781
 * @param data  user data which will be passed to the handler
4782
 */
4783
void
4784
xmlXPathSetErrorHandler(xmlXPathContext *ctxt,
4785
6.12k
                        xmlStructuredErrorFunc handler, void *data) {
4786
6.12k
    if (ctxt == NULL)
4787
0
        return;
4788
4789
6.12k
    ctxt->error = handler;
4790
6.12k
    ctxt->userData = data;
4791
6.12k
}
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
10.6k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
10.6k
    xmlXPathParserContextPtr ret;
4809
4810
10.6k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
10.6k
    if (ret == NULL) {
4812
23
        xmlXPathErrMemory(ctxt);
4813
23
  return(NULL);
4814
23
    }
4815
10.5k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
10.5k
    ret->cur = ret->base = str;
4817
10.5k
    ret->context = ctxt;
4818
4819
10.5k
    ret->comp = xmlXPathNewCompExpr();
4820
10.5k
    if (ret->comp == NULL) {
4821
55
        xmlXPathErrMemory(ctxt);
4822
55
  xmlFree(ret->valueTab);
4823
55
  xmlFree(ret);
4824
55
  return(NULL);
4825
55
    }
4826
10.5k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
10.5k
    return(ret);
4832
10.5k
}
4833
4834
/**
4835
 * Create a new xmlXPathParserContext when processing a compiled expression
4836
 *
4837
 * @param comp  the XPath compiled expression
4838
 * @param ctxt  the XPath context
4839
 * @returns the xmlXPathParserContext just allocated.
4840
 */
4841
static xmlXPathParserContextPtr
4842
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
0
    xmlXPathParserContextPtr ret;
4844
4845
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
0
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
0
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
0
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
0
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
0
    ret->valueNr = 0;
4865
0
    ret->value = NULL;
4866
4867
0
    ret->context = ctxt;
4868
0
    ret->comp = comp;
4869
4870
0
    return(ret);
4871
0
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
10.5k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
10.5k
    int i;
4881
4882
10.5k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
10.5k
    if (ctxt->valueTab != NULL) {
4886
17.6k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
7.17k
            if (ctxt->context)
4888
7.17k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
7.17k
        }
4892
10.5k
        xmlFree(ctxt->valueTab);
4893
10.5k
    }
4894
10.5k
    if (ctxt->comp != NULL) {
4895
#ifdef XPATH_STREAMING
4896
  if (ctxt->comp->stream != NULL) {
4897
      xmlFreePatternList(ctxt->comp->stream);
4898
      ctxt->comp->stream = NULL;
4899
  }
4900
#endif
4901
10.5k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
10.5k
    }
4903
10.5k
    xmlFree(ctxt);
4904
10.5k
}
4905
4906
/************************************************************************
4907
 *                  *
4908
 *    The implicit core function library      *
4909
 *                  *
4910
 ************************************************************************/
4911
4912
/**
4913
 * Function computing the beginning of the string value of the node,
4914
 * used to speed up comparisons
4915
 *
4916
 * @param node  a node pointer
4917
 * @returns an int usable as a hash
4918
 */
4919
static unsigned int
4920
130k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
130k
    int len = 2;
4922
130k
    const xmlChar * string = NULL;
4923
130k
    xmlNodePtr tmp = NULL;
4924
130k
    unsigned int ret = 0;
4925
4926
130k
    if (node == NULL)
4927
0
  return(0);
4928
4929
130k
    if (node->type == XML_DOCUMENT_NODE) {
4930
18.8k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
18.8k
  if (tmp == NULL)
4932
0
      node = node->children;
4933
18.8k
  else
4934
18.8k
      node = tmp;
4935
4936
18.8k
  if (node == NULL)
4937
0
      return(0);
4938
18.8k
    }
4939
4940
130k
    switch (node->type) {
4941
606
  case XML_COMMENT_NODE:
4942
3.88k
  case XML_PI_NODE:
4943
4.14k
  case XML_CDATA_SECTION_NODE:
4944
18.7k
  case XML_TEXT_NODE:
4945
18.7k
      string = node->content;
4946
18.7k
      if (string == NULL)
4947
3.27k
    return(0);
4948
15.5k
      if (string[0] == 0)
4949
186
    return(0);
4950
15.3k
      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
1.69k
  case XML_ATTRIBUTE_NODE:
4959
1.69k
      tmp = ((xmlAttrPtr) node)->children;
4960
1.69k
      break;
4961
109k
  case XML_ELEMENT_NODE:
4962
109k
      tmp = node->children;
4963
109k
      break;
4964
0
  default:
4965
0
      return(0);
4966
130k
    }
4967
550k
    while (tmp != NULL) {
4968
506k
  switch (tmp->type) {
4969
8.63k
      case XML_CDATA_SECTION_NODE:
4970
106k
      case XML_TEXT_NODE:
4971
106k
    string = tmp->content;
4972
106k
    break;
4973
400k
      default:
4974
400k
                string = NULL;
4975
400k
    break;
4976
506k
  }
4977
506k
  if ((string != NULL) && (string[0] != 0)) {
4978
106k
      if (len == 1) {
4979
35.3k
    return(ret + (string[0] << 8));
4980
35.3k
      }
4981
70.9k
      if (string[1] == 0) {
4982
38.2k
    len = 1;
4983
38.2k
    ret = string[0];
4984
38.2k
      } else {
4985
32.6k
    return(string[0] + (string[1] << 8));
4986
32.6k
      }
4987
70.9k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
438k
        if ((tmp->children != NULL) &&
4992
256k
            (tmp->type != XML_DTD_NODE) &&
4993
256k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
256k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
256k
            tmp = tmp->children;
4996
256k
            continue;
4997
256k
  }
4998
182k
  if (tmp == node)
4999
0
      break;
5000
5001
182k
  if (tmp->next != NULL) {
5002
177k
      tmp = tmp->next;
5003
177k
      continue;
5004
177k
  }
5005
5006
12.0k
  do {
5007
12.0k
      tmp = tmp->parent;
5008
12.0k
      if (tmp == NULL)
5009
0
    break;
5010
12.0k
      if (tmp == node) {
5011
3.44k
    tmp = NULL;
5012
3.44k
    break;
5013
3.44k
      }
5014
8.59k
      if (tmp->next != NULL) {
5015
1.60k
    tmp = tmp->next;
5016
1.60k
    break;
5017
1.60k
      }
5018
8.59k
  } while (tmp != NULL);
5019
5.04k
    }
5020
43.4k
    return(ret);
5021
111k
}
5022
5023
/**
5024
 * Function computing the beginning of the string value of the node,
5025
 * used to speed up comparisons
5026
 *
5027
 * @param string  a string
5028
 * @returns an int usable as a hash
5029
 */
5030
static unsigned int
5031
1.95k
xmlXPathStringHash(const xmlChar * string) {
5032
1.95k
    if (string == NULL)
5033
0
  return(0);
5034
1.95k
    if (string[0] == 0)
5035
99
  return(0);
5036
1.85k
    return(string[0] + (string[1] << 8));
5037
1.95k
}
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
51.8k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
51.8k
    int i, ret = 0;
5063
51.8k
    xmlNodeSetPtr ns;
5064
51.8k
    xmlChar *str2;
5065
5066
51.8k
    if ((f == NULL) || (arg == NULL) ||
5067
51.8k
  ((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
51.8k
    ns = arg->nodesetval;
5073
51.8k
    if (ns != NULL) {
5074
102k
  for (i = 0;i < ns->nodeNr;i++) {
5075
51.7k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
51.7k
       if (str2 != NULL) {
5077
51.7k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
51.7k
     xmlFree(str2);
5079
51.7k
     xmlXPathNumberFunction(ctxt, 1);
5080
51.7k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
51.7k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
51.7k
     if (ret)
5083
802
         break;
5084
51.7k
       } else {
5085
6
                 xmlXPathPErrMemory(ctxt);
5086
6
             }
5087
51.7k
  }
5088
51.8k
    }
5089
51.8k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
51.8k
    xmlXPathReleaseObject(ctxt->context, f);
5091
51.8k
    return(ret);
5092
51.8k
}
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
987
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
987
    int i, ret = 0;
5117
987
    xmlNodeSetPtr ns;
5118
987
    xmlChar *str2;
5119
5120
987
    if ((s == NULL) || (arg == NULL) ||
5121
987
  ((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
987
    ns = arg->nodesetval;
5127
987
    if (ns != NULL) {
5128
1.68k
  for (i = 0;i < ns->nodeNr;i++) {
5129
700
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
700
       if (str2 != NULL) {
5131
699
     xmlXPathValuePush(ctxt,
5132
699
         xmlXPathCacheNewString(ctxt, str2));
5133
699
     xmlFree(str2);
5134
699
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
699
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
699
     if (ret)
5137
0
         break;
5138
699
       } else {
5139
1
                 xmlXPathPErrMemory(ctxt);
5140
1
             }
5141
700
  }
5142
987
    }
5143
987
    xmlXPathReleaseObject(ctxt->context, arg);
5144
987
    xmlXPathReleaseObject(ctxt->context, s);
5145
987
    return(ret);
5146
987
}
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
93.5k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
93.5k
    int i, j, init = 0;
5180
93.5k
    double val1;
5181
93.5k
    double *values2;
5182
93.5k
    int ret = 0;
5183
93.5k
    xmlNodeSetPtr ns1;
5184
93.5k
    xmlNodeSetPtr ns2;
5185
5186
93.5k
    if ((arg1 == NULL) ||
5187
93.5k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
93.5k
    if ((arg2 == NULL) ||
5192
93.5k
  ((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
93.5k
    ns1 = arg1->nodesetval;
5199
93.5k
    ns2 = arg2->nodesetval;
5200
5201
93.5k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
83.4k
  xmlXPathFreeObject(arg1);
5203
83.4k
  xmlXPathFreeObject(arg2);
5204
83.4k
  return(0);
5205
83.4k
    }
5206
10.0k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
6.43k
  xmlXPathFreeObject(arg1);
5208
6.43k
  xmlXPathFreeObject(arg2);
5209
6.43k
  return(0);
5210
6.43k
    }
5211
5212
3.64k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
3.64k
    if (values2 == NULL) {
5214
4
        xmlXPathPErrMemory(ctxt);
5215
4
  xmlXPathFreeObject(arg1);
5216
4
  xmlXPathFreeObject(arg2);
5217
4
  return(0);
5218
4
    }
5219
13.4k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
10.5k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
10.5k
  if (xmlXPathIsNaN(val1))
5222
8.71k
      continue;
5223
8.22k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
7.13k
      if (init == 0) {
5225
6.34k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
6.34k
                                                          ns2->nodeTab[j]);
5227
6.34k
      }
5228
7.13k
      if (xmlXPathIsNaN(values2[j]))
5229
5.32k
    continue;
5230
1.81k
      if (inf && strict)
5231
351
    ret = (val1 < values2[j]);
5232
1.46k
      else if (inf && !strict)
5233
287
    ret = (val1 <= values2[j]);
5234
1.17k
      else if (!inf && strict)
5235
970
    ret = (val1 > values2[j]);
5236
209
      else if (!inf && !strict)
5237
209
    ret = (val1 >= values2[j]);
5238
1.81k
      if (ret)
5239
776
    break;
5240
1.81k
  }
5241
1.86k
  if (ret)
5242
776
      break;
5243
1.09k
  init = 1;
5244
1.09k
    }
5245
3.63k
    xmlFree(values2);
5246
3.63k
    xmlXPathFreeObject(arg1);
5247
3.63k
    xmlXPathFreeObject(arg2);
5248
3.63k
    return(ret);
5249
3.64k
}
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
72.3k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
72.3k
    if ((val == NULL) || (arg == NULL) ||
5274
72.3k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
72.3k
    switch(val->type) {
5278
51.8k
        case XPATH_NUMBER:
5279
51.8k
      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
987
        case XPATH_STRING:
5284
987
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
19.4k
        case XPATH_BOOLEAN:
5286
19.4k
      xmlXPathValuePush(ctxt, arg);
5287
19.4k
      xmlXPathBooleanFunction(ctxt, 1);
5288
19.4k
      xmlXPathValuePush(ctxt, val);
5289
19.4k
      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
72.3k
    }
5295
0
    return(0);
5296
72.3k
}
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
5.95k
{
5315
5.95k
    int i;
5316
5.95k
    xmlNodeSetPtr ns;
5317
5.95k
    xmlChar *str2;
5318
5.95k
    unsigned int hash;
5319
5320
5.95k
    if ((str == NULL) || (arg == NULL) ||
5321
5.95k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
5.95k
    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
5.95k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
4.00k
        return (0);
5330
1.95k
    hash = xmlXPathStringHash(str);
5331
50.3k
    for (i = 0; i < ns->nodeNr; i++) {
5332
49.5k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
2.03k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
2.03k
            if (str2 == NULL) {
5335
1
                xmlXPathPErrMemory(ctxt);
5336
1
                return(0);
5337
1
            }
5338
2.03k
            if (xmlStrEqual(str, str2)) {
5339
1.57k
                xmlFree(str2);
5340
1.57k
    if (neq)
5341
1.08k
        continue;
5342
488
                return (1);
5343
1.57k
            } else if (neq) {
5344
248
    xmlFree(str2);
5345
248
    return (1);
5346
248
      }
5347
218
            xmlFree(str2);
5348
47.5k
        } else if (neq)
5349
371
      return (1);
5350
49.5k
    }
5351
847
    return (0);
5352
1.95k
}
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
44.4k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
44.4k
  int i, ret=0;
5372
44.4k
  xmlNodeSetPtr ns;
5373
44.4k
  xmlChar *str2;
5374
44.4k
  xmlXPathObjectPtr val;
5375
44.4k
  double v;
5376
5377
44.4k
    if ((arg == NULL) ||
5378
44.4k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
44.4k
    ns = arg->nodesetval;
5382
44.4k
    if (ns != NULL) {
5383
110k
  for (i=0;i<ns->nodeNr;i++) {
5384
66.9k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
66.9k
      if (str2 != NULL) {
5386
66.9k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
66.9k
    xmlFree(str2);
5388
66.9k
    xmlXPathNumberFunction(ctxt, 1);
5389
66.9k
                CHECK_ERROR0;
5390
66.9k
    val = xmlXPathValuePop(ctxt);
5391
66.9k
    v = val->floatval;
5392
66.9k
    xmlXPathReleaseObject(ctxt->context, val);
5393
66.9k
    if (!xmlXPathIsNaN(v)) {
5394
5.32k
        if ((!neq) && (v==f)) {
5395
527
      ret = 1;
5396
527
      break;
5397
4.79k
        } else if ((neq) && (v!=f)) {
5398
393
      ret = 1;
5399
393
      break;
5400
393
        }
5401
61.6k
    } else { /* NaN is unequal to any value */
5402
61.6k
        if (neq)
5403
2.18k
      ret = 1;
5404
61.6k
    }
5405
66.9k
      } else {
5406
10
                xmlXPathPErrMemory(ctxt);
5407
10
            }
5408
66.9k
  }
5409
44.4k
    }
5410
5411
44.4k
    return(ret);
5412
44.4k
}
5413
5414
5415
/**
5416
 * Implement the equal / not equal operation on XPath nodesets:
5417
 * `arg1` == `arg2`  or  `arg1` != `arg2`
5418
 * If both objects to be compared are node-sets, then the comparison
5419
 * will be true if and only if there is a node in the first node-set and
5420
 * a node in the second node-set such that the result of performing the
5421
 * comparison on the string-values of the two nodes is true.
5422
 *
5423
 * (needless to say, this is a costly operation)
5424
 *
5425
 * @param ctxt  XPath parser context
5426
 * @param arg1  first nodeset object argument
5427
 * @param arg2  second nodeset object argument
5428
 * @param neq  flag to show whether to test '=' (0) or '!=' (1)
5429
 * @returns 0 or 1 depending on the results of the test.
5430
 */
5431
static int
5432
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5433
51.0k
                      xmlXPathObjectPtr arg2, int neq) {
5434
51.0k
    int i, j;
5435
51.0k
    unsigned int *hashs1;
5436
51.0k
    unsigned int *hashs2;
5437
51.0k
    xmlChar **values1;
5438
51.0k
    xmlChar **values2;
5439
51.0k
    int ret = 0;
5440
51.0k
    xmlNodeSetPtr ns1;
5441
51.0k
    xmlNodeSetPtr ns2;
5442
5443
51.0k
    if ((arg1 == NULL) ||
5444
51.0k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
51.0k
    if ((arg2 == NULL) ||
5447
51.0k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
51.0k
    ns1 = arg1->nodesetval;
5451
51.0k
    ns2 = arg2->nodesetval;
5452
5453
51.0k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
21.1k
  return(0);
5455
29.9k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
881
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
29.1k
    if (neq == 0)
5462
58.9k
  for (i = 0;i < ns1->nodeNr;i++)
5463
87.0k
      for (j = 0;j < ns2->nodeNr;j++)
5464
56.4k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
1.39k
        return(1);
5466
5467
27.7k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
27.7k
    if (values1 == NULL) {
5469
3
        xmlXPathPErrMemory(ctxt);
5470
3
  return(0);
5471
3
    }
5472
27.7k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
27.7k
    if (hashs1 == NULL) {
5474
1
        xmlXPathPErrMemory(ctxt);
5475
1
  xmlFree(values1);
5476
1
  return(0);
5477
1
    }
5478
27.7k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
27.7k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
27.7k
    if (values2 == NULL) {
5481
2
        xmlXPathPErrMemory(ctxt);
5482
2
  xmlFree(hashs1);
5483
2
  xmlFree(values1);
5484
2
  return(0);
5485
2
    }
5486
27.7k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
27.7k
    if (hashs2 == NULL) {
5488
1
        xmlXPathPErrMemory(ctxt);
5489
1
  xmlFree(hashs1);
5490
1
  xmlFree(values1);
5491
1
  xmlFree(values2);
5492
1
  return(0);
5493
1
    }
5494
27.7k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
54.9k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
29.5k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
81.6k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
54.4k
      if (i == 0)
5499
51.2k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
54.4k
      if (hashs1[i] != hashs2[j]) {
5501
51.8k
    if (neq) {
5502
778
        ret = 1;
5503
778
        break;
5504
778
    }
5505
51.8k
      }
5506
2.55k
      else {
5507
2.55k
    if (values1[i] == NULL) {
5508
1.85k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
1.85k
                    if (values1[i] == NULL)
5510
8
                        xmlXPathPErrMemory(ctxt);
5511
1.85k
                }
5512
2.55k
    if (values2[j] == NULL) {
5513
1.83k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
1.83k
                    if (values2[j] == NULL)
5515
5
                        xmlXPathPErrMemory(ctxt);
5516
1.83k
                }
5517
2.55k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
2.55k
    if (ret)
5519
1.57k
        break;
5520
2.55k
      }
5521
54.4k
  }
5522
29.5k
  if (ret)
5523
2.34k
      break;
5524
29.5k
    }
5525
59.1k
    for (i = 0;i < ns1->nodeNr;i++)
5526
31.4k
  if (values1[i] != NULL)
5527
1.84k
      xmlFree(values1[i]);
5528
79.0k
    for (j = 0;j < ns2->nodeNr;j++)
5529
51.3k
  if (values2[j] != NULL)
5530
1.83k
      xmlFree(values2[j]);
5531
27.7k
    xmlFree(values1);
5532
27.7k
    xmlFree(values2);
5533
27.7k
    xmlFree(hashs1);
5534
27.7k
    xmlFree(hashs2);
5535
27.7k
    return(ret);
5536
27.7k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
156k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
156k
    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
156k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
122k
        case XPATH_BOOLEAN:
5550
122k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
82.6k
    case XPATH_BOOLEAN:
5554
82.6k
        ret = (arg1->boolval == arg2->boolval);
5555
82.6k
        break;
5556
35.0k
    case XPATH_NUMBER:
5557
35.0k
        ret = (arg1->boolval ==
5558
35.0k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
35.0k
        break;
5560
4.91k
    case XPATH_STRING:
5561
4.91k
        if ((arg2->stringval == NULL) ||
5562
4.91k
      (arg2->stringval[0] == 0)) ret = 0;
5563
1.59k
        else
5564
1.59k
      ret = 1;
5565
4.91k
        ret = (arg1->boolval == ret);
5566
4.91k
        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
122k
      }
5574
122k
      break;
5575
122k
        case XPATH_NUMBER:
5576
32.6k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
24.1k
    case XPATH_BOOLEAN:
5580
24.1k
        ret = (arg2->boolval==
5581
24.1k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
24.1k
        break;
5583
700
    case XPATH_STRING:
5584
700
        xmlXPathValuePush(ctxt, arg2);
5585
700
        xmlXPathNumberFunction(ctxt, 1);
5586
700
        arg2 = xmlXPathValuePop(ctxt);
5587
700
                    if (ctxt->error)
5588
1
                        break;
5589
                    /* Falls through. */
5590
8.52k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
8.52k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
6.00k
          xmlXPathIsNaN(arg2->floatval)) {
5594
6.00k
            ret = 0;
5595
6.00k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
484
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
216
          ret = 1;
5598
268
      else
5599
268
          ret = 0;
5600
2.03k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
570
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
78
          ret = 1;
5603
492
      else
5604
492
          ret = 0;
5605
1.46k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
261
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
261
      else
5609
261
          ret = 0;
5610
1.20k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
525
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
525
      else
5614
525
          ret = 0;
5615
683
        } else {
5616
683
            ret = (arg1->floatval == arg2->floatval);
5617
683
        }
5618
8.52k
        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
32.6k
      }
5626
32.6k
      break;
5627
32.6k
        case XPATH_STRING:
5628
1.53k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
302
    case XPATH_BOOLEAN:
5632
302
        if ((arg1->stringval == NULL) ||
5633
302
      (arg1->stringval[0] == 0)) ret = 0;
5634
237
        else
5635
237
      ret = 1;
5636
302
        ret = (arg2->boolval == ret);
5637
302
        break;
5638
281
    case XPATH_STRING:
5639
281
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
281
        break;
5641
948
    case XPATH_NUMBER:
5642
948
        xmlXPathValuePush(ctxt, arg1);
5643
948
        xmlXPathNumberFunction(ctxt, 1);
5644
948
        arg1 = xmlXPathValuePop(ctxt);
5645
948
                    if (ctxt->error)
5646
1
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
947
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
923
          xmlXPathIsNaN(arg2->floatval)) {
5650
923
            ret = 0;
5651
923
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
4
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
3
          ret = 1;
5654
1
      else
5655
1
          ret = 0;
5656
20
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
2
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
1
          ret = 1;
5659
1
      else
5660
1
          ret = 0;
5661
18
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
10
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
10
      else
5665
10
          ret = 0;
5666
10
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
5
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
5
      else
5670
5
          ret = 0;
5671
5
        } else {
5672
3
            ret = (arg1->floatval == arg2->floatval);
5673
3
        }
5674
947
        break;
5675
0
    case XPATH_USERS:
5676
        /* TODO */
5677
0
        break;
5678
0
    case XPATH_NODESET:
5679
0
    case XPATH_XSLT_TREE:
5680
0
        break;
5681
1.53k
      }
5682
1.53k
      break;
5683
1.53k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
156k
    }
5690
156k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
156k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
156k
    return(ret);
5693
156k
}
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
342k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
342k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
342k
    int ret = 0;
5705
5706
342k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
342k
    arg2 = xmlXPathValuePop(ctxt);
5708
342k
    arg1 = xmlXPathValuePop(ctxt);
5709
342k
    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
342k
    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
342k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
186k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
186k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
106k
    argtmp = arg2;
5732
106k
    arg2 = arg1;
5733
106k
    arg1 = argtmp;
5734
106k
  }
5735
186k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
49.9k
      case XPATH_NODESET:
5739
49.9k
      case XPATH_XSLT_TREE:
5740
49.9k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
49.9k
    break;
5742
87.9k
      case XPATH_BOOLEAN:
5743
87.9k
    if ((arg1->nodesetval == NULL) ||
5744
87.9k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
30.4k
    else
5746
30.4k
        ret = 1;
5747
87.9k
    ret = (ret == arg2->boolval);
5748
87.9k
    break;
5749
43.5k
      case XPATH_NUMBER:
5750
43.5k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
43.5k
    break;
5752
5.00k
      case XPATH_STRING:
5753
5.00k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
5.00k
                                                 arg2->stringval, 0);
5755
5.00k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
186k
  }
5760
186k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
186k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
186k
  return(ret);
5763
186k
    }
5764
5765
155k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
342k
}
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
5.69k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
5.69k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
5.69k
    int ret = 0;
5778
5779
5.69k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
5.69k
    arg2 = xmlXPathValuePop(ctxt);
5781
5.69k
    arg1 = xmlXPathValuePop(ctxt);
5782
5.69k
    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
5.69k
    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
5.69k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
4.90k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
4.90k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
2.43k
    argtmp = arg2;
5805
2.43k
    arg2 = arg1;
5806
2.43k
    arg1 = argtmp;
5807
2.43k
  }
5808
4.90k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
1.15k
      case XPATH_NODESET:
5812
1.15k
      case XPATH_XSLT_TREE:
5813
1.15k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
1.15k
    break;
5815
1.87k
      case XPATH_BOOLEAN:
5816
1.87k
    if ((arg1->nodesetval == NULL) ||
5817
1.87k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
1.06k
    else
5819
1.06k
        ret = 1;
5820
1.87k
    ret = (ret != arg2->boolval);
5821
1.87k
    break;
5822
931
      case XPATH_NUMBER:
5823
931
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
931
    break;
5825
955
      case XPATH_STRING:
5826
955
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
955
                                                 arg2->stringval, 1);
5828
955
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
4.90k
  }
5833
4.90k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
4.90k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
4.90k
  return(ret);
5836
4.90k
    }
5837
5838
784
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
5.69k
}
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
255k
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
255k
    int ret = 0, arg1i = 0, arg2i = 0;
5866
255k
    xmlXPathObjectPtr arg1, arg2;
5867
5868
255k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
255k
    arg2 = xmlXPathValuePop(ctxt);
5870
255k
    arg1 = xmlXPathValuePop(ctxt);
5871
255k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
7
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
7
  else
5875
7
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
7
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
255k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
165k
      (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
165k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
142k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
93.5k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
93.5k
  } else {
5890
72.3k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
23.4k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
23.4k
                                arg1, arg2);
5893
48.8k
      } else {
5894
48.8k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
48.8k
                                arg2, arg1);
5896
48.8k
      }
5897
72.3k
  }
5898
165k
  return(ret);
5899
165k
    }
5900
5901
89.4k
    if (arg1->type != XPATH_NUMBER) {
5902
28.2k
  xmlXPathValuePush(ctxt, arg1);
5903
28.2k
  xmlXPathNumberFunction(ctxt, 1);
5904
28.2k
  arg1 = xmlXPathValuePop(ctxt);
5905
28.2k
    }
5906
89.4k
    if (arg2->type != XPATH_NUMBER) {
5907
20.6k
  xmlXPathValuePush(ctxt, arg2);
5908
20.6k
  xmlXPathNumberFunction(ctxt, 1);
5909
20.6k
  arg2 = xmlXPathValuePop(ctxt);
5910
20.6k
    }
5911
89.4k
    if (ctxt->error)
5912
386
        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
89.0k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
56.3k
  ret=0;
5920
56.3k
    } else {
5921
32.7k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
32.7k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
32.7k
  if (inf && strict) {
5924
18.4k
      if ((arg1i == -1 && arg2i != -1) ||
5925
18.1k
    (arg2i == 1 && arg1i != 1)) {
5926
556
    ret = 1;
5927
17.8k
      } else if (arg1i == 0 && arg2i == 0) {
5928
16.1k
    ret = (arg1->floatval < arg2->floatval);
5929
16.1k
      } else {
5930
1.66k
    ret = 0;
5931
1.66k
      }
5932
18.4k
  }
5933
14.3k
  else if (inf && !strict) {
5934
6.67k
      if (arg1i == -1 || arg2i == 1) {
5935
423
    ret = 1;
5936
6.25k
      } else if (arg1i == 0 && arg2i == 0) {
5937
5.82k
    ret = (arg1->floatval <= arg2->floatval);
5938
5.82k
      } else {
5939
427
    ret = 0;
5940
427
      }
5941
6.67k
  }
5942
7.66k
  else if (!inf && strict) {
5943
5.74k
      if ((arg1i == 1 && arg2i != 1) ||
5944
3.53k
    (arg2i == -1 && arg1i != -1)) {
5945
2.64k
    ret = 1;
5946
3.10k
      } else if (arg1i == 0 && arg2i == 0) {
5947
2.20k
    ret = (arg1->floatval > arg2->floatval);
5948
2.20k
      } else {
5949
891
    ret = 0;
5950
891
      }
5951
5.74k
  }
5952
1.91k
  else if (!inf && !strict) {
5953
1.91k
      if (arg1i == 1 || arg2i == -1) {
5954
692
    ret = 1;
5955
1.22k
      } else if (arg1i == 0 && arg2i == 0) {
5956
724
    ret = (arg1->floatval >= arg2->floatval);
5957
724
      } else {
5958
501
    ret = 0;
5959
501
      }
5960
1.91k
  }
5961
32.7k
    }
5962
89.4k
error:
5963
89.4k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
89.4k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
89.4k
    return(ret);
5966
89.0k
}
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
105k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
105k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
105k
    CAST_TO_NUMBER;
5979
105k
    CHECK_TYPE(XPATH_NUMBER);
5980
105k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
105k
}
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
86.7k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
86.7k
    xmlXPathObjectPtr arg;
5993
86.7k
    double val;
5994
5995
86.7k
    arg = xmlXPathValuePop(ctxt);
5996
86.7k
    if (arg == NULL)
5997
86.7k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
86.7k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
86.7k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
86.7k
    CAST_TO_NUMBER;
6001
86.7k
    CHECK_TYPE(XPATH_NUMBER);
6002
86.7k
    ctxt->value->floatval += val;
6003
86.7k
}
6004
6005
/**
6006
 * Implement the subtraction operation on XPath objects:
6007
 * The numeric operators convert their operands to numbers as if
6008
 * by calling the number function.
6009
 *
6010
 * @param ctxt  the XPath Parser context
6011
 */
6012
void
6013
37.1k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
37.1k
    xmlXPathObjectPtr arg;
6015
37.1k
    double val;
6016
6017
37.1k
    arg = xmlXPathValuePop(ctxt);
6018
37.1k
    if (arg == NULL)
6019
37.1k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
37.1k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
37.1k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
37.1k
    CAST_TO_NUMBER;
6023
37.1k
    CHECK_TYPE(XPATH_NUMBER);
6024
37.1k
    ctxt->value->floatval -= val;
6025
37.1k
}
6026
6027
/**
6028
 * Implement the multiply operation on XPath objects:
6029
 * The numeric operators convert their operands to numbers as if
6030
 * by calling the number function.
6031
 *
6032
 * @param ctxt  the XPath Parser context
6033
 */
6034
void
6035
117k
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
117k
    xmlXPathObjectPtr arg;
6037
117k
    double val;
6038
6039
117k
    arg = xmlXPathValuePop(ctxt);
6040
117k
    if (arg == NULL)
6041
117k
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
117k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
117k
    xmlXPathReleaseObject(ctxt->context, arg);
6044
117k
    CAST_TO_NUMBER;
6045
117k
    CHECK_TYPE(XPATH_NUMBER);
6046
117k
    ctxt->value->floatval *= val;
6047
117k
}
6048
6049
/**
6050
 * Implement the div operation on XPath objects `arg1` / `arg2`.
6051
 * The numeric operators convert their operands to numbers as if
6052
 * by calling the number function.
6053
 *
6054
 * @param ctxt  the XPath Parser context
6055
 */
6056
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6057
void
6058
1.52k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
1.52k
    xmlXPathObjectPtr arg;
6060
1.52k
    double val;
6061
6062
1.52k
    arg = xmlXPathValuePop(ctxt);
6063
1.52k
    if (arg == NULL)
6064
1.52k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
1.52k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
1.52k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
1.52k
    CAST_TO_NUMBER;
6068
1.52k
    CHECK_TYPE(XPATH_NUMBER);
6069
1.51k
    ctxt->value->floatval /= val;
6070
1.51k
}
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
821
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
821
    xmlXPathObjectPtr arg;
6082
821
    double arg1, arg2;
6083
6084
821
    arg = xmlXPathValuePop(ctxt);
6085
821
    if (arg == NULL)
6086
821
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
821
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
821
    xmlXPathReleaseObject(ctxt->context, arg);
6089
821
    CAST_TO_NUMBER;
6090
821
    CHECK_TYPE(XPATH_NUMBER);
6091
819
    arg1 = ctxt->value->floatval;
6092
819
    if (arg2 == 0)
6093
31
  ctxt->value->floatval = xmlXPathNAN;
6094
788
    else {
6095
788
  ctxt->value->floatval = fmod(arg1, arg2);
6096
788
    }
6097
819
}
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
986
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
986
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
986
    if (cur == NULL)
6141
493
        return(ctxt->context->node);
6142
493
    return(NULL);
6143
986
}
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
541k
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
541k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
541k
    if (cur == NULL) {
6157
8.98k
  if (ctxt->context->node == NULL) return(NULL);
6158
8.98k
  switch (ctxt->context->node->type) {
6159
4.41k
            case XML_ELEMENT_NODE:
6160
7.16k
            case XML_TEXT_NODE:
6161
7.37k
            case XML_CDATA_SECTION_NODE:
6162
7.37k
            case XML_ENTITY_REF_NODE:
6163
7.37k
            case XML_ENTITY_NODE:
6164
7.88k
            case XML_PI_NODE:
6165
8.62k
            case XML_COMMENT_NODE:
6166
8.62k
            case XML_NOTATION_NODE:
6167
8.62k
            case XML_DTD_NODE:
6168
8.62k
    return(ctxt->context->node->children);
6169
347
            case XML_DOCUMENT_NODE:
6170
347
            case XML_DOCUMENT_TYPE_NODE:
6171
347
            case XML_DOCUMENT_FRAG_NODE:
6172
347
            case XML_HTML_DOCUMENT_NODE:
6173
347
    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
10
            case XML_ATTRIBUTE_NODE:
6178
10
      case XML_NAMESPACE_DECL:
6179
10
      case XML_XINCLUDE_START:
6180
10
      case XML_XINCLUDE_END:
6181
10
    return(NULL);
6182
8.98k
  }
6183
0
  return(NULL);
6184
8.98k
    }
6185
532k
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
532k
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
532k
    return(cur->next);
6189
532k
}
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
3.22M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
3.22M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
3.22M
    if (cur == NULL) {
6203
1.54M
  cur = ctxt->context->node;
6204
1.54M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
1.54M
  switch (cur->type) {
6209
1.19M
            case XML_ELEMENT_NODE:
6210
1.19M
      case XML_DOCUMENT_FRAG_NODE:
6211
1.19M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
1.19M
            case XML_ENTITY_NODE:
6213
1.19M
    cur = cur->children;
6214
1.19M
    if (cur != NULL) {
6215
713k
        if (cur->type == XML_ELEMENT_NODE)
6216
453k
      return(cur);
6217
267k
        do {
6218
267k
      cur = cur->next;
6219
267k
        } while ((cur != NULL) &&
6220
77.2k
      (cur->type != XML_ELEMENT_NODE));
6221
260k
        return(cur);
6222
713k
    }
6223
478k
    return(NULL);
6224
196k
            case XML_DOCUMENT_NODE:
6225
196k
            case XML_HTML_DOCUMENT_NODE:
6226
196k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
154k
      default:
6228
154k
    return(NULL);
6229
1.54M
  }
6230
0
  return(NULL);
6231
1.54M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
1.68M
    switch (cur->type) {
6236
1.68M
  case XML_ELEMENT_NODE:
6237
1.68M
  case XML_TEXT_NODE:
6238
1.68M
  case XML_ENTITY_REF_NODE:
6239
1.68M
  case XML_ENTITY_NODE:
6240
1.68M
  case XML_CDATA_SECTION_NODE:
6241
1.68M
  case XML_PI_NODE:
6242
1.68M
  case XML_COMMENT_NODE:
6243
1.68M
  case XML_XINCLUDE_END:
6244
1.68M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
1.68M
    }
6249
1.68M
    if (cur->next != NULL) {
6250
1.14M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
891k
      return(cur->next);
6252
253k
  cur = cur->next;
6253
346k
  do {
6254
346k
      cur = cur->next;
6255
346k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
253k
  return(cur);
6257
1.14M
    }
6258
541k
    return(NULL);
6259
1.68M
}
6260
6261
/**
6262
 * Traversal function for the "descendant" direction
6263
 * the descendant axis contains the descendants of the context node in document
6264
 * order; a descendant is a child or a child of a child and so on.
6265
 *
6266
 * @param ctxt  the XPath Parser context
6267
 * @param cur  the current node in the traversal
6268
 * @returns the next element following that axis
6269
 */
6270
xmlNode *
6271
5.09M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
5.09M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
5.09M
    if (cur == NULL) {
6274
98.2k
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
98.2k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
97.6k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
583
      return(NULL);
6279
6280
97.6k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
10.3k
      return(ctxt->context->doc->children);
6282
87.3k
        return(ctxt->context->node->children);
6283
97.6k
    }
6284
6285
4.99M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
4.99M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
1.72M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
1.72M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
1.72M
      if (cur->type != XML_DTD_NODE)
6297
1.72M
    return(cur);
6298
1.72M
  }
6299
1.72M
    }
6300
6301
3.27M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
3.27M
    while (cur->next != NULL) {
6304
2.56M
  cur = cur->next;
6305
2.56M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
2.56M
      (cur->type != XML_DTD_NODE))
6307
2.56M
      return(cur);
6308
2.56M
    }
6309
6310
1.77M
    do {
6311
1.77M
        cur = cur->parent;
6312
1.77M
  if (cur == NULL) break;
6313
1.77M
  if (cur == ctxt->context->node) return(NULL);
6314
1.66M
  if (cur->next != NULL) {
6315
600k
      cur = cur->next;
6316
600k
      return(cur);
6317
600k
  }
6318
1.66M
    } while (cur != NULL);
6319
0
    return(cur);
6320
706k
}
6321
6322
/**
6323
 * Traversal function for the "descendant-or-self" direction
6324
 * the descendant-or-self axis contains the context node and the descendants
6325
 * of the context node in document order; thus the context node is the first
6326
 * node on the axis, and the first child of the context node is the second node
6327
 * on the axis
6328
 *
6329
 * @param ctxt  the XPath Parser context
6330
 * @param cur  the current node in the traversal
6331
 * @returns the next element following that axis
6332
 */
6333
xmlNode *
6334
3.37M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
3.37M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
3.37M
    if (cur == NULL)
6337
61.9k
        return(ctxt->context->node);
6338
6339
3.31M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
3.31M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
3.31M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
1.17k
        return(NULL);
6344
6345
3.31M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
3.31M
}
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
725k
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
725k
    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
725k
    if (cur == NULL) {
6365
367k
  if (ctxt->context->node == NULL) return(NULL);
6366
367k
  switch (ctxt->context->node->type) {
6367
228k
            case XML_ELEMENT_NODE:
6368
335k
            case XML_TEXT_NODE:
6369
346k
            case XML_CDATA_SECTION_NODE:
6370
346k
            case XML_ENTITY_REF_NODE:
6371
346k
            case XML_ENTITY_NODE:
6372
355k
            case XML_PI_NODE:
6373
356k
            case XML_COMMENT_NODE:
6374
356k
            case XML_NOTATION_NODE:
6375
356k
            case XML_DTD_NODE:
6376
356k
      case XML_ELEMENT_DECL:
6377
356k
      case XML_ATTRIBUTE_DECL:
6378
356k
      case XML_XINCLUDE_START:
6379
356k
      case XML_XINCLUDE_END:
6380
356k
      case XML_ENTITY_DECL:
6381
356k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
356k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
347k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
347k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
347k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
356k
    return(ctxt->context->node->parent);
6389
1.20k
            case XML_ATTRIBUTE_NODE: {
6390
1.20k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
1.20k
    return(att->parent);
6393
356k
      }
6394
9.67k
            case XML_DOCUMENT_NODE:
6395
9.67k
            case XML_DOCUMENT_TYPE_NODE:
6396
9.67k
            case XML_DOCUMENT_FRAG_NODE:
6397
9.67k
            case XML_HTML_DOCUMENT_NODE:
6398
9.67k
                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
367k
  }
6408
367k
    }
6409
358k
    return(NULL);
6410
725k
}
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
98.0k
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
98.0k
    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
98.0k
    if (cur == NULL) {
6433
18.6k
  if (ctxt->context->node == NULL) return(NULL);
6434
18.6k
  switch (ctxt->context->node->type) {
6435
13.8k
            case XML_ELEMENT_NODE:
6436
16.4k
            case XML_TEXT_NODE:
6437
16.7k
            case XML_CDATA_SECTION_NODE:
6438
16.7k
            case XML_ENTITY_REF_NODE:
6439
16.7k
            case XML_ENTITY_NODE:
6440
17.7k
            case XML_PI_NODE:
6441
17.9k
            case XML_COMMENT_NODE:
6442
17.9k
      case XML_DTD_NODE:
6443
17.9k
      case XML_ELEMENT_DECL:
6444
17.9k
      case XML_ATTRIBUTE_DECL:
6445
17.9k
      case XML_ENTITY_DECL:
6446
17.9k
            case XML_NOTATION_NODE:
6447
17.9k
      case XML_XINCLUDE_START:
6448
17.9k
      case XML_XINCLUDE_END:
6449
17.9k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
17.9k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
16.6k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
16.6k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
16.6k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
17.9k
    return(ctxt->context->node->parent);
6457
3
            case XML_ATTRIBUTE_NODE: {
6458
3
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
3
    return(tmp->parent);
6461
17.9k
      }
6462
661
            case XML_DOCUMENT_NODE:
6463
661
            case XML_DOCUMENT_TYPE_NODE:
6464
661
            case XML_DOCUMENT_FRAG_NODE:
6465
661
            case XML_HTML_DOCUMENT_NODE:
6466
661
                return(NULL);
6467
0
      case XML_NAMESPACE_DECL: {
6468
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
0
    if ((ns->next != NULL) &&
6471
0
        (ns->next->type != XML_NAMESPACE_DECL))
6472
0
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
0
      }
6476
18.6k
  }
6477
0
  return(NULL);
6478
18.6k
    }
6479
79.4k
    if (cur == ctxt->context->doc->children)
6480
7.33k
  return((xmlNodePtr) ctxt->context->doc);
6481
72.0k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
21.8k
  return(NULL);
6483
50.1k
    switch (cur->type) {
6484
48.1k
  case XML_ELEMENT_NODE:
6485
49.5k
  case XML_TEXT_NODE:
6486
49.7k
  case XML_CDATA_SECTION_NODE:
6487
49.7k
  case XML_ENTITY_REF_NODE:
6488
49.7k
  case XML_ENTITY_NODE:
6489
50.1k
  case XML_PI_NODE:
6490
50.1k
  case XML_COMMENT_NODE:
6491
50.1k
  case XML_NOTATION_NODE:
6492
50.1k
  case XML_DTD_NODE:
6493
50.1k
        case XML_ELEMENT_DECL:
6494
50.1k
        case XML_ATTRIBUTE_DECL:
6495
50.1k
        case XML_ENTITY_DECL:
6496
50.1k
  case XML_XINCLUDE_START:
6497
50.1k
  case XML_XINCLUDE_END:
6498
50.1k
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
50.1k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
37.2k
    ((cur->parent->name[0] == ' ') ||
6502
37.2k
     (xmlStrEqual(cur->parent->name,
6503
37.2k
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
50.1k
      return(cur->parent);
6506
6
  case XML_ATTRIBUTE_NODE: {
6507
6
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
6
      return(att->parent);
6510
50.1k
  }
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
50.1k
    }
6526
0
    return(NULL);
6527
50.1k
}
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
23.7k
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
23.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
23.7k
    if (cur == NULL)
6544
3.95k
        return(ctxt->context->node);
6545
19.8k
    return(xmlXPathNextAncestor(ctxt, cur));
6546
23.7k
}
6547
6548
/**
6549
 * Traversal function for the "following-sibling" direction
6550
 * The following-sibling axis contains the following siblings of the context
6551
 * node in document order.
6552
 *
6553
 * @param ctxt  the XPath Parser context
6554
 * @param cur  the current node in the traversal
6555
 * @returns the next element following that axis
6556
 */
6557
xmlNode *
6558
0
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
0
  return(NULL);
6563
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
3
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6582
3
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6583
3
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6584
3
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6585
0
  return(NULL);
6586
3
    if (cur == (xmlNodePtr) ctxt->context->doc)
6587
0
        return(NULL);
6588
3
    if (cur == NULL)
6589
3
        return(ctxt->context->node->prev);
6590
0
    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
0
    return(cur->prev);
6596
0
}
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
1.49k
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6611
1.49k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6612
1.49k
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6613
1.29k
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6614
82
        return(cur->children);
6615
6616
1.41k
    if (cur == NULL) {
6617
200
        cur = ctxt->context->node;
6618
200
        if (cur->type == XML_ATTRIBUTE_NODE) {
6619
12
            cur = cur->parent;
6620
188
        } 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
200
    }
6629
1.41k
    if (cur == NULL) return(NULL) ; /* ERROR */
6630
1.41k
    if (cur->next != NULL) return(cur->next) ;
6631
443
    do {
6632
443
        cur = cur->parent;
6633
443
        if (cur == NULL) break;
6634
408
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6635
243
        if (cur->next != NULL) return(cur->next);
6636
243
    } while (cur != NULL);
6637
35
    return(cur);
6638
302
}
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
0
{
6732
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6733
0
    if (cur == NULL) {
6734
0
        cur = ctxt->context->node;
6735
0
        if (cur == NULL)
6736
0
            return (NULL);
6737
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6738
0
            cur = cur->parent;
6739
0
        } 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
0
        ctxt->ancestor = cur->parent;
6748
0
    }
6749
0
    if (cur->type == XML_NAMESPACE_DECL)
6750
0
        return(NULL);
6751
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6752
0
  cur = cur->prev;
6753
0
    while (cur->prev == NULL) {
6754
0
        cur = cur->parent;
6755
0
        if (cur == NULL)
6756
0
            return (NULL);
6757
0
        if (cur == ctxt->context->doc->children)
6758
0
            return (NULL);
6759
0
        if (cur != ctxt->ancestor)
6760
0
            return (cur);
6761
0
        ctxt->ancestor = cur->parent;
6762
0
    }
6763
0
    cur = cur->prev;
6764
0
    while (cur->last != NULL)
6765
0
        cur = cur->last;
6766
0
    return (cur);
6767
0
}
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
3
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6783
3
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6784
3
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6785
0
    if (cur == NULL) {
6786
0
        if (ctxt->context->tmpNsList != NULL)
6787
0
      xmlFree(ctxt->context->tmpNsList);
6788
0
  ctxt->context->tmpNsNr = 0;
6789
0
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6790
0
                             &ctxt->context->tmpNsList) < 0) {
6791
0
            xmlXPathPErrMemory(ctxt);
6792
0
            return(NULL);
6793
0
        }
6794
0
        if (ctxt->context->tmpNsList != NULL) {
6795
0
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6796
0
                ctxt->context->tmpNsNr++;
6797
0
            }
6798
0
        }
6799
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
6800
0
    }
6801
0
    if (ctxt->context->tmpNsNr > 0) {
6802
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6803
0
    } else {
6804
0
  if (ctxt->context->tmpNsList != NULL)
6805
0
      xmlFree(ctxt->context->tmpNsList);
6806
0
  ctxt->context->tmpNsList = NULL;
6807
0
  return(NULL);
6808
0
    }
6809
0
}
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
374k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6821
374k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6822
374k
    if (ctxt->context->node == NULL)
6823
0
  return(NULL);
6824
374k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6825
55.7k
  return(NULL);
6826
319k
    if (cur == NULL) {
6827
307k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6828
0
      return(NULL);
6829
307k
        return((xmlNodePtr)ctxt->context->node->properties);
6830
307k
    }
6831
11.2k
    return((xmlNodePtr)cur->next);
6832
319k
}
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
265k
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6856
265k
    if ((ctxt == NULL) || (ctxt->context == NULL))
6857
0
  return;
6858
265k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6859
265k
                                            (xmlNodePtr) ctxt->context->doc));
6860
265k
}
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
51
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6901
143
    CHECK_ARITY(0);
6902
143
    if (ctxt->context->proximityPosition >= 0) {
6903
46
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6904
46
            (double) ctxt->context->proximityPosition));
6905
46
    } else {
6906
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6907
0
    }
6908
143
}
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
65
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6919
65
    xmlXPathObjectPtr cur;
6920
6921
189
    CHECK_ARITY(1);
6922
189
    if ((ctxt->value == NULL) ||
6923
62
  ((ctxt->value->type != XPATH_NODESET) &&
6924
4
   (ctxt->value->type != XPATH_XSLT_TREE)))
6925
58
  XP_ERROR(XPATH_INVALID_TYPE);
6926
58
    cur = xmlXPathValuePop(ctxt);
6927
6928
58
    if ((cur == NULL) || (cur->nodesetval == NULL))
6929
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6930
58
    else
6931
58
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6932
58
      (double) cur->nodesetval->nodeNr));
6933
58
    xmlXPathReleaseObject(ctxt->context, cur);
6934
58
}
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
15.5k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6945
15.5k
    xmlNodeSetPtr ret;
6946
15.5k
    const xmlChar *cur = ids;
6947
15.5k
    xmlChar *ID;
6948
15.5k
    xmlAttrPtr attr;
6949
15.5k
    xmlNodePtr elem = NULL;
6950
6951
15.5k
    if (ids == NULL) return(NULL);
6952
6953
15.5k
    ret = xmlXPathNodeSetCreate(NULL);
6954
15.5k
    if (ret == NULL)
6955
13
        return(ret);
6956
6957
15.4k
    while (IS_BLANK_CH(*cur)) cur++;
6958
32.6k
    while (*cur != 0) {
6959
159k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6960
142k
      cur++;
6961
6962
17.1k
        ID = xmlStrndup(ids, cur - ids);
6963
17.1k
  if (ID == NULL) {
6964
16
            xmlXPathFreeNodeSet(ret);
6965
16
            return(NULL);
6966
16
        }
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
17.1k
        attr = xmlGetID(doc, ID);
6975
17.1k
        xmlFree(ID);
6976
17.1k
        if (attr != NULL) {
6977
865
            if (attr->type == XML_ATTRIBUTE_NODE)
6978
865
                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
865
            if (elem != NULL) {
6984
865
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
6985
2
                    xmlXPathFreeNodeSet(ret);
6986
2
                    return(NULL);
6987
2
                }
6988
865
            }
6989
865
        }
6990
6991
17.1k
  while (IS_BLANK_CH(*cur)) cur++;
6992
17.1k
  ids = cur;
6993
17.1k
    }
6994
15.4k
    return(ret);
6995
15.4k
}
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
13.8k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7016
13.8k
    xmlChar *tokens;
7017
13.8k
    xmlNodeSetPtr ret;
7018
13.8k
    xmlXPathObjectPtr obj;
7019
7020
41.5k
    CHECK_ARITY(1);
7021
41.5k
    obj = xmlXPathValuePop(ctxt);
7022
41.5k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7023
13.8k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7024
3.38k
  xmlNodeSetPtr ns;
7025
3.38k
  int i;
7026
7027
3.38k
  ret = xmlXPathNodeSetCreate(NULL);
7028
3.38k
        if (ret == NULL)
7029
4
            xmlXPathPErrMemory(ctxt);
7030
7031
3.38k
  if (obj->nodesetval != NULL) {
7032
8.45k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7033
5.06k
    tokens =
7034
5.06k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7035
5.06k
                if (tokens == NULL)
7036
12
                    xmlXPathPErrMemory(ctxt);
7037
5.06k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7038
5.06k
                if (ns == NULL)
7039
30
                    xmlXPathPErrMemory(ctxt);
7040
5.06k
    ret = xmlXPathNodeSetMerge(ret, ns);
7041
5.06k
                if (ret == NULL)
7042
1
                    xmlXPathPErrMemory(ctxt);
7043
5.06k
    xmlXPathFreeNodeSet(ns);
7044
5.06k
    if (tokens != NULL)
7045
5.05k
        xmlFree(tokens);
7046
5.06k
      }
7047
3.38k
  }
7048
3.38k
  xmlXPathReleaseObject(ctxt->context, obj);
7049
3.38k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7050
3.38k
  return;
7051
3.38k
    }
7052
10.4k
    tokens = xmlXPathCastToString(obj);
7053
10.4k
    if (tokens == NULL)
7054
8
        xmlXPathPErrMemory(ctxt);
7055
10.4k
    xmlXPathReleaseObject(ctxt->context, obj);
7056
10.4k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7057
10.4k
    if (ret == NULL)
7058
21
        xmlXPathPErrMemory(ctxt);
7059
10.4k
    xmlFree(tokens);
7060
10.4k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7061
10.4k
}
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
1.52k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7077
1.52k
    xmlXPathObjectPtr cur;
7078
7079
1.52k
    if (ctxt == NULL) return;
7080
7081
1.52k
    if (nargs == 0) {
7082
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7083
0
  nargs = 1;
7084
0
    }
7085
7086
4.58k
    CHECK_ARITY(1);
7087
4.58k
    if ((ctxt->value == NULL) ||
7088
1.52k
  ((ctxt->value->type != XPATH_NODESET) &&
7089
3
   (ctxt->value->type != XPATH_XSLT_TREE)))
7090
1.52k
  XP_ERROR(XPATH_INVALID_TYPE);
7091
1.52k
    cur = xmlXPathValuePop(ctxt);
7092
7093
1.52k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7094
1
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7095
1.52k
    } else {
7096
1.52k
  int i = 0; /* Should be first in document order !!!!! */
7097
1.52k
  switch (cur->nodesetval->nodeTab[i]->type) {
7098
1
  case XML_ELEMENT_NODE:
7099
1
  case XML_ATTRIBUTE_NODE:
7100
1
  case XML_PI_NODE:
7101
1
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7102
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7103
1
      else
7104
1
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7105
1
      cur->nodesetval->nodeTab[i]->name));
7106
1
      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
1.52k
  default:
7112
1.52k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7113
1.52k
  }
7114
1.52k
    }
7115
1.52k
    xmlXPathReleaseObject(ctxt->context, cur);
7116
1.52k
}
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
0
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7133
0
    xmlXPathObjectPtr cur;
7134
7135
0
    if (ctxt == NULL) return;
7136
7137
0
    if (nargs == 0) {
7138
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7139
0
  nargs = 1;
7140
0
    }
7141
0
    CHECK_ARITY(1);
7142
0
    if ((ctxt->value == NULL) ||
7143
0
  ((ctxt->value->type != XPATH_NODESET) &&
7144
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7145
0
  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
4.23k
{
7192
4.23k
    xmlXPathObjectPtr cur;
7193
7194
4.23k
    if (nargs == 0) {
7195
1.95k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7196
1.95k
        nargs = 1;
7197
1.95k
    }
7198
7199
12.7k
    CHECK_ARITY(1);
7200
12.7k
    if ((ctxt->value == NULL) ||
7201
4.23k
        ((ctxt->value->type != XPATH_NODESET) &&
7202
7
         (ctxt->value->type != XPATH_XSLT_TREE)))
7203
4.22k
        XP_ERROR(XPATH_INVALID_TYPE);
7204
4.22k
    cur = xmlXPathValuePop(ctxt);
7205
7206
4.22k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7207
1.78k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7208
2.43k
    } else {
7209
2.43k
        int i = 0;              /* Should be first in document order !!!!! */
7210
7211
2.43k
        switch (cur->nodesetval->nodeTab[i]->type) {
7212
911
            case XML_ELEMENT_NODE:
7213
911
            case XML_ATTRIBUTE_NODE:
7214
911
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7215
0
        xmlXPathValuePush(ctxt,
7216
0
      xmlXPathCacheNewCString(ctxt, ""));
7217
911
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7218
848
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7219
848
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7220
848
          cur->nodesetval->nodeTab[i]->name));
7221
848
    } else {
7222
63
        xmlChar *fullname;
7223
7224
63
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7225
63
             cur->nodesetval->nodeTab[i]->ns->prefix,
7226
63
             NULL, 0);
7227
63
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7228
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7229
63
        if (fullname == NULL)
7230
1
                        xmlXPathPErrMemory(ctxt);
7231
63
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7232
63
                }
7233
911
                break;
7234
1.52k
            default:
7235
1.52k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7236
1.52k
        cur->nodesetval->nodeTab[i]));
7237
1.52k
                xmlXPathLocalNameFunction(ctxt, 1);
7238
2.43k
        }
7239
2.43k
    }
7240
4.22k
    xmlXPathReleaseObject(ctxt->context, cur);
7241
4.22k
}
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
9.90k
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7281
9.90k
    xmlXPathObjectPtr cur;
7282
9.90k
    xmlChar *stringval;
7283
7284
9.90k
    if (ctxt == NULL) return;
7285
9.90k
    if (nargs == 0) {
7286
27
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7287
27
        if (stringval == NULL)
7288
1
            xmlXPathPErrMemory(ctxt);
7289
27
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7290
27
  return;
7291
27
    }
7292
7293
39.5k
    CHECK_ARITY(1);
7294
39.5k
    cur = xmlXPathValuePop(ctxt);
7295
39.5k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7296
9.87k
    if (cur->type != XPATH_STRING) {
7297
9.87k
        stringval = xmlXPathCastToString(cur);
7298
9.87k
        if (stringval == NULL)
7299
13
            xmlXPathPErrMemory(ctxt);
7300
9.87k
        xmlXPathReleaseObject(ctxt->context, cur);
7301
9.87k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7302
9.87k
    }
7303
9.87k
    xmlXPathValuePush(ctxt, cur);
7304
9.87k
}
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
269
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7319
269
    xmlXPathObjectPtr cur;
7320
7321
269
    if (nargs == 0) {
7322
74
        if ((ctxt == NULL) || (ctxt->context == NULL))
7323
0
      return;
7324
74
  if (ctxt->context->node == NULL) {
7325
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7326
74
  } else {
7327
74
      xmlChar *content;
7328
7329
74
      content = xmlXPathCastNodeToString(ctxt->context->node);
7330
74
            if (content == NULL)
7331
1
                xmlXPathPErrMemory(ctxt);
7332
74
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7333
74
    xmlUTF8Strlen(content)));
7334
74
      xmlFree(content);
7335
74
  }
7336
74
  return;
7337
74
    }
7338
774
    CHECK_ARITY(1);
7339
774
    CAST_TO_STRING;
7340
774
    CHECK_TYPE(XPATH_STRING);
7341
190
    cur = xmlXPathValuePop(ctxt);
7342
190
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7343
190
  xmlUTF8Strlen(cur->stringval)));
7344
190
    xmlXPathReleaseObject(ctxt->context, cur);
7345
190
}
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
350
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7357
350
    xmlXPathObjectPtr cur, newobj;
7358
350
    xmlChar *tmp;
7359
7360
350
    if (ctxt == NULL) return;
7361
350
    if (nargs < 2) {
7362
11
  CHECK_ARITY(2);
7363
11
    }
7364
7365
339
    CAST_TO_STRING;
7366
339
    cur = xmlXPathValuePop(ctxt);
7367
339
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7368
2
  xmlXPathReleaseObject(ctxt->context, cur);
7369
2
  return;
7370
2
    }
7371
337
    nargs--;
7372
7373
1.57k
    while (nargs > 0) {
7374
1.24k
  CAST_TO_STRING;
7375
1.24k
  newobj = xmlXPathValuePop(ctxt);
7376
1.24k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7377
3
      xmlXPathReleaseObject(ctxt->context, newobj);
7378
3
      xmlXPathReleaseObject(ctxt->context, cur);
7379
3
      XP_ERROR(XPATH_INVALID_TYPE);
7380
0
  }
7381
1.23k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7382
1.23k
        if (tmp == NULL)
7383
1
            xmlXPathPErrMemory(ctxt);
7384
1.23k
  newobj->stringval = cur->stringval;
7385
1.23k
  cur->stringval = tmp;
7386
1.23k
  xmlXPathReleaseObject(ctxt->context, newobj);
7387
1.23k
  nargs--;
7388
1.23k
    }
7389
334
    xmlXPathValuePush(ctxt, cur);
7390
334
}
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
0
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7403
0
    xmlXPathObjectPtr hay, needle;
7404
7405
0
    CHECK_ARITY(2);
7406
0
    CAST_TO_STRING;
7407
0
    CHECK_TYPE(XPATH_STRING);
7408
0
    needle = xmlXPathValuePop(ctxt);
7409
0
    CAST_TO_STRING;
7410
0
    hay = xmlXPathValuePop(ctxt);
7411
7412
0
    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
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7418
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7419
0
    else
7420
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7421
0
    xmlXPathReleaseObject(ctxt->context, hay);
7422
0
    xmlXPathReleaseObject(ctxt->context, needle);
7423
0
}
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
61
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7436
61
    xmlXPathObjectPtr hay, needle;
7437
61
    int n;
7438
7439
175
    CHECK_ARITY(2);
7440
175
    CAST_TO_STRING;
7441
175
    CHECK_TYPE(XPATH_STRING);
7442
56
    needle = xmlXPathValuePop(ctxt);
7443
56
    CAST_TO_STRING;
7444
56
    hay = xmlXPathValuePop(ctxt);
7445
7446
56
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7447
1
  xmlXPathReleaseObject(ctxt->context, hay);
7448
1
  xmlXPathReleaseObject(ctxt->context, needle);
7449
1
  XP_ERROR(XPATH_INVALID_TYPE);
7450
0
    }
7451
55
    n = xmlStrlen(needle->stringval);
7452
55
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7453
31
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7454
24
    else
7455
24
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7456
55
    xmlXPathReleaseObject(ctxt->context, hay);
7457
55
    xmlXPathReleaseObject(ctxt->context, needle);
7458
55
}
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
324
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7489
324
    xmlXPathObjectPtr str, start, len;
7490
324
    double le=0, in;
7491
324
    int i = 1, j = INT_MAX;
7492
7493
324
    if (nargs < 2) {
7494
6
  CHECK_ARITY(2);
7495
6
    }
7496
318
    if (nargs > 3) {
7497
6
  CHECK_ARITY(3);
7498
6
    }
7499
    /*
7500
     * take care of possible last (position) argument
7501
    */
7502
312
    if (nargs == 3) {
7503
111
  CAST_TO_NUMBER;
7504
111
  CHECK_TYPE(XPATH_NUMBER);
7505
110
  len = xmlXPathValuePop(ctxt);
7506
110
  le = len->floatval;
7507
110
  xmlXPathReleaseObject(ctxt->context, len);
7508
110
    }
7509
7510
311
    CAST_TO_NUMBER;
7511
311
    CHECK_TYPE(XPATH_NUMBER);
7512
310
    start = xmlXPathValuePop(ctxt);
7513
310
    in = start->floatval;
7514
310
    xmlXPathReleaseObject(ctxt->context, start);
7515
310
    CAST_TO_STRING;
7516
310
    CHECK_TYPE(XPATH_STRING);
7517
306
    str = xmlXPathValuePop(ctxt);
7518
7519
306
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7520
73
        i = INT_MAX;
7521
233
    } else if (in >= 1.0) {
7522
145
        i = (int)in;
7523
145
        if (in - floor(in) >= 0.5)
7524
32
            i += 1;
7525
145
    }
7526
7527
306
    if (nargs == 3) {
7528
109
        double rin, rle, end;
7529
7530
109
        rin = floor(in);
7531
109
        if (in - rin >= 0.5)
7532
32
            rin += 1.0;
7533
7534
109
        rle = floor(le);
7535
109
        if (le - rle >= 0.5)
7536
1
            rle += 1.0;
7537
7538
109
        end = rin + rle;
7539
109
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7540
69
            j = 1;
7541
69
        } else if (end < INT_MAX) {
7542
26
            j = (int)end;
7543
26
        }
7544
109
    }
7545
7546
306
    i -= 1;
7547
306
    j -= 1;
7548
7549
306
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7550
137
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7551
137
        if (ret == NULL)
7552
2
            xmlXPathPErrMemory(ctxt);
7553
137
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7554
137
  xmlFree(ret);
7555
169
    } else {
7556
169
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7557
169
    }
7558
7559
306
    xmlXPathReleaseObject(ctxt->context, str);
7560
306
}
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
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7576
0
    xmlXPathObjectPtr str = NULL;
7577
0
    xmlXPathObjectPtr find = NULL;
7578
0
    const xmlChar *point;
7579
0
    xmlChar *result;
7580
7581
0
    CHECK_ARITY(2);
7582
0
    CAST_TO_STRING;
7583
0
    find = xmlXPathValuePop(ctxt);
7584
0
    CAST_TO_STRING;
7585
0
    str = xmlXPathValuePop(ctxt);
7586
0
    if (ctxt->error != 0)
7587
0
        goto error;
7588
7589
0
    point = xmlStrstr(str->stringval, find->stringval);
7590
0
    if (point == NULL) {
7591
0
        result = xmlStrdup(BAD_CAST "");
7592
0
    } else {
7593
0
        result = xmlStrndup(str->stringval, point - str->stringval);
7594
0
    }
7595
0
    if (result == NULL) {
7596
0
        xmlXPathPErrMemory(ctxt);
7597
0
        goto error;
7598
0
    }
7599
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7600
7601
0
error:
7602
0
    xmlXPathReleaseObject(ctxt->context, str);
7603
0
    xmlXPathReleaseObject(ctxt->context, find);
7604
0
}
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
0
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7731
0
    xmlXPathObjectPtr str = NULL;
7732
0
    xmlXPathObjectPtr from = NULL;
7733
0
    xmlXPathObjectPtr to = NULL;
7734
0
    xmlBufPtr target;
7735
0
    int offset, max;
7736
0
    int ch;
7737
0
    const xmlChar *point;
7738
0
    xmlChar *cptr, *content;
7739
7740
0
    CHECK_ARITY(3);
7741
7742
0
    CAST_TO_STRING;
7743
0
    to = xmlXPathValuePop(ctxt);
7744
0
    CAST_TO_STRING;
7745
0
    from = xmlXPathValuePop(ctxt);
7746
0
    CAST_TO_STRING;
7747
0
    str = xmlXPathValuePop(ctxt);
7748
0
    if (ctxt->error != 0)
7749
0
        goto error;
7750
7751
    /*
7752
     * Account for quadratic runtime
7753
     */
7754
0
    if (ctxt->context->opLimit != 0) {
7755
0
        unsigned long f1 = xmlStrlen(from->stringval);
7756
0
        unsigned long f2 = xmlStrlen(str->stringval);
7757
7758
0
        if ((f1 > 0) && (f2 > 0)) {
7759
0
            unsigned long p;
7760
7761
0
            f1 = f1 / 10 + 1;
7762
0
            f2 = f2 / 10 + 1;
7763
0
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7764
0
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7765
0
                goto error;
7766
0
        }
7767
0
    }
7768
7769
0
    target = xmlBufCreate(50);
7770
0
    if (target == NULL) {
7771
0
        xmlXPathPErrMemory(ctxt);
7772
0
        goto error;
7773
0
    }
7774
7775
0
    max = xmlUTF8Strlen(to->stringval);
7776
0
    for (cptr = str->stringval; (ch=*cptr); ) {
7777
0
        offset = xmlUTF8Strloc(from->stringval, cptr);
7778
0
        if (offset >= 0) {
7779
0
            if (offset < max) {
7780
0
                point = xmlUTF8Strpos(to->stringval, offset);
7781
0
                if (point)
7782
0
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7783
0
            }
7784
0
        } else
7785
0
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7786
7787
        /* Step to next character in input */
7788
0
        cptr++;
7789
0
        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
0
    }
7805
7806
0
    content = xmlBufDetach(target);
7807
0
    if (content == NULL)
7808
0
        xmlXPathPErrMemory(ctxt);
7809
0
    else
7810
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7811
0
    xmlBufFree(target);
7812
0
error:
7813
0
    xmlXPathReleaseObject(ctxt->context, str);
7814
0
    xmlXPathReleaseObject(ctxt->context, from);
7815
0
    xmlXPathReleaseObject(ctxt->context, to);
7816
0
}
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
24.0k
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7832
24.0k
    xmlXPathObjectPtr cur;
7833
7834
72.2k
    CHECK_ARITY(1);
7835
72.2k
    cur = xmlXPathValuePop(ctxt);
7836
72.2k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7837
24.0k
    if (cur->type != XPATH_BOOLEAN) {
7838
21.1k
        int boolval = xmlXPathCastToBoolean(cur);
7839
7840
21.1k
        xmlXPathReleaseObject(ctxt->context, cur);
7841
21.1k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7842
21.1k
    }
7843
24.0k
    xmlXPathValuePush(ctxt, cur);
7844
24.0k
}
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
4
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7857
10
    CHECK_ARITY(1);
7858
10
    CAST_TO_BOOLEAN;
7859
10
    CHECK_TYPE(XPATH_BOOLEAN);
7860
2
    ctxt->value->boolval = ! ctxt->value->boolval;
7861
2
}
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
14
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7872
36
    CHECK_ARITY(0);
7873
36
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7874
36
}
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
3
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7885
7
    CHECK_ARITY(0);
7886
7
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7887
7
}
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
7.73k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7911
7.73k
    xmlXPathObjectPtr val;
7912
7.73k
    xmlNodePtr cur;
7913
7.73k
    xmlChar *theLang;
7914
7.73k
    const xmlChar *lang;
7915
7.73k
    int ret = 0;
7916
7.73k
    int i;
7917
7918
23.2k
    CHECK_ARITY(1);
7919
23.2k
    CAST_TO_STRING;
7920
23.2k
    CHECK_TYPE(XPATH_STRING);
7921
7.73k
    val = xmlXPathValuePop(ctxt);
7922
7.73k
    lang = val->stringval;
7923
7.73k
    cur = ctxt->context->node;
7924
89.9k
    while (cur != NULL) {
7925
82.2k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7926
82.2k
                                &theLang) < 0)
7927
0
            xmlXPathPErrMemory(ctxt);
7928
82.2k
        if (theLang != NULL)
7929
0
            break;
7930
82.2k
        cur = cur->parent;
7931
82.2k
    }
7932
7.73k
    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
7.73k
not_equal:
7940
7.73k
    if (theLang != NULL)
7941
0
  xmlFree((void *)theLang);
7942
7943
7.73k
    xmlXPathReleaseObject(ctxt->context, val);
7944
7.73k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7945
7.73k
}
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
388k
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7956
388k
    xmlXPathObjectPtr cur;
7957
388k
    double res;
7958
7959
388k
    if (ctxt == NULL) return;
7960
388k
    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.55M
    CHECK_ARITY(1);
7976
1.55M
    cur = xmlXPathValuePop(ctxt);
7977
1.55M
    if (cur->type != XPATH_NUMBER) {
7978
388k
        double floatval;
7979
7980
388k
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
7981
388k
        xmlXPathReleaseObject(ctxt->context, cur);
7982
388k
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
7983
388k
    }
7984
1.55M
    xmlXPathValuePush(ctxt, cur);
7985
1.55M
}
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
41
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
7998
41
    xmlXPathObjectPtr cur;
7999
41
    int i;
8000
41
    double res = 0.0;
8001
8002
95
    CHECK_ARITY(1);
8003
95
    if ((ctxt->value == NULL) ||
8004
27
  ((ctxt->value->type != XPATH_NODESET) &&
8005
3
   (ctxt->value->type != XPATH_XSLT_TREE)))
8006
24
  XP_ERROR(XPATH_INVALID_TYPE);
8007
24
    cur = xmlXPathValuePop(ctxt);
8008
8009
24
    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
24
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8016
24
    xmlXPathReleaseObject(ctxt->context, cur);
8017
24
}
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
31
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
91
    CHECK_ARITY(1);
8031
91
    CAST_TO_NUMBER;
8032
91
    CHECK_TYPE(XPATH_NUMBER);
8033
8034
29
    ctxt->value->floatval = floor(ctxt->value->floatval);
8035
29
}
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
123k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8116
123k
    const xmlChar *end;
8117
123k
    xmlChar *ret;
8118
8119
123k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8120
8121
123k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8122
123k
    if (end == NULL) {
8123
3
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8124
0
    }
8125
123k
    if (end == ctxt->cur)
8126
3.23k
        return(NULL);
8127
8128
120k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8129
120k
    if (ret == NULL)
8130
75
        xmlXPathPErrMemory(ctxt);
8131
120k
    ctxt->cur = end;
8132
120k
    return(ret);
8133
123k
}
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
11.0k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8147
11.0k
    xmlChar *ret = NULL;
8148
8149
11.0k
    *prefix = NULL;
8150
11.0k
    ret = xmlXPathParseNCName(ctxt);
8151
11.0k
    if (ret && CUR == ':') {
8152
1.39k
        *prefix = ret;
8153
1.39k
  NEXT;
8154
1.39k
  ret = xmlXPathParseNCName(ctxt);
8155
1.39k
    }
8156
11.0k
    return(ret);
8157
11.0k
}
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
14.7k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8168
14.7k
    const xmlChar *end;
8169
14.7k
    xmlChar *ret;
8170
8171
14.7k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8172
8173
14.7k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8174
14.7k
    if (end == NULL) {
8175
3
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8176
0
    }
8177
14.7k
    if (end == ctxt->cur)
8178
2.87k
        return(NULL);
8179
8180
11.8k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8181
11.8k
    if (ret == NULL)
8182
38
        xmlXPathPErrMemory(ctxt);
8183
11.8k
    ctxt->cur = end;
8184
11.8k
    return(ret);
8185
14.7k
}
8186
8187
85.0k
#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
561k
xmlXPathStringEvalNumber(const xmlChar *str) {
8205
561k
    const xmlChar *cur = str;
8206
561k
    double ret;
8207
561k
    int ok = 0;
8208
561k
    int isneg = 0;
8209
561k
    int exponent = 0;
8210
561k
    int is_exponent_negative = 0;
8211
561k
#ifdef __GNUC__
8212
561k
    unsigned long tmp = 0;
8213
561k
    double temp;
8214
561k
#endif
8215
561k
    if (cur == NULL) return(0);
8216
561k
    while (IS_BLANK_CH(*cur)) cur++;
8217
561k
    if (*cur == '-') {
8218
86.2k
  isneg = 1;
8219
86.2k
  cur++;
8220
86.2k
    }
8221
561k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8222
447k
        return(xmlXPathNAN);
8223
447k
    }
8224
8225
113k
#ifdef __GNUC__
8226
    /*
8227
     * tmp/temp is a workaround against a gcc compiler bug
8228
     * http://veillard.com/gcc.bug
8229
     */
8230
113k
    ret = 0;
8231
122k
    while ((*cur >= '0') && (*cur <= '9')) {
8232
9.37k
  ret = ret * 10;
8233
9.37k
  tmp = (*cur - '0');
8234
9.37k
  ok = 1;
8235
9.37k
  cur++;
8236
9.37k
  temp = (double) tmp;
8237
9.37k
  ret = ret + temp;
8238
9.37k
    }
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
113k
    if (*cur == '.') {
8249
107k
  int v, frac = 0, max;
8250
107k
  double fraction = 0;
8251
8252
107k
        cur++;
8253
107k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8254
26.6k
      return(xmlXPathNAN);
8255
26.6k
  }
8256
87.7k
        while (*cur == '0') {
8257
7.19k
      frac = frac + 1;
8258
7.19k
      cur++;
8259
7.19k
        }
8260
80.6k
        max = frac + MAX_FRAC;
8261
240k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8262
159k
      v = (*cur - '0');
8263
159k
      fraction = fraction * 10 + v;
8264
159k
      frac = frac + 1;
8265
159k
      cur++;
8266
159k
  }
8267
80.6k
  fraction /= pow(10.0, frac);
8268
80.6k
  ret = ret + fraction;
8269
82.4k
  while ((*cur >= '0') && (*cur <= '9'))
8270
1.84k
      cur++;
8271
80.6k
    }
8272
86.6k
    if ((*cur == 'e') || (*cur == 'E')) {
8273
46.3k
      cur++;
8274
46.3k
      if (*cur == '-') {
8275
38.0k
  is_exponent_negative = 1;
8276
38.0k
  cur++;
8277
38.0k
      } else if (*cur == '+') {
8278
300
        cur++;
8279
300
      }
8280
268k
      while ((*cur >= '0') && (*cur <= '9')) {
8281
221k
        if (exponent < 1000000)
8282
220k
    exponent = exponent * 10 + (*cur - '0');
8283
221k
  cur++;
8284
221k
      }
8285
46.3k
    }
8286
322k
    while (IS_BLANK_CH(*cur)) cur++;
8287
86.6k
    if (*cur != 0) return(xmlXPathNAN);
8288
52.8k
    if (isneg) ret = -ret;
8289
52.8k
    if (is_exponent_negative) exponent = -exponent;
8290
52.8k
    ret *= pow(10.0, (double)exponent);
8291
52.8k
    return(ret);
8292
86.6k
}
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
25.0k
{
8306
25.0k
    double ret = 0.0;
8307
25.0k
    int ok = 0;
8308
25.0k
    int exponent = 0;
8309
25.0k
    int is_exponent_negative = 0;
8310
25.0k
    xmlXPathObjectPtr num;
8311
25.0k
#ifdef __GNUC__
8312
25.0k
    unsigned long tmp = 0;
8313
25.0k
    double temp;
8314
25.0k
#endif
8315
8316
25.0k
    CHECK_ERROR;
8317
25.0k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8318
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8319
0
    }
8320
25.0k
#ifdef __GNUC__
8321
    /*
8322
     * tmp/temp is a workaround against a gcc compiler bug
8323
     * http://veillard.com/gcc.bug
8324
     */
8325
25.0k
    ret = 0;
8326
86.5k
    while ((CUR >= '0') && (CUR <= '9')) {
8327
61.4k
  ret = ret * 10;
8328
61.4k
  tmp = (CUR - '0');
8329
61.4k
        ok = 1;
8330
61.4k
        NEXT;
8331
61.4k
  temp = (double) tmp;
8332
61.4k
  ret = ret + temp;
8333
61.4k
    }
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
25.0k
    if (CUR == '.') {
8343
4.49k
  int v, frac = 0, max;
8344
4.49k
  double fraction = 0;
8345
8346
4.49k
        NEXT;
8347
4.49k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8348
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8349
0
        }
8350
7.69k
        while (CUR == '0') {
8351
3.19k
            frac = frac + 1;
8352
3.19k
            NEXT;
8353
3.19k
        }
8354
4.49k
        max = frac + MAX_FRAC;
8355
20.9k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8356
16.4k
      v = (CUR - '0');
8357
16.4k
      fraction = fraction * 10 + v;
8358
16.4k
      frac = frac + 1;
8359
16.4k
            NEXT;
8360
16.4k
        }
8361
4.49k
        fraction /= pow(10.0, frac);
8362
4.49k
        ret = ret + fraction;
8363
6.09k
        while ((CUR >= '0') && (CUR <= '9'))
8364
1.59k
            NEXT;
8365
4.49k
    }
8366
25.0k
    if ((CUR == 'e') || (CUR == 'E')) {
8367
3.67k
        NEXT;
8368
3.67k
        if (CUR == '-') {
8369
164
            is_exponent_negative = 1;
8370
164
            NEXT;
8371
3.50k
        } else if (CUR == '+') {
8372
74
      NEXT;
8373
74
  }
8374
18.6k
        while ((CUR >= '0') && (CUR <= '9')) {
8375
15.0k
            if (exponent < 1000000)
8376
13.7k
                exponent = exponent * 10 + (CUR - '0');
8377
15.0k
            NEXT;
8378
15.0k
        }
8379
3.67k
        if (is_exponent_negative)
8380
164
            exponent = -exponent;
8381
3.67k
        ret *= pow(10.0, (double) exponent);
8382
3.67k
    }
8383
25.0k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8384
25.0k
    if (num == NULL) {
8385
19
  ctxt->error = XPATH_MEMORY_ERROR;
8386
24.9k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8387
24.9k
                              NULL) == -1) {
8388
6
        xmlXPathReleaseObject(ctxt->context, num);
8389
6
    }
8390
25.0k
}
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
1.67k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8403
1.67k
    const xmlChar *q;
8404
1.67k
    xmlChar *ret = NULL;
8405
1.67k
    int quote;
8406
8407
1.67k
    if (CUR == '"') {
8408
177
        quote = '"';
8409
1.49k
    } else if (CUR == '\'') {
8410
1.48k
        quote = '\'';
8411
1.48k
    } else {
8412
8
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8413
0
    }
8414
8415
1.66k
    NEXT;
8416
1.66k
    q = CUR_PTR;
8417
57.0k
    while (CUR != quote) {
8418
55.5k
        int ch;
8419
55.5k
        int len = 4;
8420
8421
55.5k
        if (CUR == 0)
8422
55.4k
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8423
55.4k
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8424
55.4k
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8425
55.4k
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8426
55.4k
        CUR_PTR += len;
8427
55.4k
    }
8428
1.52k
    ret = xmlStrndup(q, CUR_PTR - q);
8429
1.52k
    if (ret == NULL)
8430
4
        xmlXPathPErrMemory(ctxt);
8431
1.52k
    NEXT;
8432
1.52k
    return(ret);
8433
1.66k
}
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
1.56k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8447
1.56k
    xmlChar *ret = NULL;
8448
1.56k
    xmlXPathObjectPtr lit;
8449
8450
1.56k
    ret = xmlXPathParseLiteral(ctxt);
8451
1.56k
    if (ret == NULL)
8452
134
        return;
8453
1.42k
    lit = xmlXPathCacheNewString(ctxt, ret);
8454
1.42k
    if (lit == NULL) {
8455
8
        ctxt->error = XPATH_MEMORY_ERROR;
8456
1.42k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8457
1.42k
                              NULL) == -1) {
8458
1
        xmlXPathReleaseObject(ctxt->context, lit);
8459
1
    }
8460
1.42k
    xmlFree(ret);
8461
1.42k
}
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
1.14k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8480
1.14k
    xmlChar *name;
8481
1.14k
    xmlChar *prefix;
8482
8483
1.14k
    SKIP_BLANKS;
8484
1.14k
    if (CUR != '$') {
8485
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8486
0
    }
8487
1.14k
    NEXT;
8488
1.14k
    name = xmlXPathParseQName(ctxt, &prefix);
8489
1.14k
    if (name == NULL) {
8490
33
        xmlFree(prefix);
8491
33
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8492
0
    }
8493
1.11k
    ctxt->comp->last = -1;
8494
1.11k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8495
2
        xmlFree(prefix);
8496
2
        xmlFree(name);
8497
2
    }
8498
1.11k
    SKIP_BLANKS;
8499
1.11k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8500
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8501
0
    }
8502
1.11k
}
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
10.0k
xmlXPathIsNodeType(const xmlChar *name) {
8517
10.0k
    if (name == NULL)
8518
0
  return(0);
8519
8520
10.0k
    if (xmlStrEqual(name, BAD_CAST "node"))
8521
32
  return(1);
8522
10.0k
    if (xmlStrEqual(name, BAD_CAST "text"))
8523
33
  return(1);
8524
10.0k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8525
9
  return(1);
8526
10.0k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8527
133
  return(1);
8528
9.87k
    return(0);
8529
10.0k
}
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
9.87k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8542
9.87k
    xmlChar *name;
8543
9.87k
    xmlChar *prefix;
8544
9.87k
    int nbargs = 0;
8545
9.87k
    int sort = 1;
8546
8547
9.87k
    name = xmlXPathParseQName(ctxt, &prefix);
8548
9.87k
    if (name == NULL) {
8549
23
  xmlFree(prefix);
8550
23
  XP_ERROR(XPATH_EXPR_ERROR);
8551
0
    }
8552
9.85k
    SKIP_BLANKS;
8553
8554
9.85k
    if (CUR != '(') {
8555
6
  xmlFree(name);
8556
6
  xmlFree(prefix);
8557
6
  XP_ERROR(XPATH_EXPR_ERROR);
8558
0
    }
8559
9.84k
    NEXT;
8560
9.84k
    SKIP_BLANKS;
8561
8562
    /*
8563
    * Optimization for count(): we don't need the node-set to be sorted.
8564
    */
8565
9.84k
    if ((prefix == NULL) && (name[0] == 'c') &&
8566
959
  xmlStrEqual(name, BAD_CAST "count"))
8567
73
    {
8568
73
  sort = 0;
8569
73
    }
8570
9.84k
    ctxt->comp->last = -1;
8571
9.84k
    if (CUR != ')') {
8572
11.4k
  while (CUR != 0) {
8573
11.4k
      int op1 = ctxt->comp->last;
8574
11.4k
      ctxt->comp->last = -1;
8575
11.4k
      xmlXPathCompileExpr(ctxt, sort);
8576
11.4k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8577
716
    xmlFree(name);
8578
716
    xmlFree(prefix);
8579
716
    return;
8580
716
      }
8581
10.7k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8582
10.7k
      nbargs++;
8583
10.7k
      if (CUR == ')') break;
8584
3.60k
      if (CUR != ',') {
8585
93
    xmlFree(name);
8586
93
    xmlFree(prefix);
8587
93
    XP_ERROR(XPATH_EXPR_ERROR);
8588
0
      }
8589
3.51k
      NEXT;
8590
3.51k
      SKIP_BLANKS;
8591
3.51k
  }
8592
7.92k
    }
8593
9.03k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8594
1
        xmlFree(prefix);
8595
1
        xmlFree(name);
8596
1
    }
8597
9.03k
    NEXT;
8598
9.03k
    SKIP_BLANKS;
8599
9.03k
}
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
40.9k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8614
40.9k
    SKIP_BLANKS;
8615
40.9k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8616
39.8k
    else if (CUR == '(') {
8617
3.37k
  NEXT;
8618
3.37k
  SKIP_BLANKS;
8619
3.37k
  xmlXPathCompileExpr(ctxt, 1);
8620
3.37k
  CHECK_ERROR;
8621
3.06k
  if (CUR != ')') {
8622
40
      XP_ERROR(XPATH_EXPR_ERROR);
8623
0
  }
8624
3.02k
  NEXT;
8625
3.02k
  SKIP_BLANKS;
8626
36.4k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8627
25.0k
  xmlXPathCompNumber(ctxt);
8628
25.0k
    } else if ((CUR == '\'') || (CUR == '"')) {
8629
1.56k
  xmlXPathCompLiteral(ctxt);
8630
9.87k
    } else {
8631
9.87k
  xmlXPathCompFunctionCall(ctxt);
8632
9.87k
    }
8633
40.6k
    SKIP_BLANKS;
8634
40.6k
}
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
40.9k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8652
40.9k
    xmlXPathCompPrimaryExpr(ctxt);
8653
40.9k
    CHECK_ERROR;
8654
39.5k
    SKIP_BLANKS;
8655
8656
45.1k
    while (CUR == '[') {
8657
5.63k
  xmlXPathCompPredicate(ctxt, 1);
8658
5.63k
  SKIP_BLANKS;
8659
5.63k
    }
8660
8661
8662
39.5k
}
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
82.0k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8674
82.0k
    const xmlChar *end;
8675
82.0k
    xmlChar *ret;
8676
8677
82.0k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8678
82.0k
    if (end == NULL) {
8679
3
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8680
0
    }
8681
81.9k
    if (end == ctxt->cur)
8682
3.06k
        return(NULL);
8683
8684
78.9k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8685
78.9k
    if (ret == NULL)
8686
56
        xmlXPathPErrMemory(ctxt);
8687
78.9k
    return(ret);
8688
81.9k
}
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
1.94M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8703
1.94M
    int lc = 1;           /* Should we branch to LocationPath ?         */
8704
1.94M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8705
8706
1.94M
    SKIP_BLANKS;
8707
1.94M
    if ((CUR == '$') || (CUR == '(') ||
8708
1.93M
  (IS_ASCII_DIGIT(CUR)) ||
8709
1.91M
        (CUR == '\'') || (CUR == '"') ||
8710
1.91M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8711
31.1k
  lc = 0;
8712
1.91M
    } else if (CUR == '*') {
8713
  /* relative or absolute location path */
8714
1.74M
  lc = 1;
8715
1.74M
    } else if (CUR == '/') {
8716
  /* relative or absolute location path */
8717
80.5k
  lc = 1;
8718
89.6k
    } else if (CUR == '@') {
8719
  /* relative abbreviated attribute location path */
8720
710
  lc = 1;
8721
88.9k
    } else if (CUR == '.') {
8722
  /* relative abbreviated attribute location path */
8723
6.96k
  lc = 1;
8724
82.0k
    } 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
82.0k
  SKIP_BLANKS;
8737
82.0k
  name = xmlXPathScanName(ctxt);
8738
82.0k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8739
1.53k
      lc = 1;
8740
1.53k
      xmlFree(name);
8741
80.4k
  } else if (name != NULL) {
8742
77.3k
      int len =xmlStrlen(name);
8743
8744
8745
791k
      while (NXT(len) != 0) {
8746
790k
    if (NXT(len) == '/') {
8747
        /* element name */
8748
4.86k
        lc = 1;
8749
4.86k
        break;
8750
785k
    } else if (IS_BLANK_CH(NXT(len))) {
8751
        /* ignore blanks */
8752
713k
        ;
8753
713k
    } else if (NXT(len) == ':') {
8754
384
        lc = 1;
8755
384
        break;
8756
70.9k
    } else if ((NXT(len) == '(')) {
8757
        /* Node Type or Function */
8758
10.0k
        if (xmlXPathIsNodeType(name)) {
8759
207
      lc = 1;
8760
9.87k
        } else {
8761
9.87k
      lc = 0;
8762
9.87k
        }
8763
10.0k
                    break;
8764
60.8k
    } else if ((NXT(len) == '[')) {
8765
        /* element name */
8766
1.42k
        lc = 1;
8767
1.42k
        break;
8768
59.4k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8769
51.2k
         (NXT(len) == '=')) {
8770
15.1k
        lc = 1;
8771
15.1k
        break;
8772
44.3k
    } else {
8773
44.3k
        lc = 1;
8774
44.3k
        break;
8775
44.3k
    }
8776
713k
    len++;
8777
713k
      }
8778
77.3k
      if (NXT(len) == 0) {
8779
    /* element name */
8780
1.12k
    lc = 1;
8781
1.12k
      }
8782
77.3k
      xmlFree(name);
8783
77.3k
  } else {
8784
      /* make sure all cases are covered explicitly */
8785
3.12k
      XP_ERROR(XPATH_EXPR_ERROR);
8786
0
  }
8787
82.0k
    }
8788
8789
1.94M
    if (lc) {
8790
1.89M
  if (CUR == '/') {
8791
80.5k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8792
1.81M
  } else {
8793
1.81M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8794
1.81M
  }
8795
1.89M
  xmlXPathCompLocationPath(ctxt);
8796
1.89M
    } else {
8797
40.9k
  xmlXPathCompFilterExpr(ctxt);
8798
40.9k
  CHECK_ERROR;
8799
39.3k
  if ((CUR == '/') && (NXT(1) == '/')) {
8800
640
      SKIP(2);
8801
640
      SKIP_BLANKS;
8802
8803
640
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8804
640
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8805
8806
640
      xmlXPathCompRelativeLocationPath(ctxt);
8807
38.6k
  } else if (CUR == '/') {
8808
1.75k
      xmlXPathCompRelativeLocationPath(ctxt);
8809
1.75k
  }
8810
39.3k
    }
8811
1.93M
    SKIP_BLANKS;
8812
1.93M
}
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
1.92M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8825
1.92M
    xmlXPathCompPathExpr(ctxt);
8826
1.92M
    CHECK_ERROR;
8827
1.91M
    SKIP_BLANKS;
8828
1.93M
    while (CUR == '|') {
8829
18.5k
  int op1 = ctxt->comp->last;
8830
18.5k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8831
8832
18.5k
  NEXT;
8833
18.5k
  SKIP_BLANKS;
8834
18.5k
  xmlXPathCompPathExpr(ctxt);
8835
8836
18.5k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8837
8838
18.5k
  SKIP_BLANKS;
8839
18.5k
    }
8840
1.91M
}
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
1.92M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8853
1.92M
    int minus = 0;
8854
1.92M
    int found = 0;
8855
8856
1.92M
    SKIP_BLANKS;
8857
2.02M
    while (CUR == '-') {
8858
97.3k
        minus = 1 - minus;
8859
97.3k
  found = 1;
8860
97.3k
  NEXT;
8861
97.3k
  SKIP_BLANKS;
8862
97.3k
    }
8863
8864
1.92M
    xmlXPathCompUnionExpr(ctxt);
8865
1.92M
    CHECK_ERROR;
8866
1.91M
    if (found) {
8867
62.7k
  if (minus)
8868
52.6k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8869
10.1k
  else
8870
10.1k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8871
62.7k
    }
8872
1.91M
}
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
155k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8888
155k
    xmlXPathCompUnaryExpr(ctxt);
8889
155k
    CHECK_ERROR;
8890
150k
    SKIP_BLANKS;
8891
1.91M
    while ((CUR == '*') ||
8892
152k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8893
1.76M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8894
1.76M
  int op = -1;
8895
1.76M
  int op1 = ctxt->comp->last;
8896
8897
1.76M
        if (CUR == '*') {
8898
1.76M
      op = 0;
8899
1.76M
      NEXT;
8900
1.76M
  } else if (CUR == 'd') {
8901
879
      op = 1;
8902
879
      SKIP(3);
8903
978
  } else if (CUR == 'm') {
8904
978
      op = 2;
8905
978
      SKIP(3);
8906
978
  }
8907
1.76M
  SKIP_BLANKS;
8908
1.76M
        xmlXPathCompUnaryExpr(ctxt);
8909
1.76M
  CHECK_ERROR;
8910
1.76M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8911
1.76M
  SKIP_BLANKS;
8912
1.76M
    }
8913
150k
}
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
93.1k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8927
8928
93.1k
    xmlXPathCompMultiplicativeExpr(ctxt);
8929
93.1k
    CHECK_ERROR;
8930
88.5k
    SKIP_BLANKS;
8931
150k
    while ((CUR == '+') || (CUR == '-')) {
8932
62.5k
  int plus;
8933
62.5k
  int op1 = ctxt->comp->last;
8934
8935
62.5k
        if (CUR == '+') plus = 1;
8936
58.1k
  else plus = 0;
8937
62.5k
  NEXT;
8938
62.5k
  SKIP_BLANKS;
8939
62.5k
        xmlXPathCompMultiplicativeExpr(ctxt);
8940
62.5k
  CHECK_ERROR;
8941
61.7k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8942
61.7k
  SKIP_BLANKS;
8943
61.7k
    }
8944
88.5k
}
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
74.7k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8965
74.7k
    xmlXPathCompAdditiveExpr(ctxt);
8966
74.7k
    CHECK_ERROR;
8967
69.8k
    SKIP_BLANKS;
8968
87.8k
    while ((CUR == '<') || (CUR == '>')) {
8969
18.3k
  int inf, strict;
8970
18.3k
  int op1 = ctxt->comp->last;
8971
8972
18.3k
        if (CUR == '<') inf = 1;
8973
16.4k
  else inf = 0;
8974
18.3k
  if (NXT(1) == '=') strict = 0;
8975
17.4k
  else strict = 1;
8976
18.3k
  NEXT;
8977
18.3k
  if (!strict) NEXT;
8978
18.3k
  SKIP_BLANKS;
8979
18.3k
        xmlXPathCompAdditiveExpr(ctxt);
8980
18.3k
  CHECK_ERROR;
8981
17.9k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8982
17.9k
  SKIP_BLANKS;
8983
17.9k
    }
8984
69.8k
}
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
40.8k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9002
40.8k
    xmlXPathCompRelationalExpr(ctxt);
9003
40.8k
    CHECK_ERROR;
9004
36.4k
    SKIP_BLANKS;
9005
69.4k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9006
33.8k
  int eq;
9007
33.8k
  int op1 = ctxt->comp->last;
9008
9009
33.8k
        if (CUR == '=') eq = 1;
9010
1.90k
  else eq = 0;
9011
33.8k
  NEXT;
9012
33.8k
  if (!eq) NEXT;
9013
33.8k
  SKIP_BLANKS;
9014
33.8k
        xmlXPathCompRelationalExpr(ctxt);
9015
33.8k
  CHECK_ERROR;
9016
32.9k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9017
32.9k
  SKIP_BLANKS;
9018
32.9k
    }
9019
36.4k
}
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
40.1k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9031
40.1k
    xmlXPathCompEqualityExpr(ctxt);
9032
40.1k
    CHECK_ERROR;
9033
34.9k
    SKIP_BLANKS;
9034
35.5k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9035
692
  int op1 = ctxt->comp->last;
9036
692
        SKIP(3);
9037
692
  SKIP_BLANKS;
9038
692
        xmlXPathCompEqualityExpr(ctxt);
9039
692
  CHECK_ERROR;
9040
658
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9041
658
  SKIP_BLANKS;
9042
658
    }
9043
34.9k
}
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
37.4k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9057
37.4k
    xmlXPathContextPtr xpctxt = ctxt->context;
9058
9059
37.4k
    if (xpctxt != NULL) {
9060
37.4k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9061
37.1k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9062
        /*
9063
         * Parsing a single '(' pushes about 10 functions on the call stack
9064
         * before recursing!
9065
         */
9066
37.1k
        xpctxt->depth += 10;
9067
37.1k
    }
9068
9069
37.1k
    xmlXPathCompAndExpr(ctxt);
9070
37.1k
    CHECK_ERROR;
9071
32.0k
    SKIP_BLANKS;
9072
34.8k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9073
3.00k
  int op1 = ctxt->comp->last;
9074
3.00k
        SKIP(2);
9075
3.00k
  SKIP_BLANKS;
9076
3.00k
        xmlXPathCompAndExpr(ctxt);
9077
3.00k
  CHECK_ERROR;
9078
2.82k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9079
2.82k
  SKIP_BLANKS;
9080
2.82k
    }
9081
31.8k
    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
21.6k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9089
21.6k
    }
9090
9091
31.8k
    if (xpctxt != NULL)
9092
31.8k
        xpctxt->depth -= 10;
9093
31.8k
}
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
13.3k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9106
13.3k
    int op1 = ctxt->comp->last;
9107
9108
13.3k
    SKIP_BLANKS;
9109
13.3k
    if (CUR != '[') {
9110
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9111
0
    }
9112
13.3k
    NEXT;
9113
13.3k
    SKIP_BLANKS;
9114
9115
13.3k
    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
13.3k
    if (! filter)
9126
7.73k
  xmlXPathCompileExpr(ctxt, 0);
9127
5.63k
    else
9128
5.63k
  xmlXPathCompileExpr(ctxt, 1);
9129
13.3k
    CHECK_ERROR;
9130
9131
10.5k
    if (CUR != ']') {
9132
201
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9133
0
    }
9134
9135
10.3k
    if (filter)
9136
5.05k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9137
5.25k
    else
9138
5.25k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9139
9140
10.3k
    NEXT;
9141
10.3k
    SKIP_BLANKS;
9142
10.3k
}
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
1.90M
         xmlChar *name) {
9170
1.90M
    int blanks;
9171
9172
1.90M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9173
0
  return(NULL);
9174
0
    }
9175
1.90M
    *type = (xmlXPathTypeVal) 0;
9176
1.90M
    *test = (xmlXPathTestVal) 0;
9177
1.90M
    *prefix = NULL;
9178
1.90M
    SKIP_BLANKS;
9179
9180
1.90M
    if ((name == NULL) && (CUR == '*')) {
9181
  /*
9182
   * All elements
9183
   */
9184
1.80M
  NEXT;
9185
1.80M
  *test = NODE_TEST_ALL;
9186
1.80M
  return(NULL);
9187
1.80M
    }
9188
9189
101k
    if (name == NULL)
9190
4.46k
  name = xmlXPathParseNCName(ctxt);
9191
101k
    if (name == NULL) {
9192
240
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9193
0
    }
9194
9195
100k
    blanks = IS_BLANK_CH(CUR);
9196
100k
    SKIP_BLANKS;
9197
100k
    if (CUR == '(') {
9198
1.02k
  NEXT;
9199
  /*
9200
   * NodeType or PI search
9201
   */
9202
1.02k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9203
9
      *type = NODE_TYPE_COMMENT;
9204
1.01k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9205
78
      *type = NODE_TYPE_NODE;
9206
941
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9207
132
      *type = NODE_TYPE_PI;
9208
809
  else if (xmlStrEqual(name, BAD_CAST "text"))
9209
739
      *type = NODE_TYPE_TEXT;
9210
70
  else {
9211
70
      if (name != NULL)
9212
70
    xmlFree(name);
9213
70
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9214
0
  }
9215
9216
958
  *test = NODE_TEST_TYPE;
9217
9218
958
  SKIP_BLANKS;
9219
958
  if (*type == NODE_TYPE_PI) {
9220
      /*
9221
       * Specific case: search a PI by name.
9222
       */
9223
132
      if (name != NULL)
9224
132
    xmlFree(name);
9225
132
      name = NULL;
9226
132
      if (CUR != ')') {
9227
108
    name = xmlXPathParseLiteral(ctxt);
9228
108
    *test = NODE_TEST_PI;
9229
108
    SKIP_BLANKS;
9230
108
      }
9231
132
  }
9232
958
  if (CUR != ')') {
9233
65
      if (name != NULL)
9234
51
    xmlFree(name);
9235
65
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9236
0
  }
9237
893
  NEXT;
9238
893
  return(name);
9239
958
    }
9240
99.8k
    *test = NODE_TEST_NAME;
9241
99.8k
    if ((!blanks) && (CUR == ':')) {
9242
4.63k
  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
4.63k
  *prefix = name;
9252
9253
4.63k
  if (CUR == '*') {
9254
      /*
9255
       * All elements
9256
       */
9257
640
      NEXT;
9258
640
      *test = NODE_TEST_ALL;
9259
640
      return(NULL);
9260
640
  }
9261
9262
3.99k
  name = xmlXPathParseNCName(ctxt);
9263
3.99k
  if (name == NULL) {
9264
60
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9265
0
  }
9266
3.99k
    }
9267
99.1k
    return(name);
9268
99.8k
}
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
99.4k
xmlXPathIsAxisName(const xmlChar *name) {
9290
99.4k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9291
99.4k
    switch (name[0]) {
9292
15.3k
  case 'a':
9293
15.3k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9294
1.77k
    ret = AXIS_ANCESTOR;
9295
15.3k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9296
477
    ret = AXIS_ANCESTOR_OR_SELF;
9297
15.3k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9298
69
    ret = AXIS_ATTRIBUTE;
9299
15.3k
      break;
9300
2.30k
  case 'c':
9301
2.30k
      if (xmlStrEqual(name, BAD_CAST "child"))
9302
66
    ret = AXIS_CHILD;
9303
2.30k
      break;
9304
1.80k
  case 'd':
9305
1.80k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9306
199
    ret = AXIS_DESCENDANT;
9307
1.80k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9308
10
    ret = AXIS_DESCENDANT_OR_SELF;
9309
1.80k
      break;
9310
1.43k
  case 'f':
9311
1.43k
      if (xmlStrEqual(name, BAD_CAST "following"))
9312
341
    ret = AXIS_FOLLOWING;
9313
1.43k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9314
34
    ret = AXIS_FOLLOWING_SIBLING;
9315
1.43k
      break;
9316
3.40k
  case 'n':
9317
3.40k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9318
15
    ret = AXIS_NAMESPACE;
9319
3.40k
      break;
9320
1.78k
  case 'p':
9321
1.78k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9322
426
    ret = AXIS_PARENT;
9323
1.78k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9324
26
    ret = AXIS_PRECEDING;
9325
1.78k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9326
15
    ret = AXIS_PRECEDING_SIBLING;
9327
1.78k
      break;
9328
4.04k
  case 's':
9329
4.04k
      if (xmlStrEqual(name, BAD_CAST "self"))
9330
1.29k
    ret = AXIS_SELF;
9331
4.04k
      break;
9332
99.4k
    }
9333
99.4k
    return(ret);
9334
99.4k
}
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
1.92M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9359
1.92M
    SKIP_BLANKS;
9360
1.92M
    if ((CUR == '.') && (NXT(1) == '.')) {
9361
7.95k
  SKIP(2);
9362
7.95k
  SKIP_BLANKS;
9363
7.95k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9364
7.95k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9365
1.91M
    } else if (CUR == '.') {
9366
14.4k
  NEXT;
9367
14.4k
  SKIP_BLANKS;
9368
1.90M
    } else {
9369
1.90M
  xmlChar *name = NULL;
9370
1.90M
  xmlChar *prefix = NULL;
9371
1.90M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9372
1.90M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9373
1.90M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9374
1.90M
  int op1;
9375
9376
1.90M
  if (CUR == '*') {
9377
1.80M
      axis = AXIS_CHILD;
9378
1.80M
  } else {
9379
102k
      if (name == NULL)
9380
102k
    name = xmlXPathParseNCName(ctxt);
9381
102k
      if (name != NULL) {
9382
99.4k
    axis = xmlXPathIsAxisName(name);
9383
99.4k
    if (axis != 0) {
9384
4.75k
        SKIP_BLANKS;
9385
4.75k
        if ((CUR == ':') && (NXT(1) == ':')) {
9386
2.42k
      SKIP(2);
9387
2.42k
      xmlFree(name);
9388
2.42k
      name = NULL;
9389
2.42k
        } else {
9390
      /* an element name can conflict with an axis one :-\ */
9391
2.32k
      axis = AXIS_CHILD;
9392
2.32k
        }
9393
94.6k
    } else {
9394
94.6k
        axis = AXIS_CHILD;
9395
94.6k
    }
9396
99.4k
      } else if (CUR == '@') {
9397
2.41k
    NEXT;
9398
2.41k
    axis = AXIS_ATTRIBUTE;
9399
2.41k
      } else {
9400
543
    axis = AXIS_CHILD;
9401
543
      }
9402
102k
  }
9403
9404
1.90M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9405
634
            xmlFree(name);
9406
634
            return;
9407
634
        }
9408
9409
1.90M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9410
1.90M
  if (test == 0)
9411
310
      return;
9412
9413
1.90M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9414
4.63k
      (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
1.90M
  op1 = ctxt->comp->last;
9422
1.90M
  ctxt->comp->last = -1;
9423
9424
1.90M
  SKIP_BLANKS;
9425
1.91M
  while (CUR == '[') {
9426
7.73k
      xmlXPathCompPredicate(ctxt, 0);
9427
7.73k
  }
9428
9429
1.90M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9430
1.90M
                           test, type, (void *)prefix, (void *)name) == -1) {
9431
35
            xmlFree(prefix);
9432
35
            xmlFree(name);
9433
35
        }
9434
1.90M
    }
9435
1.92M
}
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
1.89M
(xmlXPathParserContextPtr ctxt) {
9450
1.89M
    SKIP_BLANKS;
9451
1.89M
    if ((CUR == '/') && (NXT(1) == '/')) {
9452
3.69k
  SKIP(2);
9453
3.69k
  SKIP_BLANKS;
9454
3.69k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9455
3.69k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9456
1.89M
    } else if (CUR == '/') {
9457
3.55k
      NEXT;
9458
3.55k
  SKIP_BLANKS;
9459
3.55k
    }
9460
1.89M
    xmlXPathCompStep(ctxt);
9461
1.89M
    CHECK_ERROR;
9462
1.89M
    SKIP_BLANKS;
9463
1.92M
    while (CUR == '/') {
9464
28.1k
  if ((CUR == '/') && (NXT(1) == '/')) {
9465
4.93k
      SKIP(2);
9466
4.93k
      SKIP_BLANKS;
9467
4.93k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9468
4.93k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9469
4.93k
      xmlXPathCompStep(ctxt);
9470
23.1k
  } else if (CUR == '/') {
9471
23.1k
      NEXT;
9472
23.1k
      SKIP_BLANKS;
9473
23.1k
      xmlXPathCompStep(ctxt);
9474
23.1k
  }
9475
28.1k
  SKIP_BLANKS;
9476
28.1k
    }
9477
1.89M
}
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
1.89M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9493
1.89M
    SKIP_BLANKS;
9494
1.89M
    if (CUR != '/') {
9495
1.81M
        xmlXPathCompRelativeLocationPath(ctxt);
9496
1.81M
    } else {
9497
164k
  while (CUR == '/') {
9498
84.4k
      if ((CUR == '/') && (NXT(1) == '/')) {
9499
9.33k
    SKIP(2);
9500
9.33k
    SKIP_BLANKS;
9501
9.33k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9502
9.33k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9503
9.33k
    xmlXPathCompRelativeLocationPath(ctxt);
9504
75.0k
      } else if (CUR == '/') {
9505
75.0k
    NEXT;
9506
75.0k
    SKIP_BLANKS;
9507
75.0k
    if ((CUR != 0) &&
9508
74.2k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9509
66.6k
                     (CUR == '_') || (CUR == '.') ||
9510
61.5k
         (CUR == '@') || (CUR == '*')))
9511
67.9k
        xmlXPathCompRelativeLocationPath(ctxt);
9512
75.0k
      }
9513
84.4k
      CHECK_ERROR;
9514
84.4k
  }
9515
80.5k
    }
9516
1.89M
}
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
86.0k
{
9546
86.0k
    xmlXPathContextPtr xpctxt;
9547
86.0k
    xmlNodePtr oldnode;
9548
86.0k
    xmlDocPtr olddoc;
9549
86.0k
    xmlXPathStepOpPtr filterOp;
9550
86.0k
    int oldcs, oldpp;
9551
86.0k
    int i, j, pos;
9552
9553
86.0k
    if ((set == NULL) || (set->nodeNr == 0))
9554
1.60k
        return;
9555
9556
    /*
9557
    * Check if the node set contains a sufficient number of nodes for
9558
    * the requested range.
9559
    */
9560
84.4k
    if (set->nodeNr < minPos) {
9561
1.92k
        xmlXPathNodeSetClear(set, hasNsNodes);
9562
1.92k
        return;
9563
1.92k
    }
9564
9565
82.4k
    xpctxt = ctxt->context;
9566
82.4k
    oldnode = xpctxt->node;
9567
82.4k
    olddoc = xpctxt->doc;
9568
82.4k
    oldcs = xpctxt->contextSize;
9569
82.4k
    oldpp = xpctxt->proximityPosition;
9570
82.4k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9571
9572
82.4k
    xpctxt->contextSize = set->nodeNr;
9573
9574
337k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9575
312k
        xmlNodePtr node = set->nodeTab[i];
9576
312k
        int res;
9577
9578
312k
        xpctxt->node = node;
9579
312k
        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
312k
        if ((node->type != XML_NAMESPACE_DECL) &&
9588
312k
            (node->doc != NULL))
9589
312k
            xpctxt->doc = node->doc;
9590
9591
312k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9592
9593
312k
        if (ctxt->error != XPATH_EXPRESSION_OK)
9594
768
            break;
9595
311k
        if (res < 0) {
9596
            /* Shouldn't happen */
9597
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9598
0
            break;
9599
0
        }
9600
9601
311k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9602
205k
            if (i != j) {
9603
537
                set->nodeTab[j] = node;
9604
537
                set->nodeTab[i] = NULL;
9605
537
            }
9606
9607
205k
            j += 1;
9608
205k
        } else {
9609
            /* Remove the entry from the initial node set. */
9610
106k
            set->nodeTab[i] = NULL;
9611
106k
            if (node->type == XML_NAMESPACE_DECL)
9612
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9613
106k
        }
9614
9615
311k
        if (res != 0) {
9616
205k
            if (pos == maxPos) {
9617
56.4k
                i += 1;
9618
56.4k
                break;
9619
56.4k
            }
9620
9621
149k
            pos += 1;
9622
149k
        }
9623
311k
    }
9624
9625
    /* Free remaining nodes. */
9626
82.4k
    if (hasNsNodes) {
9627
2.97k
        for (; i < set->nodeNr; i++) {
9628
329
            xmlNodePtr node = set->nodeTab[i];
9629
329
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9630
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9631
329
        }
9632
2.64k
    }
9633
9634
82.4k
    set->nodeNr = j;
9635
9636
    /* If too many elements were removed, shrink table to preserve memory. */
9637
82.4k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9638
7.94k
        (set->nodeNr < set->nodeMax / 2)) {
9639
4.22k
        xmlNodePtr *tmp;
9640
4.22k
        int nodeMax = set->nodeNr;
9641
9642
4.22k
        if (nodeMax < XML_NODESET_DEFAULT)
9643
4.10k
            nodeMax = XML_NODESET_DEFAULT;
9644
4.22k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9645
4.22k
                nodeMax * sizeof(xmlNodePtr));
9646
4.22k
        if (tmp == NULL) {
9647
1
            xmlXPathPErrMemory(ctxt);
9648
4.22k
        } else {
9649
4.22k
            set->nodeTab = tmp;
9650
4.22k
            set->nodeMax = nodeMax;
9651
4.22k
        }
9652
4.22k
    }
9653
9654
82.4k
    xpctxt->node = oldnode;
9655
82.4k
    xpctxt->doc = olddoc;
9656
82.4k
    xpctxt->contextSize = oldcs;
9657
82.4k
    xpctxt->proximityPosition = oldpp;
9658
82.4k
}
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
82.7k
{
9679
82.7k
    if (op->ch1 != -1) {
9680
1.03k
  xmlXPathCompExprPtr comp = ctxt->comp;
9681
  /*
9682
  * Process inner predicates first.
9683
  */
9684
1.03k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9685
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9686
0
  }
9687
1.03k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9688
1.03k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9689
1.03k
        ctxt->context->depth += 1;
9690
1.03k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9691
1.03k
                                    1, set->nodeNr, hasNsNodes);
9692
1.03k
        ctxt->context->depth -= 1;
9693
1.03k
  CHECK_ERROR;
9694
1.03k
    }
9695
9696
82.4k
    if (op->ch2 != -1)
9697
82.4k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9698
82.4k
}
9699
9700
static int
9701
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9702
          xmlXPathStepOpPtr op,
9703
          int *maxPos)
9704
30.7k
{
9705
9706
30.7k
    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
30.7k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9722
0
  return(0);
9723
9724
30.7k
    if (op->ch2 != -1) {
9725
30.7k
  exprOp = &ctxt->comp->steps[op->ch2];
9726
30.7k
    } else
9727
0
  return(0);
9728
9729
30.7k
    if ((exprOp != NULL) &&
9730
30.7k
  (exprOp->op == XPATH_OP_VALUE) &&
9731
4.83k
  (exprOp->value4 != NULL) &&
9732
4.83k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9733
4.77k
    {
9734
4.77k
        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
4.77k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9748
4.52k
      *maxPos = (int) floatval;
9749
4.52k
            if (floatval == (double) *maxPos)
9750
4.39k
                return(1);
9751
4.52k
        }
9752
4.77k
    }
9753
26.3k
    return(0);
9754
30.7k
}
9755
9756
static int
9757
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9758
                           xmlXPathStepOpPtr op,
9759
         xmlNodePtr * first, xmlNodePtr * last,
9760
         int toBool)
9761
1.01M
{
9762
9763
1.01M
#define XP_TEST_HIT \
9764
5.37M
    if (hasAxisRange != 0) { \
9765
277k
  if (++pos == maxPos) { \
9766
1.31k
      if (addNode(seq, cur) < 0) \
9767
1.31k
          xmlXPathPErrMemory(ctxt); \
9768
1.31k
      goto axis_range_end; } \
9769
5.09M
    } else { \
9770
5.09M
  if (addNode(seq, cur) < 0) \
9771
5.09M
      xmlXPathPErrMemory(ctxt); \
9772
5.09M
  if (breakOnFirstHit) goto first_hit; }
9773
9774
1.01M
#define XP_TEST_HIT_NS \
9775
1.01M
    if (hasAxisRange != 0) { \
9776
0
  if (++pos == maxPos) { \
9777
0
      hasNsNodes = 1; \
9778
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9779
0
          xmlXPathPErrMemory(ctxt); \
9780
0
  goto axis_range_end; } \
9781
0
    } else { \
9782
0
  hasNsNodes = 1; \
9783
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9784
0
      xmlXPathPErrMemory(ctxt); \
9785
0
  if (breakOnFirstHit) goto first_hit; }
9786
9787
1.01M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9788
1.01M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9789
1.01M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9790
1.01M
    const xmlChar *prefix = op->value4;
9791
1.01M
    const xmlChar *name = op->value5;
9792
1.01M
    const xmlChar *URI = NULL;
9793
9794
1.01M
    int total = 0, hasNsNodes = 0;
9795
    /* The popped object holding the context nodes */
9796
1.01M
    xmlXPathObjectPtr obj;
9797
    /* The set of context nodes for the node tests */
9798
1.01M
    xmlNodeSetPtr contextSeq;
9799
1.01M
    int contextIdx;
9800
1.01M
    xmlNodePtr contextNode;
9801
    /* The final resulting node set wrt to all context nodes */
9802
1.01M
    xmlNodeSetPtr outSeq;
9803
    /*
9804
    * The temporary resulting node set wrt 1 context node.
9805
    * Used to feed predicate evaluation.
9806
    */
9807
1.01M
    xmlNodeSetPtr seq;
9808
1.01M
    xmlNodePtr cur;
9809
    /* First predicate operator */
9810
1.01M
    xmlXPathStepOpPtr predOp;
9811
1.01M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9812
1.01M
    int hasPredicateRange, hasAxisRange, pos;
9813
1.01M
    int breakOnFirstHit;
9814
9815
1.01M
    xmlXPathTraversalFunction next = NULL;
9816
1.01M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9817
1.01M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9818
1.01M
    xmlNodePtr oldContextNode;
9819
1.01M
    xmlXPathContextPtr xpctxt = ctxt->context;
9820
9821
9822
1.01M
    CHECK_TYPE0(XPATH_NODESET);
9823
1.01M
    obj = xmlXPathValuePop(ctxt);
9824
    /*
9825
    * Setup namespaces.
9826
    */
9827
1.01M
    if (prefix != NULL) {
9828
12.2k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9829
12.2k
        if (URI == NULL) {
9830
211
      xmlXPathReleaseObject(xpctxt, obj);
9831
211
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9832
211
                           "Undefined namespace prefix: %s\n", prefix);
9833
211
            return 0;
9834
211
  }
9835
12.2k
    }
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
1.01M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9850
1.01M
    switch (axis) {
9851
668
        case AXIS_ANCESTOR:
9852
668
            first = NULL;
9853
668
            next = xmlXPathNextAncestor;
9854
668
            break;
9855
358
        case AXIS_ANCESTOR_OR_SELF:
9856
358
            first = NULL;
9857
358
            next = xmlXPathNextAncestorOrSelf;
9858
358
            break;
9859
18.4k
        case AXIS_ATTRIBUTE:
9860
18.4k
            first = NULL;
9861
18.4k
      last = NULL;
9862
18.4k
            next = xmlXPathNextAttribute;
9863
18.4k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9864
18.4k
            break;
9865
834k
        case AXIS_CHILD:
9866
834k
      last = NULL;
9867
834k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9868
831k
    (type == NODE_TYPE_NODE))
9869
831k
      {
9870
    /*
9871
    * Optimization if an element node type is 'element'.
9872
    */
9873
831k
    next = xmlXPathNextChildElement;
9874
831k
      } else
9875
3.34k
    next = xmlXPathNextChild;
9876
834k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9877
834k
            break;
9878
12.7k
        case AXIS_DESCENDANT:
9879
12.7k
      last = NULL;
9880
12.7k
            next = xmlXPathNextDescendant;
9881
12.7k
            break;
9882
99.8k
        case AXIS_DESCENDANT_OR_SELF:
9883
99.8k
      last = NULL;
9884
99.8k
            next = xmlXPathNextDescendantOrSelf;
9885
99.8k
            break;
9886
200
        case AXIS_FOLLOWING:
9887
200
      last = NULL;
9888
200
            next = xmlXPathNextFollowing;
9889
200
            break;
9890
0
        case AXIS_FOLLOWING_SIBLING:
9891
0
      last = NULL;
9892
0
            next = xmlXPathNextFollowingSibling;
9893
0
            break;
9894
3
        case AXIS_NAMESPACE:
9895
3
            first = NULL;
9896
3
      last = NULL;
9897
3
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9898
3
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9899
3
            break;
9900
52.2k
        case AXIS_PARENT:
9901
52.2k
            first = NULL;
9902
52.2k
            next = xmlXPathNextParent;
9903
52.2k
            break;
9904
0
        case AXIS_PRECEDING:
9905
0
            first = NULL;
9906
0
            next = xmlXPathNextPrecedingInternal;
9907
0
            break;
9908
3
        case AXIS_PRECEDING_SIBLING:
9909
3
            first = NULL;
9910
3
            next = xmlXPathNextPrecedingSibling;
9911
3
            break;
9912
495
        case AXIS_SELF:
9913
495
            first = NULL;
9914
495
      last = NULL;
9915
495
            next = xmlXPathNextSelf;
9916
495
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9917
495
            break;
9918
1.01M
    }
9919
9920
1.01M
    if (next == NULL) {
9921
0
  xmlXPathReleaseObject(xpctxt, obj);
9922
0
        return(0);
9923
0
    }
9924
1.01M
    contextSeq = obj->nodesetval;
9925
1.01M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9926
93.4k
        xmlXPathValuePush(ctxt, obj);
9927
93.4k
        return(0);
9928
93.4k
    }
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
926k
    maxPos = 0;
9948
926k
    predOp = NULL;
9949
926k
    hasPredicateRange = 0;
9950
926k
    hasAxisRange = 0;
9951
926k
    if (op->ch2 != -1) {
9952
  /*
9953
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9954
  */
9955
30.7k
  predOp = &ctxt->comp->steps[op->ch2];
9956
30.7k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9957
4.39k
      if (predOp->ch1 != -1) {
9958
    /*
9959
    * Use the next inner predicate operator.
9960
    */
9961
151
    predOp = &ctxt->comp->steps[predOp->ch1];
9962
151
    hasPredicateRange = 1;
9963
4.23k
      } else {
9964
    /*
9965
    * There's no other predicate than the [n] predicate.
9966
    */
9967
4.23k
    predOp = NULL;
9968
4.23k
    hasAxisRange = 1;
9969
4.23k
      }
9970
4.39k
  }
9971
30.7k
    }
9972
926k
    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
926k
    oldContextNode = xpctxt->node;
9987
926k
    addNode = xmlXPathNodeSetAddUnique;
9988
926k
    outSeq = NULL;
9989
926k
    seq = NULL;
9990
926k
    contextNode = NULL;
9991
926k
    contextIdx = 0;
9992
9993
9994
3.38M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
9995
2.46M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
9996
2.46M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
9997
9998
2.46M
  if (seq == NULL) {
9999
946k
      seq = xmlXPathNodeSetCreate(NULL);
10000
946k
      if (seq == NULL) {
10001
107
                xmlXPathPErrMemory(ctxt);
10002
107
    total = 0;
10003
107
    goto error;
10004
107
      }
10005
946k
  }
10006
  /*
10007
  * Traverse the axis and test the nodes.
10008
  */
10009
2.46M
  pos = 0;
10010
2.46M
  cur = NULL;
10011
2.46M
  hasNsNodes = 0;
10012
10.1M
        do {
10013
10.1M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10014
47
                goto error;
10015
10016
10.1M
            cur = next(ctxt, cur);
10017
10.1M
            if (cur == NULL)
10018
2.45M
                break;
10019
10020
      /*
10021
      * QUESTION TODO: What does the "first" and "last" stuff do?
10022
      */
10023
7.67M
            if ((first != NULL) && (*first != NULL)) {
10024
5.33k
    if (*first == cur)
10025
612
        break;
10026
4.72k
    if (((total % 256) == 0) &&
10027
4.69k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10028
4.69k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10029
#else
10030
        (xmlXPathCmpNodes(*first, cur) >= 0))
10031
#endif
10032
4.61k
    {
10033
4.61k
        break;
10034
4.61k
    }
10035
4.72k
      }
10036
7.66M
      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
7.66M
            total++;
10051
10052
7.66M
      switch (test) {
10053
0
                case NODE_TEST_NONE:
10054
0
        total = 0;
10055
0
        goto error;
10056
4.20M
                case NODE_TEST_TYPE:
10057
4.20M
        if (type == NODE_TYPE_NODE) {
10058
3.67M
      switch (cur->type) {
10059
64.2k
          case XML_DOCUMENT_NODE:
10060
64.2k
          case XML_HTML_DOCUMENT_NODE:
10061
2.73M
          case XML_ELEMENT_NODE:
10062
2.73M
          case XML_ATTRIBUTE_NODE:
10063
2.81M
          case XML_PI_NODE:
10064
2.82M
          case XML_COMMENT_NODE:
10065
2.90M
          case XML_CDATA_SECTION_NODE:
10066
3.67M
          case XML_TEXT_NODE:
10067
3.67M
        XP_TEST_HIT
10068
3.67M
        break;
10069
3.67M
          case XML_NAMESPACE_DECL: {
10070
0
        if (axis == AXIS_NAMESPACE) {
10071
0
            XP_TEST_HIT_NS
10072
0
        } else {
10073
0
                              hasNsNodes = 1;
10074
0
            XP_TEST_HIT
10075
0
        }
10076
0
        break;
10077
0
                            }
10078
348
          default:
10079
348
        break;
10080
3.67M
      }
10081
3.67M
        } else if (cur->type == (xmlElementType) type) {
10082
246k
      if (cur->type == XML_NAMESPACE_DECL)
10083
0
          XP_TEST_HIT_NS
10084
246k
      else
10085
246k
          XP_TEST_HIT
10086
284k
        } else if ((type == NODE_TYPE_TEXT) &&
10087
284k
       (cur->type == XML_CDATA_SECTION_NODE))
10088
36.8k
        {
10089
36.8k
      XP_TEST_HIT
10090
36.8k
        }
10091
4.20M
        break;
10092
4.20M
                case NODE_TEST_PI:
10093
151
                    if ((cur->type == XML_PI_NODE) &&
10094
71
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10095
35
        {
10096
35
      XP_TEST_HIT
10097
35
                    }
10098
151
                    break;
10099
979k
                case NODE_TEST_ALL:
10100
979k
                    if (axis == AXIS_ATTRIBUTE) {
10101
9.39k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10102
9.39k
      {
10103
9.39k
                            if (prefix == NULL)
10104
8.49k
          {
10105
8.49k
        XP_TEST_HIT
10106
8.49k
                            } else if ((cur->ns != NULL) &&
10107
705
        (xmlStrEqual(URI, cur->ns->href)))
10108
705
          {
10109
705
        XP_TEST_HIT
10110
705
                            }
10111
9.39k
                        }
10112
970k
                    } else if (axis == AXIS_NAMESPACE) {
10113
0
                        if (cur->type == XML_NAMESPACE_DECL)
10114
0
      {
10115
0
          XP_TEST_HIT_NS
10116
0
                        }
10117
970k
                    } else {
10118
970k
                        if (cur->type == XML_ELEMENT_NODE) {
10119
953k
                            if (prefix == NULL)
10120
947k
          {
10121
947k
        XP_TEST_HIT
10122
10123
947k
                            } else if ((cur->ns != NULL) &&
10124
841
        (xmlStrEqual(URI, cur->ns->href)))
10125
404
          {
10126
404
        XP_TEST_HIT
10127
404
                            }
10128
953k
                        }
10129
970k
                    }
10130
978k
                    break;
10131
978k
                case NODE_TEST_NS:{
10132
                        /* TODO */
10133
0
                        break;
10134
979k
                    }
10135
2.48M
                case NODE_TEST_NAME:
10136
2.48M
                    if (axis == AXIS_ATTRIBUTE) {
10137
2.26k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10138
0
          break;
10139
2.48M
        } else if (axis == AXIS_NAMESPACE) {
10140
0
                        if (cur->type != XML_NAMESPACE_DECL)
10141
0
          break;
10142
2.48M
        } else {
10143
2.48M
            if (cur->type != XML_ELEMENT_NODE)
10144
519k
          break;
10145
2.48M
        }
10146
1.96M
                    switch (cur->type) {
10147
1.96M
                        case XML_ELEMENT_NODE:
10148
1.96M
                            if (xmlStrEqual(name, cur->name)) {
10149
468k
                                if (prefix == NULL) {
10150
463k
                                    if (cur->ns == NULL)
10151
463k
            {
10152
463k
          XP_TEST_HIT
10153
463k
                                    }
10154
463k
                                } else {
10155
4.91k
                                    if ((cur->ns != NULL) &&
10156
327
                                        (xmlStrEqual(URI, cur->ns->href)))
10157
11
            {
10158
11
          XP_TEST_HIT
10159
11
                                    }
10160
4.91k
                                }
10161
468k
                            }
10162
1.96M
                            break;
10163
1.96M
                        case XML_ATTRIBUTE_NODE:{
10164
2.26k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10165
10166
2.26k
                                if (xmlStrEqual(name, attr->name)) {
10167
327
                                    if (prefix == NULL) {
10168
111
                                        if ((attr->ns == NULL) ||
10169
6
                                            (attr->ns->prefix == NULL))
10170
105
          {
10171
105
              XP_TEST_HIT
10172
105
                                        }
10173
216
                                    } else {
10174
216
                                        if ((attr->ns != NULL) &&
10175
2
                                            (xmlStrEqual(URI,
10176
2
                attr->ns->href)))
10177
2
          {
10178
2
              XP_TEST_HIT
10179
2
                                        }
10180
216
                                    }
10181
327
                                }
10182
2.25k
                                break;
10183
2.26k
                            }
10184
2.25k
                        case XML_NAMESPACE_DECL:
10185
0
                            if (cur->type == XML_NAMESPACE_DECL) {
10186
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
10187
10188
0
                                if ((ns->prefix != NULL) && (name != NULL)
10189
0
                                    && (xmlStrEqual(ns->prefix, name)))
10190
0
        {
10191
0
            XP_TEST_HIT_NS
10192
0
                                }
10193
0
                            }
10194
0
                            break;
10195
0
                        default:
10196
0
                            break;
10197
1.96M
                    }
10198
1.96M
                    break;
10199
7.66M
      } /* switch(test) */
10200
7.66M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10201
10202
2.46M
  goto apply_predicates;
10203
10204
2.46M
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
1.31k
  if (outSeq == NULL) {
10212
639
      outSeq = seq;
10213
639
      seq = NULL;
10214
678
  } else {
10215
678
      outSeq = mergeAndClear(outSeq, seq);
10216
678
            if (outSeq == NULL)
10217
1
                xmlXPathPErrMemory(ctxt);
10218
678
        }
10219
  /*
10220
  * Break if only a true/false result was requested.
10221
  */
10222
1.31k
  if (toBool)
10223
351
      break;
10224
966
  continue;
10225
10226
1.08k
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
1.08k
  if (outSeq == NULL) {
10232
1.08k
      outSeq = seq;
10233
1.08k
      seq = NULL;
10234
1.08k
  } else {
10235
0
      outSeq = mergeAndClear(outSeq, seq);
10236
0
            if (outSeq == NULL)
10237
0
                xmlXPathPErrMemory(ctxt);
10238
0
        }
10239
1.08k
  break;
10240
10241
2.46M
apply_predicates: /* --------------------------------------------------- */
10242
2.46M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10243
126
      goto error;
10244
10245
        /*
10246
  * Apply predicates.
10247
  */
10248
2.46M
        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
81.7k
      if (hasPredicateRange != 0)
10278
4.36k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10279
4.36k
              hasNsNodes);
10280
77.3k
      else
10281
77.3k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10282
77.3k
              hasNsNodes);
10283
10284
81.7k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10285
738
    total = 0;
10286
738
    goto error;
10287
738
      }
10288
81.7k
        }
10289
10290
2.46M
        if (seq->nodeNr > 0) {
10291
      /*
10292
      * Add to result set.
10293
      */
10294
854k
      if (outSeq == NULL) {
10295
205k
    outSeq = seq;
10296
205k
    seq = NULL;
10297
648k
      } else {
10298
648k
    outSeq = mergeAndClear(outSeq, seq);
10299
648k
                if (outSeq == NULL)
10300
58
                    xmlXPathPErrMemory(ctxt);
10301
648k
      }
10302
10303
854k
            if (toBool)
10304
440
                break;
10305
854k
  }
10306
2.46M
    }
10307
10308
926k
error:
10309
926k
    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
926k
    xmlXPathReleaseObject(xpctxt, obj);
10321
10322
    /*
10323
    * Ensure we return at least an empty set.
10324
    */
10325
926k
    if (outSeq == NULL) {
10326
718k
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10327
718k
      outSeq = seq;
10328
718k
        } else {
10329
212
      outSeq = xmlXPathNodeSetCreate(NULL);
10330
212
            if (outSeq == NULL)
10331
1
                xmlXPathPErrMemory(ctxt);
10332
212
        }
10333
718k
    }
10334
926k
    if ((seq != NULL) && (seq != outSeq)) {
10335
20.7k
   xmlXPathFreeNodeSet(seq);
10336
20.7k
    }
10337
    /*
10338
    * Hand over the result. Better to push the set also in
10339
    * case of errors.
10340
    */
10341
926k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10342
    /*
10343
    * Reset the context node.
10344
    */
10345
926k
    xpctxt->node = oldContextNode;
10346
    /*
10347
    * When traversing the namespace axis in "toBool" mode, it's
10348
    * possible that tmpNsList wasn't freed.
10349
    */
10350
926k
    if (xpctxt->tmpNsList != NULL) {
10351
0
        xmlFree(xpctxt->tmpNsList);
10352
0
        xpctxt->tmpNsList = NULL;
10353
0
    }
10354
10355
926k
    return(total);
10356
926k
}
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
16.3k
{
10375
16.3k
    int total = 0, cur;
10376
16.3k
    xmlXPathCompExprPtr comp;
10377
16.3k
    xmlXPathObjectPtr arg1, arg2;
10378
10379
16.3k
    CHECK_ERROR0;
10380
16.3k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10381
0
        return(0);
10382
16.3k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10383
16.3k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10384
16.3k
    ctxt->context->depth += 1;
10385
16.3k
    comp = ctxt->comp;
10386
16.3k
    switch (op->op) {
10387
0
        case XPATH_OP_END:
10388
0
            break;
10389
6.22k
        case XPATH_OP_UNION:
10390
6.22k
            total =
10391
6.22k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10392
6.22k
                                        first);
10393
6.22k
      CHECK_ERROR0;
10394
5.95k
            if ((ctxt->value != NULL)
10395
5.95k
                && (ctxt->value->type == XPATH_NODESET)
10396
5.95k
                && (ctxt->value->nodesetval != NULL)
10397
5.95k
                && (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
5.61k
    if (ctxt->value->nodesetval->nodeNr > 1)
10409
4.42k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10410
5.61k
                *first = ctxt->value->nodesetval->nodeTab[0];
10411
5.61k
            }
10412
5.95k
            cur =
10413
5.95k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10414
5.95k
                                        first);
10415
5.95k
      CHECK_ERROR0;
10416
10417
5.93k
            arg2 = xmlXPathValuePop(ctxt);
10418
5.93k
            arg1 = xmlXPathValuePop(ctxt);
10419
5.93k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10420
5.93k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10421
2
          xmlXPathReleaseObject(ctxt->context, arg1);
10422
2
          xmlXPathReleaseObject(ctxt->context, arg2);
10423
2
                XP_ERROR0(XPATH_INVALID_TYPE);
10424
0
            }
10425
5.93k
            if ((ctxt->context->opLimit != 0) &&
10426
5.93k
                (((arg1->nodesetval != NULL) &&
10427
5.93k
                  (xmlXPathCheckOpLimit(ctxt,
10428
5.93k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10429
5.93k
                 ((arg2->nodesetval != NULL) &&
10430
5.93k
                  (xmlXPathCheckOpLimit(ctxt,
10431
5.93k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10432
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10433
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10434
0
                break;
10435
0
            }
10436
10437
5.93k
            if ((arg2->nodesetval != NULL) &&
10438
5.93k
                (arg2->nodesetval->nodeNr != 0)) {
10439
404
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10440
404
                                                        arg2->nodesetval);
10441
404
                if (arg1->nodesetval == NULL)
10442
4
                    xmlXPathPErrMemory(ctxt);
10443
404
            }
10444
5.93k
            xmlXPathValuePush(ctxt, arg1);
10445
5.93k
      xmlXPathReleaseObject(ctxt->context, arg2);
10446
5.93k
            total += cur;
10447
5.93k
            break;
10448
880
        case XPATH_OP_ROOT:
10449
880
            xmlXPathRoot(ctxt);
10450
880
            break;
10451
367
        case XPATH_OP_NODE:
10452
367
            if (op->ch1 != -1)
10453
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10454
367
      CHECK_ERROR0;
10455
367
            if (op->ch2 != -1)
10456
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10457
367
      CHECK_ERROR0;
10458
367
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10459
367
    ctxt->context->node));
10460
367
            break;
10461
6.05k
        case XPATH_OP_COLLECT:{
10462
6.05k
                if (op->ch1 == -1)
10463
0
                    break;
10464
10465
6.05k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10466
6.05k
    CHECK_ERROR0;
10467
10468
6.04k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10469
6.04k
                break;
10470
6.05k
            }
10471
3
        case XPATH_OP_VALUE:
10472
3
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10473
3
            break;
10474
1.50k
        case XPATH_OP_SORT:
10475
1.50k
            if (op->ch1 != -1)
10476
1.50k
                total +=
10477
1.50k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10478
1.50k
                                            first);
10479
1.50k
      CHECK_ERROR0;
10480
1.45k
            if ((ctxt->value != NULL)
10481
1.45k
                && (ctxt->value->type == XPATH_NODESET)
10482
1.45k
                && (ctxt->value->nodesetval != NULL)
10483
1.45k
    && (ctxt->value->nodesetval->nodeNr > 1))
10484
166
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10485
1.45k
            break;
10486
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10487
1.35k
  case XPATH_OP_FILTER:
10488
1.35k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10489
1.35k
            break;
10490
0
#endif
10491
12
        default:
10492
12
            total += xmlXPathCompOpEval(ctxt, op);
10493
12
            break;
10494
16.3k
    }
10495
10496
16.0k
    ctxt->context->depth -= 1;
10497
16.0k
    return(total);
10498
16.3k
}
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
1.35k
{
10637
1.35k
    int total = 0;
10638
1.35k
    xmlXPathCompExprPtr comp;
10639
1.35k
    xmlXPathObjectPtr obj;
10640
1.35k
    xmlNodeSetPtr set;
10641
10642
1.35k
    CHECK_ERROR0;
10643
1.35k
    comp = ctxt->comp;
10644
    /*
10645
    * Optimization for ()[last()] selection i.e. the last elem
10646
    */
10647
1.35k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10648
1.35k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10649
174
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10650
100
  int f = comp->steps[op->ch2].ch1;
10651
10652
100
  if ((f != -1) &&
10653
100
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10654
0
      (comp->steps[f].value5 == NULL) &&
10655
0
      (comp->steps[f].value == 0) &&
10656
0
      (comp->steps[f].value4 != NULL) &&
10657
0
      (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
100
    }
10681
10682
1.35k
    if (op->ch1 != -1)
10683
1.35k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10684
1.35k
    CHECK_ERROR0;
10685
591
    if (op->ch2 == -1)
10686
0
  return (total);
10687
591
    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
591
    CHECK_TYPE0(XPATH_NODESET);
10696
585
    obj = xmlXPathValuePop(ctxt);
10697
585
    set = obj->nodesetval;
10698
585
    if (set != NULL) {
10699
585
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10700
585
        if (set->nodeNr > 0)
10701
68
            *first = set->nodeTab[0];
10702
585
    }
10703
585
    xmlXPathValuePush(ctxt, obj);
10704
10705
585
    return (total);
10706
591
}
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
3.26M
{
10719
3.26M
    int total = 0;
10720
3.26M
    int equal, ret;
10721
3.26M
    xmlXPathCompExprPtr comp;
10722
3.26M
    xmlXPathObjectPtr arg1, arg2;
10723
10724
3.26M
    CHECK_ERROR0;
10725
3.26M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10726
46
        return(0);
10727
3.26M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10728
3.26M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10729
3.26M
    ctxt->context->depth += 1;
10730
3.26M
    comp = ctxt->comp;
10731
3.26M
    switch (op->op) {
10732
0
        case XPATH_OP_END:
10733
0
            break;
10734
1.20k
        case XPATH_OP_AND:
10735
1.20k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10736
1.20k
      CHECK_ERROR0;
10737
899
            xmlXPathBooleanFunction(ctxt, 1);
10738
899
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10739
279
                break;
10740
620
            arg2 = xmlXPathValuePop(ctxt);
10741
620
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10742
620
      if (ctxt->error) {
10743
24
    xmlXPathFreeObject(arg2);
10744
24
    break;
10745
24
      }
10746
596
            xmlXPathBooleanFunction(ctxt, 1);
10747
596
            if (ctxt->value != NULL)
10748
595
                ctxt->value->boolval &= arg2->boolval;
10749
596
      xmlXPathReleaseObject(ctxt->context, arg2);
10750
596
            break;
10751
2.43k
        case XPATH_OP_OR:
10752
2.43k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10753
2.43k
      CHECK_ERROR0;
10754
1.73k
            xmlXPathBooleanFunction(ctxt, 1);
10755
1.73k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10756
227
                break;
10757
1.50k
            arg2 = xmlXPathValuePop(ctxt);
10758
1.50k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10759
1.50k
      if (ctxt->error) {
10760
141
    xmlXPathFreeObject(arg2);
10761
141
    break;
10762
141
      }
10763
1.36k
            xmlXPathBooleanFunction(ctxt, 1);
10764
1.36k
            if (ctxt->value != NULL)
10765
1.35k
                ctxt->value->boolval |= arg2->boolval;
10766
1.36k
      xmlXPathReleaseObject(ctxt->context, arg2);
10767
1.36k
            break;
10768
356k
        case XPATH_OP_EQUAL:
10769
356k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10770
356k
      CHECK_ERROR0;
10771
349k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10772
349k
      CHECK_ERROR0;
10773
348k
      if (op->value)
10774
342k
    equal = xmlXPathEqualValues(ctxt);
10775
5.69k
      else
10776
5.69k
    equal = xmlXPathNotEqualValues(ctxt);
10777
348k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10778
348k
            break;
10779
185k
        case XPATH_OP_CMP:
10780
185k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10781
185k
      CHECK_ERROR0;
10782
184k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10783
184k
      CHECK_ERROR0;
10784
183k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10785
183k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10786
183k
            break;
10787
249k
        case XPATH_OP_PLUS:
10788
249k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10789
249k
      CHECK_ERROR0;
10790
241k
            if (op->ch2 != -1) {
10791
124k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10792
124k
      }
10793
241k
      CHECK_ERROR0;
10794
240k
            if (op->value == 0)
10795
37.1k
                xmlXPathSubValues(ctxt);
10796
203k
            else if (op->value == 1)
10797
86.7k
                xmlXPathAddValues(ctxt);
10798
116k
            else if (op->value == 2)
10799
105k
                xmlXPathValueFlipSign(ctxt);
10800
10.8k
            else if (op->value == 3) {
10801
10.8k
                CAST_TO_NUMBER;
10802
10.8k
                CHECK_TYPE0(XPATH_NUMBER);
10803
10.8k
            }
10804
240k
            break;
10805
240k
        case XPATH_OP_MULT:
10806
129k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10807
129k
      CHECK_ERROR0;
10808
120k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10809
120k
      CHECK_ERROR0;
10810
120k
            if (op->value == 0)
10811
117k
                xmlXPathMultValues(ctxt);
10812
2.34k
            else if (op->value == 1)
10813
1.52k
                xmlXPathDivValues(ctxt);
10814
821
            else if (op->value == 2)
10815
821
                xmlXPathModValues(ctxt);
10816
120k
            break;
10817
91.6k
        case XPATH_OP_UNION:
10818
91.6k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10819
91.6k
      CHECK_ERROR0;
10820
91.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10821
91.0k
      CHECK_ERROR0;
10822
10823
90.8k
            arg2 = xmlXPathValuePop(ctxt);
10824
90.8k
            arg1 = xmlXPathValuePop(ctxt);
10825
90.8k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10826
90.7k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10827
62
          xmlXPathReleaseObject(ctxt->context, arg1);
10828
62
          xmlXPathReleaseObject(ctxt->context, arg2);
10829
62
                XP_ERROR0(XPATH_INVALID_TYPE);
10830
0
            }
10831
90.7k
            if ((ctxt->context->opLimit != 0) &&
10832
90.7k
                (((arg1->nodesetval != NULL) &&
10833
90.7k
                  (xmlXPathCheckOpLimit(ctxt,
10834
90.7k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10835
90.7k
                 ((arg2->nodesetval != NULL) &&
10836
90.7k
                  (xmlXPathCheckOpLimit(ctxt,
10837
90.7k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10838
15
          xmlXPathReleaseObject(ctxt->context, arg1);
10839
15
          xmlXPathReleaseObject(ctxt->context, arg2);
10840
15
                break;
10841
15
            }
10842
10843
90.7k
      if (((arg2->nodesetval != NULL) &&
10844
90.7k
     (arg2->nodesetval->nodeNr != 0)))
10845
49.5k
      {
10846
49.5k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10847
49.5k
              arg2->nodesetval);
10848
49.5k
                if (arg1->nodesetval == NULL)
10849
13
                    xmlXPathPErrMemory(ctxt);
10850
49.5k
      }
10851
10852
90.7k
            xmlXPathValuePush(ctxt, arg1);
10853
90.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
10854
90.7k
            break;
10855
264k
        case XPATH_OP_ROOT:
10856
264k
            xmlXPathRoot(ctxt);
10857
264k
            break;
10858
781k
        case XPATH_OP_NODE:
10859
781k
            if (op->ch1 != -1)
10860
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10861
781k
      CHECK_ERROR0;
10862
781k
            if (op->ch2 != -1)
10863
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10864
781k
      CHECK_ERROR0;
10865
781k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10866
781k
                                                    ctxt->context->node));
10867
781k
            break;
10868
996k
        case XPATH_OP_COLLECT:{
10869
996k
                if (op->ch1 == -1)
10870
0
                    break;
10871
10872
996k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10873
996k
    CHECK_ERROR0;
10874
10875
995k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10876
995k
                break;
10877
996k
            }
10878
74.6k
        case XPATH_OP_VALUE:
10879
74.6k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10880
74.6k
            break;
10881
67
        case XPATH_OP_VARIABLE:{
10882
67
    xmlXPathObjectPtr val;
10883
10884
67
                if (op->ch1 != -1)
10885
0
                    total +=
10886
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10887
67
                if (op->value5 == NULL) {
10888
35
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10889
35
        if (val == NULL) {
10890
35
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10891
35
                                       "Undefined variable: %s\n", op->value4);
10892
35
                        return 0;
10893
35
                    }
10894
0
                    xmlXPathValuePush(ctxt, val);
10895
32
    } else {
10896
32
                    const xmlChar *URI;
10897
10898
32
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10899
32
                    if (URI == NULL) {
10900
8
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10901
8
                                       "Undefined namespace prefix: %s\n",
10902
8
                                       op->value5);
10903
8
                        return 0;
10904
8
                    }
10905
24
        val = xmlXPathVariableLookupNS(ctxt->context,
10906
24
                                                       op->value4, URI);
10907
24
        if (val == NULL) {
10908
24
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10909
24
                                       "Undefined variable: %s:%s\n",
10910
24
                                       op->value5, op->value4);
10911
24
                        return 0;
10912
24
                    }
10913
0
                    xmlXPathValuePush(ctxt, val);
10914
0
                }
10915
0
                break;
10916
67
            }
10917
27.9k
        case XPATH_OP_FUNCTION:{
10918
27.9k
                xmlXPathFunction func;
10919
27.9k
                const xmlChar *oldFunc, *oldFuncURI;
10920
27.9k
    int i;
10921
27.9k
                int frame;
10922
10923
27.9k
                frame = ctxt->valueNr;
10924
27.9k
                if (op->ch1 != -1) {
10925
25.7k
                    total +=
10926
25.7k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10927
25.7k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10928
774
                        break;
10929
25.7k
                }
10930
27.1k
    if (ctxt->valueNr < frame + op->value)
10931
27.1k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10932
54.4k
    for (i = 0; i < op->value; i++) {
10933
27.3k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10934
27.3k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10935
27.3k
                }
10936
27.1k
                if (op->cache != NULL)
10937
20.1k
                    func = op->cache;
10938
6.96k
                else {
10939
6.96k
                    const xmlChar *URI = NULL;
10940
10941
6.96k
                    if (op->value5 == NULL) {
10942
6.84k
                        func = xmlXPathFunctionLookup(ctxt->context,
10943
6.84k
                                                      op->value4);
10944
6.84k
                        if (func == NULL) {
10945
459
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10946
459
                                           "Unregistered function: %s\n",
10947
459
                                           op->value4);
10948
459
                            return 0;
10949
459
                        }
10950
6.84k
                    } else {
10951
118
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10952
118
                        if (URI == NULL) {
10953
104
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10954
104
                                           "Undefined namespace prefix: %s\n",
10955
104
                                           op->value5);
10956
104
                            return 0;
10957
104
                        }
10958
14
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10959
14
                                                        op->value4, URI);
10960
14
                        if (func == NULL) {
10961
14
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10962
14
                                           "Unregistered function: %s:%s\n",
10963
14
                                           op->value5, op->value4);
10964
14
                            return 0;
10965
14
                        }
10966
14
                    }
10967
6.38k
                    op->cache = func;
10968
6.38k
                    op->cacheURI = (void *) URI;
10969
6.38k
                }
10970
26.5k
                oldFunc = ctxt->context->function;
10971
26.5k
                oldFuncURI = ctxt->context->functionURI;
10972
26.5k
                ctxt->context->function = op->value4;
10973
26.5k
                ctxt->context->functionURI = op->cacheURI;
10974
26.5k
                func(ctxt, op->value);
10975
26.5k
                ctxt->context->function = oldFunc;
10976
26.5k
                ctxt->context->functionURI = oldFuncURI;
10977
26.5k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
10978
26.3k
                    (ctxt->valueNr != frame + 1))
10979
26.5k
                    XP_ERROR0(XPATH_STACK_ERROR);
10980
26.5k
                break;
10981
26.5k
            }
10982
28.8k
        case XPATH_OP_ARG:
10983
28.8k
            if (op->ch1 != -1) {
10984
3.09k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10985
3.09k
          CHECK_ERROR0;
10986
3.09k
            }
10987
28.4k
            if (op->ch2 != -1) {
10988
28.4k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10989
28.4k
          CHECK_ERROR0;
10990
28.4k
      }
10991
27.7k
            break;
10992
27.7k
        case XPATH_OP_PREDICATE:
10993
6.13k
        case XPATH_OP_FILTER:{
10994
6.13k
                xmlXPathObjectPtr obj;
10995
6.13k
                xmlNodeSetPtr set;
10996
10997
                /*
10998
                 * Optimization for ()[1] selection i.e. the first elem
10999
                 */
11000
6.13k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11001
6.13k
#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
6.13k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11012
1.82k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11013
#else
11014
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11015
#endif
11016
6.08k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11017
3.28k
                    xmlXPathObjectPtr val;
11018
11019
3.28k
                    val = comp->steps[op->ch2].value4;
11020
3.28k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11021
3.27k
                        (val->floatval == 1.0)) {
11022
2.72k
                        xmlNodePtr first = NULL;
11023
11024
2.72k
                        total +=
11025
2.72k
                            xmlXPathCompOpEvalFirst(ctxt,
11026
2.72k
                                                    &comp->steps[op->ch1],
11027
2.72k
                                                    &first);
11028
2.72k
      CHECK_ERROR0;
11029
                        /*
11030
                         * The nodeset should be in document order,
11031
                         * Keep only the first value
11032
                         */
11033
1.90k
                        if ((ctxt->value != NULL) &&
11034
1.90k
                            (ctxt->value->type == XPATH_NODESET) &&
11035
1.90k
                            (ctxt->value->nodesetval != NULL) &&
11036
1.90k
                            (ctxt->value->nodesetval->nodeNr > 1))
11037
157
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11038
157
                                                        1, 1);
11039
1.90k
                        break;
11040
2.72k
                    }
11041
3.28k
                }
11042
                /*
11043
                 * Optimization for ()[last()] selection i.e. the last elem
11044
                 */
11045
3.41k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11046
3.41k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
2.88k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11048
2.48k
                    int f = comp->steps[op->ch2].ch1;
11049
11050
2.48k
                    if ((f != -1) &&
11051
2.48k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11052
3
                        (comp->steps[f].value5 == NULL) &&
11053
2
                        (comp->steps[f].value == 0) &&
11054
1
                        (comp->steps[f].value4 != NULL) &&
11055
1
                        (xmlStrEqual
11056
1
                         (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
2.48k
                }
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
3.41k
                if (op->ch1 != -1)
11089
3.41k
                    total +=
11090
3.41k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11091
3.41k
    CHECK_ERROR0;
11092
3.07k
                if (op->ch2 == -1)
11093
0
                    break;
11094
3.07k
                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
3.07k
                CHECK_TYPE0(XPATH_NODESET);
11104
3.04k
                obj = xmlXPathValuePop(ctxt);
11105
3.04k
                set = obj->nodesetval;
11106
3.04k
                if (set != NULL)
11107
3.04k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11108
3.04k
                                          1, set->nodeNr, 1);
11109
3.04k
                xmlXPathValuePush(ctxt, obj);
11110
3.04k
                break;
11111
3.07k
            }
11112
70.0k
        case XPATH_OP_SORT:
11113
70.0k
            if (op->ch1 != -1)
11114
70.0k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11115
70.0k
      CHECK_ERROR0;
11116
66.3k
            if ((ctxt->value != NULL) &&
11117
66.3k
                (ctxt->value->type == XPATH_NODESET) &&
11118
49.8k
                (ctxt->value->nodesetval != NULL) &&
11119
49.8k
    (ctxt->value->nodesetval->nodeNr > 1))
11120
4.72k
      {
11121
4.72k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11122
4.72k
      }
11123
66.3k
            break;
11124
0
        default:
11125
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11126
0
            break;
11127
3.26M
    }
11128
11129
3.22M
    ctxt->context->depth -= 1;
11130
3.22M
    return (total);
11131
3.26M
}
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
312k
{
11146
312k
    xmlXPathObjectPtr resObj = NULL;
11147
11148
315k
start:
11149
315k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11150
3
        return(0);
11151
    /* comp = ctxt->comp; */
11152
315k
    switch (op->op) {
11153
0
        case XPATH_OP_END:
11154
0
            return (0);
11155
76.8k
  case XPATH_OP_VALUE:
11156
76.8k
      resObj = (xmlXPathObjectPtr) op->value4;
11157
76.8k
      if (isPredicate)
11158
76.8k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11159
0
      return(xmlXPathCastToBoolean(resObj));
11160
2.57k
  case XPATH_OP_SORT:
11161
      /*
11162
      * We don't need sorting for boolean results. Skip this one.
11163
      */
11164
2.57k
            if (op->ch1 != -1) {
11165
2.57k
    op = &ctxt->comp->steps[op->ch1];
11166
2.57k
    goto start;
11167
2.57k
      }
11168
0
      return(0);
11169
18.0k
  case XPATH_OP_COLLECT:
11170
18.0k
      if (op->ch1 == -1)
11171
0
    return(0);
11172
11173
18.0k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11174
18.0k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11175
49
    return(-1);
11176
11177
17.9k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11178
17.9k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11179
49
    return(-1);
11180
11181
17.9k
      resObj = xmlXPathValuePop(ctxt);
11182
17.9k
      if (resObj == NULL)
11183
0
    return(-1);
11184
17.9k
      break;
11185
217k
  default:
11186
      /*
11187
      * Fallback to call xmlXPathCompOpEval().
11188
      */
11189
217k
      xmlXPathCompOpEval(ctxt, op);
11190
217k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11191
667
    return(-1);
11192
11193
216k
      resObj = xmlXPathValuePop(ctxt);
11194
216k
      if (resObj == NULL)
11195
0
    return(-1);
11196
216k
      break;
11197
315k
    }
11198
11199
234k
    if (resObj) {
11200
234k
  int res;
11201
11202
234k
  if (resObj->type == XPATH_BOOLEAN) {
11203
173k
      res = resObj->boolval;
11204
173k
  } 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
60.9k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11214
60.9k
  } else {
11215
0
      res = xmlXPathCastToBoolean(resObj);
11216
0
  }
11217
234k
  xmlXPathReleaseObject(ctxt->context, resObj);
11218
234k
  return(res);
11219
234k
    }
11220
11221
0
    return(0);
11222
234k
}
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
7.22k
{
11465
7.22k
    xmlXPathCompExprPtr comp;
11466
7.22k
    int oldDepth;
11467
11468
7.22k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11469
0
  return(-1);
11470
11471
7.22k
    if (ctxt->valueTab == NULL) {
11472
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11473
0
        int valueMax = 1;
11474
#else
11475
        int valueMax = 10;
11476
#endif
11477
11478
  /* Allocate the value stack */
11479
0
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11480
0
  if (ctxt->valueTab == NULL) {
11481
0
      xmlXPathPErrMemory(ctxt);
11482
0
      return(-1);
11483
0
  }
11484
0
  ctxt->valueNr = 0;
11485
0
  ctxt->valueMax = valueMax;
11486
0
  ctxt->value = NULL;
11487
0
    }
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
7.22k
    comp = ctxt->comp;
11521
7.22k
    if (comp->last < 0) {
11522
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11523
0
  return(-1);
11524
0
    }
11525
7.22k
    oldDepth = ctxt->context->depth;
11526
7.22k
    if (toBool)
11527
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11528
0
      &comp->steps[comp->last], 0));
11529
7.22k
    else
11530
7.22k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11531
7.22k
    ctxt->context->depth = oldDepth;
11532
11533
7.22k
    return(0);
11534
7.22k
}
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
137k
                                xmlXPathObject *res) {
11595
137k
    if ((ctxt == NULL) || (res == NULL)) return(0);
11596
137k
    switch (res->type) {
11597
0
        case XPATH_BOOLEAN:
11598
0
      return(res->boolval);
11599
49.0k
        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
49.0k
      return(res->floatval == ctxt->context->proximityPosition);
11605
0
#endif
11606
20.4k
        case XPATH_NODESET:
11607
20.4k
        case XPATH_XSLT_TREE:
11608
20.4k
      if (res->nodesetval == NULL)
11609
0
    return(0);
11610
20.4k
      return(res->nodesetval->nodeNr != 0);
11611
68.1k
        case XPATH_STRING:
11612
68.1k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11613
0
        default:
11614
0
      break;
11615
137k
    }
11616
0
    return(0);
11617
137k
}
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
3.82M
{
11709
3.82M
    xmlXPathCompExprPtr comp = pctxt->comp;
11710
3.82M
    xmlXPathContextPtr ctxt;
11711
11712
    /*
11713
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11714
    * internal representation.
11715
    */
11716
11717
3.82M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11718
1.24M
        (op->ch1 != -1) &&
11719
1.24M
        (op->ch2 == -1 /* no predicate */))
11720
1.24M
    {
11721
1.24M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11722
11723
1.24M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11724
27.6k
            ((xmlXPathAxisVal) prevop->value ==
11725
27.6k
                AXIS_DESCENDANT_OR_SELF) &&
11726
10.6k
            (prevop->ch2 == -1) &&
11727
10.6k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11728
10.6k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11729
10.6k
        {
11730
            /*
11731
            * This is a "descendant-or-self::node()" without predicates.
11732
            * Try to eliminate it.
11733
            */
11734
11735
10.6k
            switch ((xmlXPathAxisVal) op->value) {
11736
2.35k
                case AXIS_CHILD:
11737
2.35k
                case AXIS_DESCENDANT:
11738
                    /*
11739
                    * Convert "descendant-or-self::node()/child::" or
11740
                    * "descendant-or-self::node()/descendant::" to
11741
                    * "descendant::"
11742
                    */
11743
2.35k
                    op->ch1   = prevop->ch1;
11744
2.35k
                    op->value = AXIS_DESCENDANT;
11745
2.35k
                    break;
11746
0
                case AXIS_SELF:
11747
2.49k
                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
2.49k
                    op->ch1   = prevop->ch1;
11754
2.49k
                    op->value = AXIS_DESCENDANT_OR_SELF;
11755
2.49k
                    break;
11756
5.79k
                default:
11757
5.79k
                    break;
11758
10.6k
            }
11759
10.6k
  }
11760
1.24M
    }
11761
11762
    /* OP_VALUE has invalid ch1. */
11763
3.82M
    if (op->op == XPATH_OP_VALUE)
11764
19.8k
        return;
11765
11766
    /* Recurse */
11767
3.80M
    ctxt = pctxt->context;
11768
3.80M
    if (ctxt != NULL) {
11769
3.80M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11770
4.23k
            return;
11771
3.80M
        ctxt->depth += 1;
11772
3.80M
    }
11773
3.80M
    if (op->ch1 != -1)
11774
2.56M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11775
3.80M
    if (op->ch2 != -1)
11776
1.25M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11777
3.80M
    if (ctxt != NULL)
11778
3.80M
        ctxt->depth -= 1;
11779
3.80M
}
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
0
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11791
0
    xmlXPathParserContextPtr pctxt;
11792
0
    xmlXPathContextPtr tmpctxt = NULL;
11793
0
    xmlXPathCompExprPtr comp;
11794
0
    int oldDepth = 0;
11795
11796
0
    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
0
    xmlInitParser();
11806
11807
    /*
11808
     * We need an xmlXPathContext for the depth check.
11809
     */
11810
0
    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
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
11818
0
    if (pctxt == NULL) {
11819
0
        if (tmpctxt != NULL)
11820
0
            xmlXPathFreeContext(tmpctxt);
11821
0
        return NULL;
11822
0
    }
11823
11824
0
    oldDepth = ctxt->depth;
11825
0
    xmlXPathCompileExpr(pctxt, 1);
11826
0
    ctxt->depth = oldDepth;
11827
11828
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
11829
0
    {
11830
0
        xmlXPathFreeParserContext(pctxt);
11831
0
        if (tmpctxt != NULL)
11832
0
            xmlXPathFreeContext(tmpctxt);
11833
0
        return(NULL);
11834
0
    }
11835
11836
0
    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
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11844
0
  comp = NULL;
11845
0
    } else {
11846
0
  comp = pctxt->comp;
11847
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11848
0
            if (ctxt != NULL)
11849
0
                oldDepth = ctxt->depth;
11850
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11851
0
            if (ctxt != NULL)
11852
0
                ctxt->depth = oldDepth;
11853
0
  }
11854
0
  pctxt->comp = NULL;
11855
0
    }
11856
0
    xmlXPathFreeParserContext(pctxt);
11857
0
    if (tmpctxt != NULL)
11858
0
        xmlXPathFreeContext(tmpctxt);
11859
11860
0
    if (comp != NULL) {
11861
0
  comp->expr = xmlStrdup(str);
11862
0
    }
11863
0
    return(comp);
11864
0
}
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
0
{
11895
0
    xmlXPathParserContextPtr pctxt;
11896
0
    xmlXPathObjectPtr resObj = NULL;
11897
0
    int res;
11898
11899
0
    if (comp == NULL)
11900
0
  return(-1);
11901
0
    xmlInitParser();
11902
11903
0
    xmlResetError(&ctxt->lastError);
11904
11905
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11906
0
    if (pctxt == NULL)
11907
0
        return(-1);
11908
0
    res = xmlXPathRunEval(pctxt, toBool);
11909
11910
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11911
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11912
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11913
0
        else if (!toBool)
11914
0
            resObj = xmlXPathValuePop(pctxt);
11915
0
    }
11916
11917
0
    if (resObjPtr)
11918
0
        *resObjPtr = resObj;
11919
0
    else
11920
0
        xmlXPathReleaseObject(ctxt, resObj);
11921
11922
0
    pctxt->comp = NULL;
11923
0
    xmlXPathFreeParserContext(pctxt);
11924
11925
0
    return(res);
11926
0
}
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
0
{
11939
0
    xmlXPathObjectPtr res = NULL;
11940
11941
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11942
0
    return(res);
11943
0
}
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
9.32k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
11971
#ifdef XPATH_STREAMING
11972
    xmlXPathCompExprPtr comp;
11973
#endif
11974
9.32k
    int oldDepth = 0;
11975
11976
9.32k
    if ((ctxt == NULL) || (ctxt->context == NULL))
11977
0
        return;
11978
9.32k
    if (ctxt->context->lastError.code != 0)
11979
34
        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
9.29k
    {
11995
9.29k
        if (ctxt->context != NULL)
11996
9.29k
            oldDepth = ctxt->context->depth;
11997
9.29k
  xmlXPathCompileExpr(ctxt, 1);
11998
9.29k
        if (ctxt->context != NULL)
11999
9.29k
            ctxt->context->depth = oldDepth;
12000
9.29k
        CHECK_ERROR;
12001
12002
        /* Check for trailing characters. */
12003
7.56k
        if (*ctxt->cur != 0)
12004
7.22k
            XP_ERROR(XPATH_EXPR_ERROR);
12005
12006
7.22k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12007
7.17k
            if (ctxt->context != NULL)
12008
7.17k
                oldDepth = ctxt->context->depth;
12009
7.17k
      xmlXPathOptimizeExpression(ctxt,
12010
7.17k
    &ctxt->comp->steps[ctxt->comp->last]);
12011
7.17k
            if (ctxt->context != NULL)
12012
7.17k
                ctxt->context->depth = oldDepth;
12013
7.17k
        }
12014
7.22k
    }
12015
12016
0
    xmlXPathRunEval(ctxt, 0);
12017
7.22k
}
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
0
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12029
0
    xmlXPathParserContextPtr ctxt;
12030
0
    xmlXPathObjectPtr res;
12031
12032
0
    if (ctx == NULL)
12033
0
        return(NULL);
12034
12035
0
    xmlInitParser();
12036
12037
0
    xmlResetError(&ctx->lastError);
12038
12039
0
    ctxt = xmlXPathNewParserContext(str, ctx);
12040
0
    if (ctxt == NULL)
12041
0
        return NULL;
12042
0
    xmlXPathEvalExpr(ctxt);
12043
12044
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12045
0
  res = NULL;
12046
0
    } else if (ctxt->valueNr != 1) {
12047
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12048
0
  res = NULL;
12049
0
    } else {
12050
0
  res = xmlXPathValuePop(ctxt);
12051
0
    }
12052
12053
0
    xmlXPathFreeParserContext(ctxt);
12054
0
    return(res);
12055
0
}
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 */