Coverage Report

Created: 2026-03-21 06:51

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