Coverage Report

Created: 2023-06-07 06:14

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/valid.h>
35
#include <libxml/xpath.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/parserInternals.h>
38
#include <libxml/hash.h>
39
#ifdef LIBXML_XPTR_LOCS_ENABLED
40
#include <libxml/xpointer.h>
41
#endif
42
#ifdef LIBXML_DEBUG_ENABLED
43
#include <libxml/debugXML.h>
44
#endif
45
#include <libxml/xmlerror.h>
46
#include <libxml/threads.h>
47
#include <libxml/globals.h>
48
#ifdef LIBXML_PATTERN_ENABLED
49
#include <libxml/pattern.h>
50
#endif
51
52
#include "private/buf.h"
53
#include "private/error.h"
54
#include "private/xpath.h"
55
56
#ifdef LIBXML_PATTERN_ENABLED
57
#define XPATH_STREAMING
58
#endif
59
60
#define TODO                \
61
128
    xmlGenericError(xmlGenericErrorContext,       \
62
128
      "Unimplemented block at %s:%d\n",       \
63
128
            __FILE__, __LINE__);
64
65
/**
66
 * WITH_TIM_SORT:
67
 *
68
 * Use the Timsort algorithm provided in timsort.h to sort
69
 * nodeset as this is a great improvement over the old Shell sort
70
 * used in xmlXPathNodeSetSort()
71
 */
72
#define WITH_TIM_SORT
73
74
/*
75
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
76
* If defined, this will use xmlXPathCmpNodesExt() instead of
77
* xmlXPathCmpNodes(). The new function is optimized comparison of
78
* non-element nodes; actually it will speed up comparison only if
79
* xmlXPathOrderDocElems() was called in order to index the elements of
80
* a tree in document order; Libxslt does such an indexing, thus it will
81
* benefit from this optimization.
82
*/
83
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
84
85
/*
86
* XP_OPTIMIZED_FILTER_FIRST:
87
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
88
* in a way, that it stop evaluation at the first node.
89
*/
90
#define XP_OPTIMIZED_FILTER_FIRST
91
92
/*
93
* XP_DEBUG_OBJ_USAGE:
94
* Internal flag to enable tracking of how much XPath objects have been
95
* created.
96
*/
97
/* #define XP_DEBUG_OBJ_USAGE */
98
99
/*
100
 * XPATH_MAX_STEPS:
101
 * when compiling an XPath expression we arbitrary limit the maximum
102
 * number of step operation in the compiled expression. 1000000 is
103
 * an insanely large value which should never be reached under normal
104
 * circumstances
105
 */
106
844k
#define XPATH_MAX_STEPS 1000000
107
108
/*
109
 * XPATH_MAX_STACK_DEPTH:
110
 * when evaluating an XPath expression we arbitrary limit the maximum
111
 * number of object allowed to be pushed on the stack. 1000000 is
112
 * an insanely large value which should never be reached under normal
113
 * circumstances
114
 */
115
32
#define XPATH_MAX_STACK_DEPTH 1000000
116
117
/*
118
 * XPATH_MAX_NODESET_LENGTH:
119
 * when evaluating an XPath expression nodesets are created and we
120
 * arbitrary limit the maximum length of those node set. 10000000 is
121
 * an insanely large value which should never be reached under normal
122
 * circumstances, one would first need to construct an in memory tree
123
 * with more than 10 millions nodes.
124
 */
125
1.36M
#define XPATH_MAX_NODESET_LENGTH 10000000
126
127
/*
128
 * XPATH_MAX_RECRUSION_DEPTH:
129
 * Maximum amount of nested functions calls when parsing or evaluating
130
 * expressions
131
 */
132
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
133
51.9M
#define XPATH_MAX_RECURSION_DEPTH 500
134
#elif defined(_WIN32)
135
/* Windows typically limits stack size to 1MB. */
136
#define XPATH_MAX_RECURSION_DEPTH 1000
137
#else
138
#define XPATH_MAX_RECURSION_DEPTH 5000
139
#endif
140
141
/*
142
 * TODO:
143
 * There are a few spots where some tests are done which depend upon ascii
144
 * data.  These should be enhanced for full UTF8 support (see particularly
145
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146
 */
147
148
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
149
150
/************************************************************************
151
 *                  *
152
 *      Floating point stuff        *
153
 *                  *
154
 ************************************************************************/
155
156
double xmlXPathNAN = 0.0;
157
double xmlXPathPINF = 0.0;
158
double xmlXPathNINF = 0.0;
159
160
/**
161
 * xmlXPathInit:
162
 *
163
 * DEPRECATED: Alias for xmlInitParser.
164
 */
165
void
166
0
xmlXPathInit(void) {
167
0
    xmlInitParser();
168
0
}
169
170
/**
171
 * xmlInitXPathInternal:
172
 *
173
 * Initialize the XPath environment
174
 */
175
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
176
void
177
4
xmlInitXPathInternal(void) {
178
4
#if defined(NAN) && defined(INFINITY)
179
4
    xmlXPathNAN = NAN;
180
4
    xmlXPathPINF = INFINITY;
181
4
    xmlXPathNINF = -INFINITY;
182
#else
183
    /* MSVC doesn't allow division by zero in constant expressions. */
184
    double zero = 0.0;
185
    xmlXPathNAN = 0.0 / zero;
186
    xmlXPathPINF = 1.0 / zero;
187
    xmlXPathNINF = -xmlXPathPINF;
188
#endif
189
4
}
190
191
/**
192
 * xmlXPathIsNaN:
193
 * @val:  a double value
194
 *
195
 * Returns 1 if the value is a NaN, 0 otherwise
196
 */
197
int
198
3.56M
xmlXPathIsNaN(double val) {
199
3.56M
#ifdef isnan
200
3.56M
    return isnan(val);
201
#else
202
    return !(val == val);
203
#endif
204
3.56M
}
205
206
/**
207
 * xmlXPathIsInf:
208
 * @val:  a double value
209
 *
210
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
211
 */
212
int
213
1.11M
xmlXPathIsInf(double val) {
214
1.11M
#ifdef isinf
215
1.11M
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
216
#else
217
    if (val >= xmlXPathPINF)
218
        return 1;
219
    if (val <= -xmlXPathPINF)
220
        return -1;
221
    return 0;
222
#endif
223
1.11M
}
224
225
#endif /* SCHEMAS or XPATH */
226
227
#ifdef LIBXML_XPATH_ENABLED
228
229
/*
230
 * TODO: when compatibility allows remove all "fake node libxslt" strings
231
 *       the test should just be name[0] = ' '
232
 */
233
#ifdef DEBUG_XPATH_EXPRESSION
234
#define DEBUG_STEP
235
#define DEBUG_EXPR
236
#define DEBUG_EVAL_COUNTS
237
#endif
238
239
static xmlNs xmlXPathXMLNamespaceStruct = {
240
    NULL,
241
    XML_NAMESPACE_DECL,
242
    XML_XML_NAMESPACE,
243
    BAD_CAST "xml",
244
    NULL,
245
    NULL
246
};
247
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
248
#ifndef LIBXML_THREAD_ENABLED
249
/*
250
 * Optimizer is disabled only when threaded apps are detected while
251
 * the library ain't compiled for thread safety.
252
 */
253
static int xmlXPathDisableOptimizer = 0;
254
#endif
255
256
static void
257
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
258
259
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
260
/**
261
 * xmlXPathCmpNodesExt:
262
 * @node1:  the first node
263
 * @node2:  the second node
264
 *
265
 * Compare two nodes w.r.t document order.
266
 * This one is optimized for handling of non-element nodes.
267
 *
268
 * Returns -2 in case of error 1 if first point < second point, 0 if
269
 *         it's the same node, -1 otherwise
270
 */
271
static int
272
71.4M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
273
71.4M
    int depth1, depth2;
274
71.4M
    int misc = 0, precedence1 = 0, precedence2 = 0;
275
71.4M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
276
71.4M
    xmlNodePtr cur, root;
277
71.4M
    ptrdiff_t l1, l2;
278
279
71.4M
    if ((node1 == NULL) || (node2 == NULL))
280
0
  return(-2);
281
282
71.4M
    if (node1 == node2)
283
0
  return(0);
284
285
    /*
286
     * a couple of optimizations which will avoid computations in most cases
287
     */
288
71.4M
    switch (node1->type) {
289
49.1M
  case XML_ELEMENT_NODE:
290
49.1M
      if (node2->type == XML_ELEMENT_NODE) {
291
38.2M
    if ((0 > (ptrdiff_t) node1->content) &&
292
38.2M
        (0 > (ptrdiff_t) node2->content) &&
293
38.2M
        (node1->doc == node2->doc))
294
10.7M
    {
295
10.7M
        l1 = -((ptrdiff_t) node1->content);
296
10.7M
        l2 = -((ptrdiff_t) node2->content);
297
10.7M
        if (l1 < l2)
298
7.45M
      return(1);
299
3.25M
        if (l1 > l2)
300
3.25M
      return(-1);
301
3.25M
    } else
302
27.5M
        goto turtle_comparison;
303
38.2M
      }
304
10.8M
      break;
305
10.8M
  case XML_ATTRIBUTE_NODE:
306
79.4k
      precedence1 = 1; /* element is owner */
307
79.4k
      miscNode1 = node1;
308
79.4k
      node1 = node1->parent;
309
79.4k
      misc = 1;
310
79.4k
      break;
311
21.0M
  case XML_TEXT_NODE:
312
21.0M
  case XML_CDATA_SECTION_NODE:
313
21.4M
  case XML_COMMENT_NODE:
314
21.7M
  case XML_PI_NODE: {
315
21.7M
      miscNode1 = node1;
316
      /*
317
      * Find nearest element node.
318
      */
319
21.7M
      if (node1->prev != NULL) {
320
16.5M
    do {
321
16.5M
        node1 = node1->prev;
322
16.5M
        if (node1->type == XML_ELEMENT_NODE) {
323
9.38M
      precedence1 = 3; /* element in prev-sibl axis */
324
9.38M
      break;
325
9.38M
        }
326
7.17M
        if (node1->prev == NULL) {
327
678k
      precedence1 = 2; /* element is parent */
328
      /*
329
      * URGENT TODO: Are there any cases, where the
330
      * parent of such a node is not an element node?
331
      */
332
678k
      node1 = node1->parent;
333
678k
      break;
334
678k
        }
335
7.17M
    } while (1);
336
11.6M
      } else {
337
11.6M
    precedence1 = 2; /* element is parent */
338
11.6M
    node1 = node1->parent;
339
11.6M
      }
340
21.7M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
341
21.7M
    (0 <= (ptrdiff_t) node1->content)) {
342
    /*
343
    * Fallback for whatever case.
344
    */
345
4.87M
    node1 = miscNode1;
346
4.87M
    precedence1 = 0;
347
4.87M
      } else
348
16.8M
    misc = 1;
349
21.7M
  }
350
0
      break;
351
157k
  case XML_NAMESPACE_DECL:
352
      /*
353
      * TODO: why do we return 1 for namespace nodes?
354
      */
355
157k
      return(1);
356
324k
  default:
357
324k
      break;
358
71.4M
    }
359
33.0M
    switch (node2->type) {
360
13.3M
  case XML_ELEMENT_NODE:
361
13.3M
      break;
362
78.3k
  case XML_ATTRIBUTE_NODE:
363
78.3k
      precedence2 = 1; /* element is owner */
364
78.3k
      miscNode2 = node2;
365
78.3k
      node2 = node2->parent;
366
78.3k
      misc = 1;
367
78.3k
      break;
368
18.1M
  case XML_TEXT_NODE:
369
18.1M
  case XML_CDATA_SECTION_NODE:
370
18.6M
  case XML_COMMENT_NODE:
371
18.8M
  case XML_PI_NODE: {
372
18.8M
      miscNode2 = node2;
373
18.8M
      if (node2->prev != NULL) {
374
16.0M
    do {
375
16.0M
        node2 = node2->prev;
376
16.0M
        if (node2->type == XML_ELEMENT_NODE) {
377
8.78M
      precedence2 = 3; /* element in prev-sibl axis */
378
8.78M
      break;
379
8.78M
        }
380
7.22M
        if (node2->prev == NULL) {
381
647k
      precedence2 = 2; /* element is parent */
382
647k
      node2 = node2->parent;
383
647k
      break;
384
647k
        }
385
7.22M
    } while (1);
386
9.43M
      } else {
387
9.43M
    precedence2 = 2; /* element is parent */
388
9.43M
    node2 = node2->parent;
389
9.43M
      }
390
18.8M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
391
18.8M
    (0 <= (ptrdiff_t) node2->content))
392
3.39M
      {
393
3.39M
    node2 = miscNode2;
394
3.39M
    precedence2 = 0;
395
3.39M
      } else
396
15.4M
    misc = 1;
397
18.8M
  }
398
0
      break;
399
4.71k
  case XML_NAMESPACE_DECL:
400
4.71k
      return(1);
401
723k
  default:
402
723k
      break;
403
33.0M
    }
404
32.9M
    if (misc) {
405
26.3M
  if (node1 == node2) {
406
9.35M
      if (precedence1 == precedence2) {
407
    /*
408
    * The ugly case; but normally there aren't many
409
    * adjacent non-element nodes around.
410
    */
411
632k
    cur = miscNode2->prev;
412
700k
    while (cur != NULL) {
413
592k
        if (cur == miscNode1)
414
489k
      return(1);
415
102k
        if (cur->type == XML_ELEMENT_NODE)
416
34.9k
      return(-1);
417
67.5k
        cur = cur->prev;
418
67.5k
    }
419
107k
    return (-1);
420
8.72M
      } else {
421
    /*
422
    * Evaluate based on higher precedence wrt to the element.
423
    * TODO: This assumes attributes are sorted before content.
424
    *   Is this 100% correct?
425
    */
426
8.72M
    if (precedence1 < precedence2)
427
5.95M
        return(1);
428
2.77M
    else
429
2.77M
        return(-1);
430
8.72M
      }
431
9.35M
  }
432
  /*
433
  * Special case: One of the helper-elements is contained by the other.
434
  * <foo>
435
  *   <node2>
436
  *     <node1>Text-1(precedence1 == 2)</node1>
437
  *   </node2>
438
  *   Text-6(precedence2 == 3)
439
  * </foo>
440
  */
441
16.9M
  if ((precedence2 == 3) && (precedence1 > 1)) {
442
2.34M
      cur = node1->parent;
443
10.4M
      while (cur) {
444
8.81M
    if (cur == node2)
445
737k
        return(1);
446
8.08M
    cur = cur->parent;
447
8.08M
      }
448
2.34M
  }
449
16.2M
  if ((precedence1 == 3) && (precedence2 > 1)) {
450
1.64M
      cur = node2->parent;
451
9.05M
      while (cur) {
452
7.48M
    if (cur == node1)
453
75.1k
        return(-1);
454
7.40M
    cur = cur->parent;
455
7.40M
      }
456
1.64M
  }
457
16.2M
    }
458
459
    /*
460
     * Speedup using document order if available.
461
     */
462
22.8M
    if ((node1->type == XML_ELEMENT_NODE) &&
463
22.8M
  (node2->type == XML_ELEMENT_NODE) &&
464
22.8M
  (0 > (ptrdiff_t) node1->content) &&
465
22.8M
  (0 > (ptrdiff_t) node2->content) &&
466
22.8M
  (node1->doc == node2->doc)) {
467
468
15.9M
  l1 = -((ptrdiff_t) node1->content);
469
15.9M
  l2 = -((ptrdiff_t) node2->content);
470
15.9M
  if (l1 < l2)
471
8.12M
      return(1);
472
7.85M
  if (l1 > l2)
473
7.85M
      return(-1);
474
7.85M
    }
475
476
34.4M
turtle_comparison:
477
478
34.4M
    if (node1 == node2->prev)
479
25.8M
  return(1);
480
8.59M
    if (node1 == node2->next)
481
105k
  return(-1);
482
    /*
483
     * compute depth to root
484
     */
485
24.9M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
486
16.9M
  if (cur->parent == node1)
487
445k
      return(1);
488
16.4M
  depth2++;
489
16.4M
    }
490
8.04M
    root = cur;
491
22.4M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
492
15.7M
  if (cur->parent == node2)
493
1.29M
      return(-1);
494
14.4M
  depth1++;
495
14.4M
    }
496
    /*
497
     * Distinct document (or distinct entities :-( ) case.
498
     */
499
6.75M
    if (root != cur) {
500
2.75M
  return(-2);
501
2.75M
    }
502
    /*
503
     * get the nearest common ancestor.
504
     */
505
5.69M
    while (depth1 > depth2) {
506
1.69M
  depth1--;
507
1.69M
  node1 = node1->parent;
508
1.69M
    }
509
7.17M
    while (depth2 > depth1) {
510
3.17M
  depth2--;
511
3.17M
  node2 = node2->parent;
512
3.17M
    }
513
5.69M
    while (node1->parent != node2->parent) {
514
1.69M
  node1 = node1->parent;
515
1.69M
  node2 = node2->parent;
516
  /* should not happen but just in case ... */
517
1.69M
  if ((node1 == NULL) || (node2 == NULL))
518
0
      return(-2);
519
1.69M
    }
520
    /*
521
     * Find who's first.
522
     */
523
4.00M
    if (node1 == node2->prev)
524
240k
  return(1);
525
3.76M
    if (node1 == node2->next)
526
923k
  return(-1);
527
    /*
528
     * Speedup using document order if available.
529
     */
530
2.83M
    if ((node1->type == XML_ELEMENT_NODE) &&
531
2.83M
  (node2->type == XML_ELEMENT_NODE) &&
532
2.83M
  (0 > (ptrdiff_t) node1->content) &&
533
2.83M
  (0 > (ptrdiff_t) node2->content) &&
534
2.83M
  (node1->doc == node2->doc)) {
535
536
0
  l1 = -((ptrdiff_t) node1->content);
537
0
  l2 = -((ptrdiff_t) node2->content);
538
0
  if (l1 < l2)
539
0
      return(1);
540
0
  if (l1 > l2)
541
0
      return(-1);
542
0
    }
543
544
22.9M
    for (cur = node1->next;cur != NULL;cur = cur->next)
545
20.8M
  if (cur == node2)
546
703k
      return(1);
547
2.13M
    return(-1); /* assume there is no sibling list corruption */
548
2.83M
}
549
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
550
551
/*
552
 * Wrapper for the Timsort algorithm from timsort.h
553
 */
554
#ifdef WITH_TIM_SORT
555
#define SORT_NAME libxml_domnode
556
21.1M
#define SORT_TYPE xmlNodePtr
557
/**
558
 * wrap_cmp:
559
 * @x: a node
560
 * @y: another node
561
 *
562
 * Comparison function for the Timsort implementation
563
 *
564
 * Returns -2 in case of error -1 if first point < second point, 0 if
565
 *         it's the same node, +1 otherwise
566
 */
567
static
568
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
569
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
570
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
571
71.4M
    {
572
71.4M
        int res = xmlXPathCmpNodesExt(x, y);
573
71.4M
        return res == -2 ? res : -res;
574
71.4M
    }
575
#else
576
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
577
    {
578
        int res = xmlXPathCmpNodes(x, y);
579
        return res == -2 ? res : -res;
580
    }
581
#endif
582
71.4M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
583
#include "timsort.h"
584
#endif /* WITH_TIM_SORT */
585
586
/************************************************************************
587
 *                  *
588
 *      Error handling routines       *
589
 *                  *
590
 ************************************************************************/
591
592
/**
593
 * XP_ERRORNULL:
594
 * @X:  the error code
595
 *
596
 * Macro to raise an XPath error and return NULL.
597
 */
598
#define XP_ERRORNULL(X)             \
599
72.5k
    { xmlXPathErr(ctxt, X); return(NULL); }
600
601
/*
602
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603
 */
604
static const char* const xmlXPathErrorMessages[] = {
605
    "Ok\n",
606
    "Number encoding\n",
607
    "Unfinished literal\n",
608
    "Start of literal\n",
609
    "Expected $ for variable reference\n",
610
    "Undefined variable\n",
611
    "Invalid predicate\n",
612
    "Invalid expression\n",
613
    "Missing closing curly brace\n",
614
    "Unregistered function\n",
615
    "Invalid operand\n",
616
    "Invalid type\n",
617
    "Invalid number of arguments\n",
618
    "Invalid context size\n",
619
    "Invalid context position\n",
620
    "Memory allocation error\n",
621
    "Syntax error\n",
622
    "Resource error\n",
623
    "Sub resource error\n",
624
    "Undefined namespace prefix\n",
625
    "Encoding error\n",
626
    "Char out of XML range\n",
627
    "Invalid or incomplete context\n",
628
    "Stack usage error\n",
629
    "Forbidden variable\n",
630
    "Operation limit exceeded\n",
631
    "Recursion limit exceeded\n",
632
    "?? Unknown error ??\n" /* Must be last in the list! */
633
};
634
1.40M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
635
1.40M
       sizeof(xmlXPathErrorMessages[0])) - 1)
636
/**
637
 * xmlXPathErrMemory:
638
 * @ctxt:  an XPath context
639
 * @extra:  extra information
640
 *
641
 * Handle a redefinition of attribute error
642
 */
643
static void
644
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
645
134k
{
646
134k
    if (ctxt != NULL) {
647
64.5k
        xmlResetError(&ctxt->lastError);
648
64.5k
        if (extra) {
649
63.2k
            xmlChar buf[200];
650
651
63.2k
            xmlStrPrintf(buf, 200,
652
63.2k
                         "Memory allocation failed : %s\n",
653
63.2k
                         extra);
654
63.2k
            ctxt->lastError.message = (char *) xmlStrdup(buf);
655
63.2k
        } else {
656
1.34k
            ctxt->lastError.message = (char *)
657
1.34k
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
658
1.34k
        }
659
64.5k
        ctxt->lastError.domain = XML_FROM_XPATH;
660
64.5k
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
661
64.5k
  if (ctxt->error != NULL)
662
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
663
70.4k
    } else {
664
70.4k
        if (extra)
665
70.4k
            __xmlRaiseError(NULL, NULL, NULL,
666
70.4k
                            NULL, NULL, XML_FROM_XPATH,
667
70.4k
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668
70.4k
                            extra, NULL, NULL, 0, 0,
669
70.4k
                            "Memory allocation failed : %s\n", extra);
670
0
        else
671
0
            __xmlRaiseError(NULL, NULL, NULL,
672
0
                            NULL, NULL, XML_FROM_XPATH,
673
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
674
0
                            NULL, NULL, NULL, 0, 0,
675
0
                            "Memory allocation failed\n");
676
70.4k
    }
677
134k
}
678
679
/**
680
 * xmlXPathPErrMemory:
681
 * @ctxt:  an XPath parser context
682
 * @extra:  extra information
683
 *
684
 * Handle a redefinition of attribute error
685
 */
686
static void
687
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
688
15.3k
{
689
15.3k
    if (ctxt == NULL)
690
0
  xmlXPathErrMemory(NULL, extra);
691
15.3k
    else {
692
15.3k
  ctxt->error = XPATH_MEMORY_ERROR;
693
15.3k
  xmlXPathErrMemory(ctxt->context, extra);
694
15.3k
    }
695
15.3k
}
696
697
/**
698
 * xmlXPathErr:
699
 * @ctxt:  a XPath parser context
700
 * @error:  the error code
701
 *
702
 * Handle an XPath error
703
 */
704
void
705
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
706
1.40M
{
707
1.40M
    if ((error < 0) || (error > MAXERRNO))
708
0
  error = MAXERRNO;
709
1.40M
    if (ctxt == NULL) {
710
0
  __xmlRaiseError(NULL, NULL, NULL,
711
0
      NULL, NULL, XML_FROM_XPATH,
712
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713
0
      XML_ERR_ERROR, NULL, 0,
714
0
      NULL, NULL, NULL, 0, 0,
715
0
      "%s", xmlXPathErrorMessages[error]);
716
0
  return;
717
0
    }
718
    /* Only report the first error */
719
1.40M
    if (ctxt->error != 0)
720
94.0k
        return;
721
1.31M
    ctxt->error = error;
722
1.31M
    if (ctxt->context == NULL) {
723
0
  __xmlRaiseError(NULL, NULL, NULL,
724
0
      NULL, NULL, XML_FROM_XPATH,
725
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726
0
      XML_ERR_ERROR, NULL, 0,
727
0
      (const char *) ctxt->base, NULL, NULL,
728
0
      ctxt->cur - ctxt->base, 0,
729
0
      "%s", xmlXPathErrorMessages[error]);
730
0
  return;
731
0
    }
732
733
    /* cleanup current last error */
734
1.31M
    xmlResetError(&ctxt->context->lastError);
735
736
1.31M
    ctxt->context->lastError.domain = XML_FROM_XPATH;
737
1.31M
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738
1.31M
                           XPATH_EXPRESSION_OK;
739
1.31M
    ctxt->context->lastError.level = XML_ERR_ERROR;
740
1.31M
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741
1.31M
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742
1.31M
    ctxt->context->lastError.node = ctxt->context->debugNode;
743
1.31M
    if (ctxt->context->error != NULL) {
744
0
  ctxt->context->error(ctxt->context->userData,
745
0
                       &ctxt->context->lastError);
746
1.31M
    } else {
747
1.31M
  __xmlRaiseError(NULL, NULL, NULL,
748
1.31M
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749
1.31M
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750
1.31M
      XML_ERR_ERROR, NULL, 0,
751
1.31M
      (const char *) ctxt->base, NULL, NULL,
752
1.31M
      ctxt->cur - ctxt->base, 0,
753
1.31M
      "%s", xmlXPathErrorMessages[error]);
754
1.31M
    }
755
756
1.31M
}
757
758
/**
759
 * xmlXPatherror:
760
 * @ctxt:  the XPath Parser context
761
 * @file:  the file name
762
 * @line:  the line number
763
 * @no:  the error number
764
 *
765
 * Formats an error message.
766
 */
767
void
768
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
769
161k
              int line ATTRIBUTE_UNUSED, int no) {
770
161k
    xmlXPathErr(ctxt, no);
771
161k
}
772
773
/**
774
 * xmlXPathCheckOpLimit:
775
 * @ctxt:  the XPath Parser context
776
 * @opCount:  the number of operations to be added
777
 *
778
 * Adds opCount to the running total of operations and returns -1 if the
779
 * operation limit is exceeded. Returns 0 otherwise.
780
 */
781
static int
782
73.1M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783
73.1M
    xmlXPathContextPtr xpctxt = ctxt->context;
784
785
73.1M
    if ((opCount > xpctxt->opLimit) ||
786
73.1M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787
430k
        xpctxt->opCount = xpctxt->opLimit;
788
430k
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789
430k
        return(-1);
790
430k
    }
791
792
72.6M
    xpctxt->opCount += opCount;
793
72.6M
    return(0);
794
73.1M
}
795
796
#define OP_LIMIT_EXCEEDED(ctxt, n) \
797
70.9M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
798
799
/************************************************************************
800
 *                  *
801
 *      Utilities         *
802
 *                  *
803
 ************************************************************************/
804
805
/**
806
 * xsltPointerList:
807
 *
808
 * Pointer-list for various purposes.
809
 */
810
typedef struct _xmlPointerList xmlPointerList;
811
typedef xmlPointerList *xmlPointerListPtr;
812
struct _xmlPointerList {
813
    void **items;
814
    int number;
815
    int size;
816
};
817
/*
818
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
819
* and here, we should make the functions public.
820
*/
821
static int
822
xmlPointerListAddSize(xmlPointerListPtr list,
823
           void *item,
824
           int initialSize)
825
19.6M
{
826
19.6M
    if (list->size <= list->number) {
827
55.3k
        void **tmp;
828
55.3k
        size_t newSize;
829
830
55.3k
        if (list->size == 0) {
831
26.3k
            if (initialSize <= 0)
832
425
                initialSize = 1;
833
26.3k
            newSize = initialSize;
834
29.0k
        } else {
835
29.0k
            if (list->size > 50000000) {
836
0
                xmlXPathErrMemory(NULL,
837
0
                    "xmlPointerListAddSize: re-allocating item\n");
838
0
                return(-1);
839
0
            }
840
29.0k
      newSize = list->size * 2;
841
29.0k
        }
842
55.3k
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843
55.3k
  if (tmp == NULL) {
844
13.5k
      xmlXPathErrMemory(NULL,
845
13.5k
    "xmlPointerListAddSize: re-allocating item\n");
846
13.5k
      return(-1);
847
13.5k
  }
848
41.8k
        list->items = tmp;
849
41.8k
        list->size = newSize;
850
41.8k
    }
851
19.6M
    list->items[list->number++] = item;
852
19.6M
    return(0);
853
19.6M
}
854
855
/**
856
 * xsltPointerListCreate:
857
 *
858
 * Creates an xsltPointerList structure.
859
 *
860
 * Returns a xsltPointerList structure or NULL in case of an error.
861
 */
862
static xmlPointerListPtr
863
xmlPointerListCreate(int initialSize)
864
29.8k
{
865
29.8k
    xmlPointerListPtr ret;
866
867
29.8k
    ret = xmlMalloc(sizeof(xmlPointerList));
868
29.8k
    if (ret == NULL) {
869
3.96k
  xmlXPathErrMemory(NULL,
870
3.96k
      "xmlPointerListCreate: allocating item\n");
871
3.96k
  return (NULL);
872
3.96k
    }
873
25.8k
    memset(ret, 0, sizeof(xmlPointerList));
874
25.8k
    if (initialSize > 0) {
875
25.8k
  xmlPointerListAddSize(ret, NULL, initialSize);
876
25.8k
  ret->number = 0;
877
25.8k
    }
878
25.8k
    return (ret);
879
29.8k
}
880
881
/**
882
 * xsltPointerListFree:
883
 *
884
 * Frees the xsltPointerList structure. This does not free
885
 * the content of the list.
886
 */
887
static void
888
xmlPointerListFree(xmlPointerListPtr list)
889
25.8k
{
890
25.8k
    if (list == NULL)
891
0
  return;
892
25.8k
    if (list->items != NULL)
893
25.8k
  xmlFree(list->items);
894
25.8k
    xmlFree(list);
895
25.8k
}
896
897
/************************************************************************
898
 *                  *
899
 *      Parser Types          *
900
 *                  *
901
 ************************************************************************/
902
903
/*
904
 * Types are private:
905
 */
906
907
typedef enum {
908
    XPATH_OP_END=0,
909
    XPATH_OP_AND,
910
    XPATH_OP_OR,
911
    XPATH_OP_EQUAL,
912
    XPATH_OP_CMP,
913
    XPATH_OP_PLUS,
914
    XPATH_OP_MULT,
915
    XPATH_OP_UNION,
916
    XPATH_OP_ROOT,
917
    XPATH_OP_NODE,
918
    XPATH_OP_COLLECT,
919
    XPATH_OP_VALUE, /* 11 */
920
    XPATH_OP_VARIABLE,
921
    XPATH_OP_FUNCTION,
922
    XPATH_OP_ARG,
923
    XPATH_OP_PREDICATE,
924
    XPATH_OP_FILTER, /* 16 */
925
    XPATH_OP_SORT /* 17 */
926
#ifdef LIBXML_XPTR_LOCS_ENABLED
927
    ,XPATH_OP_RANGETO
928
#endif
929
} xmlXPathOp;
930
931
typedef enum {
932
    AXIS_ANCESTOR = 1,
933
    AXIS_ANCESTOR_OR_SELF,
934
    AXIS_ATTRIBUTE,
935
    AXIS_CHILD,
936
    AXIS_DESCENDANT,
937
    AXIS_DESCENDANT_OR_SELF,
938
    AXIS_FOLLOWING,
939
    AXIS_FOLLOWING_SIBLING,
940
    AXIS_NAMESPACE,
941
    AXIS_PARENT,
942
    AXIS_PRECEDING,
943
    AXIS_PRECEDING_SIBLING,
944
    AXIS_SELF
945
} xmlXPathAxisVal;
946
947
typedef enum {
948
    NODE_TEST_NONE = 0,
949
    NODE_TEST_TYPE = 1,
950
    NODE_TEST_PI = 2,
951
    NODE_TEST_ALL = 3,
952
    NODE_TEST_NS = 4,
953
    NODE_TEST_NAME = 5
954
} xmlXPathTestVal;
955
956
typedef enum {
957
    NODE_TYPE_NODE = 0,
958
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
959
    NODE_TYPE_TEXT = XML_TEXT_NODE,
960
    NODE_TYPE_PI = XML_PI_NODE
961
} xmlXPathTypeVal;
962
963
typedef struct _xmlXPathStepOp xmlXPathStepOp;
964
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
965
struct _xmlXPathStepOp {
966
    xmlXPathOp op;    /* The identifier of the operation */
967
    int ch1;      /* First child */
968
    int ch2;      /* Second child */
969
    int value;
970
    int value2;
971
    int value3;
972
    void *value4;
973
    void *value5;
974
    xmlXPathFunction cache;
975
    void *cacheURI;
976
};
977
978
struct _xmlXPathCompExpr {
979
    int nbStep;     /* Number of steps in this expression */
980
    int maxStep;    /* Maximum number of steps allocated */
981
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
982
    int last;     /* index of last step in expression */
983
    xmlChar *expr;    /* the expression being computed */
984
    xmlDictPtr dict;    /* the dictionary to use if any */
985
#ifdef DEBUG_EVAL_COUNTS
986
    int nb;
987
    xmlChar *string;
988
#endif
989
#ifdef XPATH_STREAMING
990
    xmlPatternPtr stream;
991
#endif
992
};
993
994
/************************************************************************
995
 *                  *
996
 *      Forward declarations        *
997
 *                  *
998
 ************************************************************************/
999
static void
1000
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
1001
static void
1002
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
1003
static int
1004
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1005
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1006
static int
1007
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1008
          xmlXPathStepOpPtr op,
1009
          int isPredicate);
1010
static void
1011
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1012
1013
/************************************************************************
1014
 *                  *
1015
 *      Parser Type functions       *
1016
 *                  *
1017
 ************************************************************************/
1018
1019
/**
1020
 * xmlXPathNewCompExpr:
1021
 *
1022
 * Create a new Xpath component
1023
 *
1024
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1025
 */
1026
static xmlXPathCompExprPtr
1027
1.32M
xmlXPathNewCompExpr(void) {
1028
1.32M
    xmlXPathCompExprPtr cur;
1029
1030
1.32M
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031
1.32M
    if (cur == NULL) {
1032
89
        xmlXPathErrMemory(NULL, "allocating component\n");
1033
89
  return(NULL);
1034
89
    }
1035
1.32M
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1036
1.32M
    cur->maxStep = 10;
1037
1.32M
    cur->nbStep = 0;
1038
1.32M
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039
1.32M
                                     sizeof(xmlXPathStepOp));
1040
1.32M
    if (cur->steps == NULL) {
1041
96
        xmlXPathErrMemory(NULL, "allocating steps\n");
1042
96
  xmlFree(cur);
1043
96
  return(NULL);
1044
96
    }
1045
1.32M
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046
1.32M
    cur->last = -1;
1047
#ifdef DEBUG_EVAL_COUNTS
1048
    cur->nb = 0;
1049
#endif
1050
1.32M
    return(cur);
1051
1.32M
}
1052
1053
/**
1054
 * xmlXPathFreeCompExpr:
1055
 * @comp:  an XPATH comp
1056
 *
1057
 * Free up the memory allocated by @comp
1058
 */
1059
void
1060
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1061
1.32M
{
1062
1.32M
    xmlXPathStepOpPtr op;
1063
1.32M
    int i;
1064
1065
1.32M
    if (comp == NULL)
1066
5.30k
        return;
1067
1.32M
    if (comp->dict == NULL) {
1068
131M
  for (i = 0; i < comp->nbStep; i++) {
1069
130M
      op = &comp->steps[i];
1070
130M
      if (op->value4 != NULL) {
1071
2.24M
    if (op->op == XPATH_OP_VALUE)
1072
1.17M
        xmlXPathFreeObject(op->value4);
1073
1.07M
    else
1074
1.07M
        xmlFree(op->value4);
1075
2.24M
      }
1076
130M
      if (op->value5 != NULL)
1077
7.37M
    xmlFree(op->value5);
1078
130M
  }
1079
1.20M
    } else {
1080
12.7M
  for (i = 0; i < comp->nbStep; i++) {
1081
12.6M
      op = &comp->steps[i];
1082
12.6M
      if (op->value4 != NULL) {
1083
114k
    if (op->op == XPATH_OP_VALUE)
1084
39.1k
        xmlXPathFreeObject(op->value4);
1085
114k
      }
1086
12.6M
  }
1087
119k
        xmlDictFree(comp->dict);
1088
119k
    }
1089
1.32M
    if (comp->steps != NULL) {
1090
1.32M
        xmlFree(comp->steps);
1091
1.32M
    }
1092
#ifdef DEBUG_EVAL_COUNTS
1093
    if (comp->string != NULL) {
1094
        xmlFree(comp->string);
1095
    }
1096
#endif
1097
1.32M
#ifdef XPATH_STREAMING
1098
1.32M
    if (comp->stream != NULL) {
1099
196k
        xmlFreePatternList(comp->stream);
1100
196k
    }
1101
1.32M
#endif
1102
1.32M
    if (comp->expr != NULL) {
1103
370k
        xmlFree(comp->expr);
1104
370k
    }
1105
1106
1.32M
    xmlFree(comp);
1107
1.32M
}
1108
1109
/**
1110
 * xmlXPathCompExprAdd:
1111
 * @comp:  the compiled expression
1112
 * @ch1: first child index
1113
 * @ch2: second child index
1114
 * @op:  an op
1115
 * @value:  the first int value
1116
 * @value2:  the second int value
1117
 * @value3:  the third int value
1118
 * @value4:  the first string value
1119
 * @value5:  the second string value
1120
 *
1121
 * Add a step to an XPath Compiled Expression
1122
 *
1123
 * Returns -1 in case of failure, the index otherwise
1124
 */
1125
static int
1126
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1127
   xmlXPathOp op, int value,
1128
143M
   int value2, int value3, void *value4, void *value5) {
1129
143M
    xmlXPathCompExprPtr comp = ctxt->comp;
1130
143M
    if (comp->nbStep >= comp->maxStep) {
1131
844k
  xmlXPathStepOp *real;
1132
1133
844k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1134
14.7k
      xmlXPathPErrMemory(ctxt, "adding step\n");
1135
14.7k
      return(-1);
1136
14.7k
        }
1137
829k
  comp->maxStep *= 2;
1138
829k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139
829k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1140
829k
  if (real == NULL) {
1141
479
      comp->maxStep /= 2;
1142
479
      xmlXPathPErrMemory(ctxt, "adding step\n");
1143
479
      return(-1);
1144
479
  }
1145
829k
  comp->steps = real;
1146
829k
    }
1147
143M
    comp->last = comp->nbStep;
1148
143M
    comp->steps[comp->nbStep].ch1 = ch1;
1149
143M
    comp->steps[comp->nbStep].ch2 = ch2;
1150
143M
    comp->steps[comp->nbStep].op = op;
1151
143M
    comp->steps[comp->nbStep].value = value;
1152
143M
    comp->steps[comp->nbStep].value2 = value2;
1153
143M
    comp->steps[comp->nbStep].value3 = value3;
1154
143M
    if ((comp->dict != NULL) &&
1155
143M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1156
12.6M
   (op == XPATH_OP_COLLECT))) {
1157
4.24M
        if (value4 != NULL) {
1158
75.4k
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1159
75.4k
          (void *)xmlDictLookup(comp->dict, value4, -1);
1160
75.4k
      xmlFree(value4);
1161
75.4k
  } else
1162
4.16M
      comp->steps[comp->nbStep].value4 = NULL;
1163
4.24M
        if (value5 != NULL) {
1164
142k
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1165
142k
          (void *)xmlDictLookup(comp->dict, value5, -1);
1166
142k
      xmlFree(value5);
1167
142k
  } else
1168
4.09M
      comp->steps[comp->nbStep].value5 = NULL;
1169
138M
    } else {
1170
138M
  comp->steps[comp->nbStep].value4 = value4;
1171
138M
  comp->steps[comp->nbStep].value5 = value5;
1172
138M
    }
1173
143M
    comp->steps[comp->nbStep].cache = NULL;
1174
143M
    return(comp->nbStep++);
1175
143M
}
1176
1177
/**
1178
 * xmlXPathCompSwap:
1179
 * @comp:  the compiled expression
1180
 * @op: operation index
1181
 *
1182
 * Swaps 2 operations in the compiled expression
1183
 */
1184
static void
1185
45.6k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186
45.6k
    int tmp;
1187
1188
#ifndef LIBXML_THREAD_ENABLED
1189
    /*
1190
     * Since this manipulates possibly shared variables, this is
1191
     * disabled if one detects that the library is used in a multithreaded
1192
     * application
1193
     */
1194
    if (xmlXPathDisableOptimizer)
1195
  return;
1196
#endif
1197
1198
45.6k
    tmp = op->ch1;
1199
45.6k
    op->ch1 = op->ch2;
1200
45.6k
    op->ch2 = tmp;
1201
45.6k
}
1202
1203
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204
43.2M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1205
43.2M
                  (op), (val), (val2), (val3), (val4), (val5))
1206
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1207
2.66M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1208
2.66M
                  (op), (val), (val2), (val3), (val4), (val5))
1209
1210
48.7M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1211
48.7M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212
1213
3.27M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1214
3.27M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215
1216
45.1M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1217
45.1M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1218
45.1M
      (val), (val2), 0 ,NULL ,NULL)
1219
1220
/************************************************************************
1221
 *                  *
1222
 *    XPath object cache structures       *
1223
 *                  *
1224
 ************************************************************************/
1225
1226
/* #define XP_DEFAULT_CACHE_ON */
1227
1228
921k
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1229
1230
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1231
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1232
struct _xmlXPathContextCache {
1233
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1234
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1235
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1236
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1237
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1238
    int maxNodeset;
1239
    int maxString;
1240
    int maxBoolean;
1241
    int maxNumber;
1242
    int maxMisc;
1243
#ifdef XP_DEBUG_OBJ_USAGE
1244
    int dbgCachedAll;
1245
    int dbgCachedNodeset;
1246
    int dbgCachedString;
1247
    int dbgCachedBool;
1248
    int dbgCachedNumber;
1249
    int dbgCachedPoint;
1250
    int dbgCachedRange;
1251
    int dbgCachedLocset;
1252
    int dbgCachedUsers;
1253
    int dbgCachedXSLTTree;
1254
    int dbgCachedUndefined;
1255
1256
1257
    int dbgReusedAll;
1258
    int dbgReusedNodeset;
1259
    int dbgReusedString;
1260
    int dbgReusedBool;
1261
    int dbgReusedNumber;
1262
    int dbgReusedPoint;
1263
    int dbgReusedRange;
1264
    int dbgReusedLocset;
1265
    int dbgReusedUsers;
1266
    int dbgReusedXSLTTree;
1267
    int dbgReusedUndefined;
1268
1269
#endif
1270
};
1271
1272
/************************************************************************
1273
 *                  *
1274
 *    Debugging related functions       *
1275
 *                  *
1276
 ************************************************************************/
1277
1278
#define STRANGE             \
1279
0
    xmlGenericError(xmlGenericErrorContext,       \
1280
0
      "Internal error at %s:%d\n",        \
1281
0
            __FILE__, __LINE__);
1282
1283
#ifdef LIBXML_DEBUG_ENABLED
1284
static void
1285
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1286
0
    int i;
1287
0
    char shift[100];
1288
1289
0
    for (i = 0;((i < depth) && (i < 25));i++)
1290
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1291
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1292
0
    if (cur == NULL) {
1293
0
  fprintf(output, "%s", shift);
1294
0
  fprintf(output, "Node is NULL !\n");
1295
0
  return;
1296
1297
0
    }
1298
1299
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1300
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1301
0
  fprintf(output, "%s", shift);
1302
0
  fprintf(output, " /\n");
1303
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1304
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1305
0
    else
1306
0
  xmlDebugDumpOneNode(output, cur, depth);
1307
0
}
1308
static void
1309
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1310
0
    xmlNodePtr tmp;
1311
0
    int i;
1312
0
    char shift[100];
1313
1314
0
    for (i = 0;((i < depth) && (i < 25));i++)
1315
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1316
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1317
0
    if (cur == NULL) {
1318
0
  fprintf(output, "%s", shift);
1319
0
  fprintf(output, "Node is NULL !\n");
1320
0
  return;
1321
1322
0
    }
1323
1324
0
    while (cur != NULL) {
1325
0
  tmp = cur;
1326
0
  cur = cur->next;
1327
0
  xmlDebugDumpOneNode(output, tmp, depth);
1328
0
    }
1329
0
}
1330
1331
static void
1332
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1333
0
    int i;
1334
0
    char shift[100];
1335
1336
0
    for (i = 0;((i < depth) && (i < 25));i++)
1337
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1338
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1339
1340
0
    if (cur == NULL) {
1341
0
  fprintf(output, "%s", shift);
1342
0
  fprintf(output, "NodeSet is NULL !\n");
1343
0
  return;
1344
1345
0
    }
1346
1347
0
    if (cur != NULL) {
1348
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1349
0
  for (i = 0;i < cur->nodeNr;i++) {
1350
0
      fprintf(output, "%s", shift);
1351
0
      fprintf(output, "%d", i + 1);
1352
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1353
0
  }
1354
0
    }
1355
0
}
1356
1357
static void
1358
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1359
0
    int i;
1360
0
    char shift[100];
1361
1362
0
    for (i = 0;((i < depth) && (i < 25));i++)
1363
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1364
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1365
1366
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1367
0
  fprintf(output, "%s", shift);
1368
0
  fprintf(output, "Value Tree is NULL !\n");
1369
0
  return;
1370
1371
0
    }
1372
1373
0
    fprintf(output, "%s", shift);
1374
0
    fprintf(output, "%d", i + 1);
1375
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1376
0
}
1377
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1378
static void
1379
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1380
    int i;
1381
    char shift[100];
1382
1383
    for (i = 0;((i < depth) && (i < 25));i++)
1384
        shift[2 * i] = shift[2 * i + 1] = ' ';
1385
    shift[2 * i] = shift[2 * i + 1] = 0;
1386
1387
    if (cur == NULL) {
1388
  fprintf(output, "%s", shift);
1389
  fprintf(output, "LocationSet is NULL !\n");
1390
  return;
1391
1392
    }
1393
1394
    for (i = 0;i < cur->locNr;i++) {
1395
  fprintf(output, "%s", shift);
1396
        fprintf(output, "%d : ", i + 1);
1397
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1398
    }
1399
}
1400
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1401
1402
/**
1403
 * xmlXPathDebugDumpObject:
1404
 * @output:  the FILE * to dump the output
1405
 * @cur:  the object to inspect
1406
 * @depth:  indentation level
1407
 *
1408
 * Dump the content of the object for debugging purposes
1409
 */
1410
void
1411
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1412
0
    int i;
1413
0
    char shift[100];
1414
1415
0
    if (output == NULL) return;
1416
1417
0
    for (i = 0;((i < depth) && (i < 25));i++)
1418
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1419
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1420
1421
1422
0
    fprintf(output, "%s", shift);
1423
1424
0
    if (cur == NULL) {
1425
0
        fprintf(output, "Object is empty (NULL)\n");
1426
0
  return;
1427
0
    }
1428
0
    switch(cur->type) {
1429
0
        case XPATH_UNDEFINED:
1430
0
      fprintf(output, "Object is uninitialized\n");
1431
0
      break;
1432
0
        case XPATH_NODESET:
1433
0
      fprintf(output, "Object is a Node Set :\n");
1434
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
  case XPATH_XSLT_TREE:
1437
0
      fprintf(output, "Object is an XSLT value tree :\n");
1438
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1439
0
      break;
1440
0
        case XPATH_BOOLEAN:
1441
0
      fprintf(output, "Object is a Boolean : ");
1442
0
      if (cur->boolval) fprintf(output, "true\n");
1443
0
      else fprintf(output, "false\n");
1444
0
      break;
1445
0
        case XPATH_NUMBER:
1446
0
      switch (xmlXPathIsInf(cur->floatval)) {
1447
0
      case 1:
1448
0
    fprintf(output, "Object is a number : Infinity\n");
1449
0
    break;
1450
0
      case -1:
1451
0
    fprintf(output, "Object is a number : -Infinity\n");
1452
0
    break;
1453
0
      default:
1454
0
    if (xmlXPathIsNaN(cur->floatval)) {
1455
0
        fprintf(output, "Object is a number : NaN\n");
1456
0
    } else if (cur->floatval == 0) {
1457
                    /* Omit sign for negative zero. */
1458
0
        fprintf(output, "Object is a number : 0\n");
1459
0
    } else {
1460
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1461
0
    }
1462
0
      }
1463
0
      break;
1464
0
        case XPATH_STRING:
1465
0
      fprintf(output, "Object is a string : ");
1466
0
      xmlDebugDumpString(output, cur->stringval);
1467
0
      fprintf(output, "\n");
1468
0
      break;
1469
#ifdef LIBXML_XPTR_LOCS_ENABLED
1470
  case XPATH_POINT:
1471
      fprintf(output, "Object is a point : index %d in node", cur->index);
1472
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1473
      fprintf(output, "\n");
1474
      break;
1475
  case XPATH_RANGE:
1476
      if ((cur->user2 == NULL) ||
1477
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1478
    fprintf(output, "Object is a collapsed range :\n");
1479
    fprintf(output, "%s", shift);
1480
    if (cur->index >= 0)
1481
        fprintf(output, "index %d in ", cur->index);
1482
    fprintf(output, "node\n");
1483
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1484
                    depth + 1);
1485
      } else  {
1486
    fprintf(output, "Object is a range :\n");
1487
    fprintf(output, "%s", shift);
1488
    fprintf(output, "From ");
1489
    if (cur->index >= 0)
1490
        fprintf(output, "index %d in ", cur->index);
1491
    fprintf(output, "node\n");
1492
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1493
                    depth + 1);
1494
    fprintf(output, "%s", shift);
1495
    fprintf(output, "To ");
1496
    if (cur->index2 >= 0)
1497
        fprintf(output, "index %d in ", cur->index2);
1498
    fprintf(output, "node\n");
1499
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1500
                    depth + 1);
1501
    fprintf(output, "\n");
1502
      }
1503
      break;
1504
  case XPATH_LOCATIONSET:
1505
      fprintf(output, "Object is a Location Set:\n");
1506
      xmlXPathDebugDumpLocationSet(output,
1507
        (xmlLocationSetPtr) cur->user, depth);
1508
      break;
1509
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1510
0
  case XPATH_USERS:
1511
0
      fprintf(output, "Object is user defined\n");
1512
0
      break;
1513
0
    }
1514
0
}
1515
1516
static void
1517
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1518
0
                       xmlXPathStepOpPtr op, int depth) {
1519
0
    int i;
1520
0
    char shift[100];
1521
1522
0
    for (i = 0;((i < depth) && (i < 25));i++)
1523
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1524
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1525
1526
0
    fprintf(output, "%s", shift);
1527
0
    if (op == NULL) {
1528
0
  fprintf(output, "Step is NULL\n");
1529
0
  return;
1530
0
    }
1531
0
    switch (op->op) {
1532
0
        case XPATH_OP_END:
1533
0
      fprintf(output, "END"); break;
1534
0
        case XPATH_OP_AND:
1535
0
      fprintf(output, "AND"); break;
1536
0
        case XPATH_OP_OR:
1537
0
      fprintf(output, "OR"); break;
1538
0
        case XPATH_OP_EQUAL:
1539
0
       if (op->value)
1540
0
     fprintf(output, "EQUAL =");
1541
0
       else
1542
0
     fprintf(output, "EQUAL !=");
1543
0
       break;
1544
0
        case XPATH_OP_CMP:
1545
0
       if (op->value)
1546
0
     fprintf(output, "CMP <");
1547
0
       else
1548
0
     fprintf(output, "CMP >");
1549
0
       if (!op->value2)
1550
0
     fprintf(output, "=");
1551
0
       break;
1552
0
        case XPATH_OP_PLUS:
1553
0
       if (op->value == 0)
1554
0
     fprintf(output, "PLUS -");
1555
0
       else if (op->value == 1)
1556
0
     fprintf(output, "PLUS +");
1557
0
       else if (op->value == 2)
1558
0
     fprintf(output, "PLUS unary -");
1559
0
       else if (op->value == 3)
1560
0
     fprintf(output, "PLUS unary - -");
1561
0
       break;
1562
0
        case XPATH_OP_MULT:
1563
0
       if (op->value == 0)
1564
0
     fprintf(output, "MULT *");
1565
0
       else if (op->value == 1)
1566
0
     fprintf(output, "MULT div");
1567
0
       else
1568
0
     fprintf(output, "MULT mod");
1569
0
       break;
1570
0
        case XPATH_OP_UNION:
1571
0
       fprintf(output, "UNION"); break;
1572
0
        case XPATH_OP_ROOT:
1573
0
       fprintf(output, "ROOT"); break;
1574
0
        case XPATH_OP_NODE:
1575
0
       fprintf(output, "NODE"); break;
1576
0
        case XPATH_OP_SORT:
1577
0
       fprintf(output, "SORT"); break;
1578
0
        case XPATH_OP_COLLECT: {
1579
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1580
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1581
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1582
0
      const xmlChar *prefix = op->value4;
1583
0
      const xmlChar *name = op->value5;
1584
1585
0
      fprintf(output, "COLLECT ");
1586
0
      switch (axis) {
1587
0
    case AXIS_ANCESTOR:
1588
0
        fprintf(output, " 'ancestors' "); break;
1589
0
    case AXIS_ANCESTOR_OR_SELF:
1590
0
        fprintf(output, " 'ancestors-or-self' "); break;
1591
0
    case AXIS_ATTRIBUTE:
1592
0
        fprintf(output, " 'attributes' "); break;
1593
0
    case AXIS_CHILD:
1594
0
        fprintf(output, " 'child' "); break;
1595
0
    case AXIS_DESCENDANT:
1596
0
        fprintf(output, " 'descendant' "); break;
1597
0
    case AXIS_DESCENDANT_OR_SELF:
1598
0
        fprintf(output, " 'descendant-or-self' "); break;
1599
0
    case AXIS_FOLLOWING:
1600
0
        fprintf(output, " 'following' "); break;
1601
0
    case AXIS_FOLLOWING_SIBLING:
1602
0
        fprintf(output, " 'following-siblings' "); break;
1603
0
    case AXIS_NAMESPACE:
1604
0
        fprintf(output, " 'namespace' "); break;
1605
0
    case AXIS_PARENT:
1606
0
        fprintf(output, " 'parent' "); break;
1607
0
    case AXIS_PRECEDING:
1608
0
        fprintf(output, " 'preceding' "); break;
1609
0
    case AXIS_PRECEDING_SIBLING:
1610
0
        fprintf(output, " 'preceding-sibling' "); break;
1611
0
    case AXIS_SELF:
1612
0
        fprintf(output, " 'self' "); break;
1613
0
      }
1614
0
      switch (test) {
1615
0
                case NODE_TEST_NONE:
1616
0
        fprintf(output, "'none' "); break;
1617
0
                case NODE_TEST_TYPE:
1618
0
        fprintf(output, "'type' "); break;
1619
0
                case NODE_TEST_PI:
1620
0
        fprintf(output, "'PI' "); break;
1621
0
                case NODE_TEST_ALL:
1622
0
        fprintf(output, "'all' "); break;
1623
0
                case NODE_TEST_NS:
1624
0
        fprintf(output, "'namespace' "); break;
1625
0
                case NODE_TEST_NAME:
1626
0
        fprintf(output, "'name' "); break;
1627
0
      }
1628
0
      switch (type) {
1629
0
                case NODE_TYPE_NODE:
1630
0
        fprintf(output, "'node' "); break;
1631
0
                case NODE_TYPE_COMMENT:
1632
0
        fprintf(output, "'comment' "); break;
1633
0
                case NODE_TYPE_TEXT:
1634
0
        fprintf(output, "'text' "); break;
1635
0
                case NODE_TYPE_PI:
1636
0
        fprintf(output, "'PI' "); break;
1637
0
      }
1638
0
      if (prefix != NULL)
1639
0
    fprintf(output, "%s:", prefix);
1640
0
      if (name != NULL)
1641
0
    fprintf(output, "%s", (const char *) name);
1642
0
      break;
1643
1644
0
        }
1645
0
  case XPATH_OP_VALUE: {
1646
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1647
1648
0
      fprintf(output, "ELEM ");
1649
0
      xmlXPathDebugDumpObject(output, object, 0);
1650
0
      goto finish;
1651
0
  }
1652
0
  case XPATH_OP_VARIABLE: {
1653
0
      const xmlChar *prefix = op->value5;
1654
0
      const xmlChar *name = op->value4;
1655
1656
0
      if (prefix != NULL)
1657
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1658
0
      else
1659
0
    fprintf(output, "VARIABLE %s", name);
1660
0
      break;
1661
0
  }
1662
0
  case XPATH_OP_FUNCTION: {
1663
0
      int nbargs = op->value;
1664
0
      const xmlChar *prefix = op->value5;
1665
0
      const xmlChar *name = op->value4;
1666
1667
0
      if (prefix != NULL)
1668
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1669
0
      prefix, name, nbargs);
1670
0
      else
1671
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1672
0
      break;
1673
0
  }
1674
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1675
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1676
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1677
#ifdef LIBXML_XPTR_LOCS_ENABLED
1678
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1679
#endif
1680
0
  default:
1681
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1682
0
    }
1683
0
    fprintf(output, "\n");
1684
0
finish:
1685
0
    if (op->ch1 >= 0)
1686
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1687
0
    if (op->ch2 >= 0)
1688
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1689
0
}
1690
1691
/**
1692
 * xmlXPathDebugDumpCompExpr:
1693
 * @output:  the FILE * for the output
1694
 * @comp:  the precompiled XPath expression
1695
 * @depth:  the indentation level.
1696
 *
1697
 * Dumps the tree of the compiled XPath expression.
1698
 */
1699
void
1700
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1701
0
                    int depth) {
1702
0
    int i;
1703
0
    char shift[100];
1704
1705
0
    if ((output == NULL) || (comp == NULL)) return;
1706
1707
0
    for (i = 0;((i < depth) && (i < 25));i++)
1708
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1709
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1710
1711
0
    fprintf(output, "%s", shift);
1712
1713
0
#ifdef XPATH_STREAMING
1714
0
    if (comp->stream) {
1715
0
        fprintf(output, "Streaming Expression\n");
1716
0
    } else
1717
0
#endif
1718
0
    {
1719
0
        fprintf(output, "Compiled Expression : %d elements\n",
1720
0
                comp->nbStep);
1721
0
        i = comp->last;
1722
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1723
0
    }
1724
0
}
1725
1726
#ifdef XP_DEBUG_OBJ_USAGE
1727
1728
/*
1729
* XPath object usage related debugging variables.
1730
*/
1731
static int xmlXPathDebugObjCounterUndefined = 0;
1732
static int xmlXPathDebugObjCounterNodeset = 0;
1733
static int xmlXPathDebugObjCounterBool = 0;
1734
static int xmlXPathDebugObjCounterNumber = 0;
1735
static int xmlXPathDebugObjCounterString = 0;
1736
static int xmlXPathDebugObjCounterPoint = 0;
1737
static int xmlXPathDebugObjCounterRange = 0;
1738
static int xmlXPathDebugObjCounterLocset = 0;
1739
static int xmlXPathDebugObjCounterUsers = 0;
1740
static int xmlXPathDebugObjCounterXSLTTree = 0;
1741
static int xmlXPathDebugObjCounterAll = 0;
1742
1743
static int xmlXPathDebugObjTotalUndefined = 0;
1744
static int xmlXPathDebugObjTotalNodeset = 0;
1745
static int xmlXPathDebugObjTotalBool = 0;
1746
static int xmlXPathDebugObjTotalNumber = 0;
1747
static int xmlXPathDebugObjTotalString = 0;
1748
static int xmlXPathDebugObjTotalPoint = 0;
1749
static int xmlXPathDebugObjTotalRange = 0;
1750
static int xmlXPathDebugObjTotalLocset = 0;
1751
static int xmlXPathDebugObjTotalUsers = 0;
1752
static int xmlXPathDebugObjTotalXSLTTree = 0;
1753
static int xmlXPathDebugObjTotalAll = 0;
1754
1755
static int xmlXPathDebugObjMaxUndefined = 0;
1756
static int xmlXPathDebugObjMaxNodeset = 0;
1757
static int xmlXPathDebugObjMaxBool = 0;
1758
static int xmlXPathDebugObjMaxNumber = 0;
1759
static int xmlXPathDebugObjMaxString = 0;
1760
static int xmlXPathDebugObjMaxPoint = 0;
1761
static int xmlXPathDebugObjMaxRange = 0;
1762
static int xmlXPathDebugObjMaxLocset = 0;
1763
static int xmlXPathDebugObjMaxUsers = 0;
1764
static int xmlXPathDebugObjMaxXSLTTree = 0;
1765
static int xmlXPathDebugObjMaxAll = 0;
1766
1767
static void
1768
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1769
{
1770
    if (ctxt != NULL) {
1771
  if (ctxt->cache != NULL) {
1772
      xmlXPathContextCachePtr cache =
1773
    (xmlXPathContextCachePtr) ctxt->cache;
1774
1775
      cache->dbgCachedAll = 0;
1776
      cache->dbgCachedNodeset = 0;
1777
      cache->dbgCachedString = 0;
1778
      cache->dbgCachedBool = 0;
1779
      cache->dbgCachedNumber = 0;
1780
      cache->dbgCachedPoint = 0;
1781
      cache->dbgCachedRange = 0;
1782
      cache->dbgCachedLocset = 0;
1783
      cache->dbgCachedUsers = 0;
1784
      cache->dbgCachedXSLTTree = 0;
1785
      cache->dbgCachedUndefined = 0;
1786
1787
      cache->dbgReusedAll = 0;
1788
      cache->dbgReusedNodeset = 0;
1789
      cache->dbgReusedString = 0;
1790
      cache->dbgReusedBool = 0;
1791
      cache->dbgReusedNumber = 0;
1792
      cache->dbgReusedPoint = 0;
1793
      cache->dbgReusedRange = 0;
1794
      cache->dbgReusedLocset = 0;
1795
      cache->dbgReusedUsers = 0;
1796
      cache->dbgReusedXSLTTree = 0;
1797
      cache->dbgReusedUndefined = 0;
1798
  }
1799
    }
1800
1801
    xmlXPathDebugObjCounterUndefined = 0;
1802
    xmlXPathDebugObjCounterNodeset = 0;
1803
    xmlXPathDebugObjCounterBool = 0;
1804
    xmlXPathDebugObjCounterNumber = 0;
1805
    xmlXPathDebugObjCounterString = 0;
1806
    xmlXPathDebugObjCounterPoint = 0;
1807
    xmlXPathDebugObjCounterRange = 0;
1808
    xmlXPathDebugObjCounterLocset = 0;
1809
    xmlXPathDebugObjCounterUsers = 0;
1810
    xmlXPathDebugObjCounterXSLTTree = 0;
1811
    xmlXPathDebugObjCounterAll = 0;
1812
1813
    xmlXPathDebugObjTotalUndefined = 0;
1814
    xmlXPathDebugObjTotalNodeset = 0;
1815
    xmlXPathDebugObjTotalBool = 0;
1816
    xmlXPathDebugObjTotalNumber = 0;
1817
    xmlXPathDebugObjTotalString = 0;
1818
    xmlXPathDebugObjTotalPoint = 0;
1819
    xmlXPathDebugObjTotalRange = 0;
1820
    xmlXPathDebugObjTotalLocset = 0;
1821
    xmlXPathDebugObjTotalUsers = 0;
1822
    xmlXPathDebugObjTotalXSLTTree = 0;
1823
    xmlXPathDebugObjTotalAll = 0;
1824
1825
    xmlXPathDebugObjMaxUndefined = 0;
1826
    xmlXPathDebugObjMaxNodeset = 0;
1827
    xmlXPathDebugObjMaxBool = 0;
1828
    xmlXPathDebugObjMaxNumber = 0;
1829
    xmlXPathDebugObjMaxString = 0;
1830
    xmlXPathDebugObjMaxPoint = 0;
1831
    xmlXPathDebugObjMaxRange = 0;
1832
    xmlXPathDebugObjMaxLocset = 0;
1833
    xmlXPathDebugObjMaxUsers = 0;
1834
    xmlXPathDebugObjMaxXSLTTree = 0;
1835
    xmlXPathDebugObjMaxAll = 0;
1836
1837
}
1838
1839
static void
1840
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1841
            xmlXPathObjectType objType)
1842
{
1843
    int isCached = 0;
1844
1845
    if (ctxt != NULL) {
1846
  if (ctxt->cache != NULL) {
1847
      xmlXPathContextCachePtr cache =
1848
    (xmlXPathContextCachePtr) ctxt->cache;
1849
1850
      isCached = 1;
1851
1852
      cache->dbgReusedAll++;
1853
      switch (objType) {
1854
    case XPATH_UNDEFINED:
1855
        cache->dbgReusedUndefined++;
1856
        break;
1857
    case XPATH_NODESET:
1858
        cache->dbgReusedNodeset++;
1859
        break;
1860
    case XPATH_BOOLEAN:
1861
        cache->dbgReusedBool++;
1862
        break;
1863
    case XPATH_NUMBER:
1864
        cache->dbgReusedNumber++;
1865
        break;
1866
    case XPATH_STRING:
1867
        cache->dbgReusedString++;
1868
        break;
1869
#ifdef LIBXML_XPTR_LOCS_ENABLED
1870
    case XPATH_POINT:
1871
        cache->dbgReusedPoint++;
1872
        break;
1873
    case XPATH_RANGE:
1874
        cache->dbgReusedRange++;
1875
        break;
1876
    case XPATH_LOCATIONSET:
1877
        cache->dbgReusedLocset++;
1878
        break;
1879
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1880
    case XPATH_USERS:
1881
        cache->dbgReusedUsers++;
1882
        break;
1883
    case XPATH_XSLT_TREE:
1884
        cache->dbgReusedXSLTTree++;
1885
        break;
1886
    default:
1887
        break;
1888
      }
1889
  }
1890
    }
1891
1892
    switch (objType) {
1893
  case XPATH_UNDEFINED:
1894
      if (! isCached)
1895
    xmlXPathDebugObjTotalUndefined++;
1896
      xmlXPathDebugObjCounterUndefined++;
1897
      if (xmlXPathDebugObjCounterUndefined >
1898
    xmlXPathDebugObjMaxUndefined)
1899
    xmlXPathDebugObjMaxUndefined =
1900
        xmlXPathDebugObjCounterUndefined;
1901
      break;
1902
  case XPATH_NODESET:
1903
      if (! isCached)
1904
    xmlXPathDebugObjTotalNodeset++;
1905
      xmlXPathDebugObjCounterNodeset++;
1906
      if (xmlXPathDebugObjCounterNodeset >
1907
    xmlXPathDebugObjMaxNodeset)
1908
    xmlXPathDebugObjMaxNodeset =
1909
        xmlXPathDebugObjCounterNodeset;
1910
      break;
1911
  case XPATH_BOOLEAN:
1912
      if (! isCached)
1913
    xmlXPathDebugObjTotalBool++;
1914
      xmlXPathDebugObjCounterBool++;
1915
      if (xmlXPathDebugObjCounterBool >
1916
    xmlXPathDebugObjMaxBool)
1917
    xmlXPathDebugObjMaxBool =
1918
        xmlXPathDebugObjCounterBool;
1919
      break;
1920
  case XPATH_NUMBER:
1921
      if (! isCached)
1922
    xmlXPathDebugObjTotalNumber++;
1923
      xmlXPathDebugObjCounterNumber++;
1924
      if (xmlXPathDebugObjCounterNumber >
1925
    xmlXPathDebugObjMaxNumber)
1926
    xmlXPathDebugObjMaxNumber =
1927
        xmlXPathDebugObjCounterNumber;
1928
      break;
1929
  case XPATH_STRING:
1930
      if (! isCached)
1931
    xmlXPathDebugObjTotalString++;
1932
      xmlXPathDebugObjCounterString++;
1933
      if (xmlXPathDebugObjCounterString >
1934
    xmlXPathDebugObjMaxString)
1935
    xmlXPathDebugObjMaxString =
1936
        xmlXPathDebugObjCounterString;
1937
      break;
1938
#ifdef LIBXML_XPTR_LOCS_ENABLED
1939
  case XPATH_POINT:
1940
      if (! isCached)
1941
    xmlXPathDebugObjTotalPoint++;
1942
      xmlXPathDebugObjCounterPoint++;
1943
      if (xmlXPathDebugObjCounterPoint >
1944
    xmlXPathDebugObjMaxPoint)
1945
    xmlXPathDebugObjMaxPoint =
1946
        xmlXPathDebugObjCounterPoint;
1947
      break;
1948
  case XPATH_RANGE:
1949
      if (! isCached)
1950
    xmlXPathDebugObjTotalRange++;
1951
      xmlXPathDebugObjCounterRange++;
1952
      if (xmlXPathDebugObjCounterRange >
1953
    xmlXPathDebugObjMaxRange)
1954
    xmlXPathDebugObjMaxRange =
1955
        xmlXPathDebugObjCounterRange;
1956
      break;
1957
  case XPATH_LOCATIONSET:
1958
      if (! isCached)
1959
    xmlXPathDebugObjTotalLocset++;
1960
      xmlXPathDebugObjCounterLocset++;
1961
      if (xmlXPathDebugObjCounterLocset >
1962
    xmlXPathDebugObjMaxLocset)
1963
    xmlXPathDebugObjMaxLocset =
1964
        xmlXPathDebugObjCounterLocset;
1965
      break;
1966
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1967
  case XPATH_USERS:
1968
      if (! isCached)
1969
    xmlXPathDebugObjTotalUsers++;
1970
      xmlXPathDebugObjCounterUsers++;
1971
      if (xmlXPathDebugObjCounterUsers >
1972
    xmlXPathDebugObjMaxUsers)
1973
    xmlXPathDebugObjMaxUsers =
1974
        xmlXPathDebugObjCounterUsers;
1975
      break;
1976
  case XPATH_XSLT_TREE:
1977
      if (! isCached)
1978
    xmlXPathDebugObjTotalXSLTTree++;
1979
      xmlXPathDebugObjCounterXSLTTree++;
1980
      if (xmlXPathDebugObjCounterXSLTTree >
1981
    xmlXPathDebugObjMaxXSLTTree)
1982
    xmlXPathDebugObjMaxXSLTTree =
1983
        xmlXPathDebugObjCounterXSLTTree;
1984
      break;
1985
  default:
1986
      break;
1987
    }
1988
    if (! isCached)
1989
  xmlXPathDebugObjTotalAll++;
1990
    xmlXPathDebugObjCounterAll++;
1991
    if (xmlXPathDebugObjCounterAll >
1992
  xmlXPathDebugObjMaxAll)
1993
  xmlXPathDebugObjMaxAll =
1994
      xmlXPathDebugObjCounterAll;
1995
}
1996
1997
static void
1998
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1999
            xmlXPathObjectType objType)
2000
{
2001
    int isCached = 0;
2002
2003
    if (ctxt != NULL) {
2004
  if (ctxt->cache != NULL) {
2005
      xmlXPathContextCachePtr cache =
2006
    (xmlXPathContextCachePtr) ctxt->cache;
2007
2008
      isCached = 1;
2009
2010
      cache->dbgCachedAll++;
2011
      switch (objType) {
2012
    case XPATH_UNDEFINED:
2013
        cache->dbgCachedUndefined++;
2014
        break;
2015
    case XPATH_NODESET:
2016
        cache->dbgCachedNodeset++;
2017
        break;
2018
    case XPATH_BOOLEAN:
2019
        cache->dbgCachedBool++;
2020
        break;
2021
    case XPATH_NUMBER:
2022
        cache->dbgCachedNumber++;
2023
        break;
2024
    case XPATH_STRING:
2025
        cache->dbgCachedString++;
2026
        break;
2027
#ifdef LIBXML_XPTR_LOCS_ENABLED
2028
    case XPATH_POINT:
2029
        cache->dbgCachedPoint++;
2030
        break;
2031
    case XPATH_RANGE:
2032
        cache->dbgCachedRange++;
2033
        break;
2034
    case XPATH_LOCATIONSET:
2035
        cache->dbgCachedLocset++;
2036
        break;
2037
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2038
    case XPATH_USERS:
2039
        cache->dbgCachedUsers++;
2040
        break;
2041
    case XPATH_XSLT_TREE:
2042
        cache->dbgCachedXSLTTree++;
2043
        break;
2044
    default:
2045
        break;
2046
      }
2047
2048
  }
2049
    }
2050
    switch (objType) {
2051
  case XPATH_UNDEFINED:
2052
      xmlXPathDebugObjCounterUndefined--;
2053
      break;
2054
  case XPATH_NODESET:
2055
      xmlXPathDebugObjCounterNodeset--;
2056
      break;
2057
  case XPATH_BOOLEAN:
2058
      xmlXPathDebugObjCounterBool--;
2059
      break;
2060
  case XPATH_NUMBER:
2061
      xmlXPathDebugObjCounterNumber--;
2062
      break;
2063
  case XPATH_STRING:
2064
      xmlXPathDebugObjCounterString--;
2065
      break;
2066
#ifdef LIBXML_XPTR_LOCS_ENABLED
2067
  case XPATH_POINT:
2068
      xmlXPathDebugObjCounterPoint--;
2069
      break;
2070
  case XPATH_RANGE:
2071
      xmlXPathDebugObjCounterRange--;
2072
      break;
2073
  case XPATH_LOCATIONSET:
2074
      xmlXPathDebugObjCounterLocset--;
2075
      break;
2076
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2077
  case XPATH_USERS:
2078
      xmlXPathDebugObjCounterUsers--;
2079
      break;
2080
  case XPATH_XSLT_TREE:
2081
      xmlXPathDebugObjCounterXSLTTree--;
2082
      break;
2083
  default:
2084
      break;
2085
    }
2086
    xmlXPathDebugObjCounterAll--;
2087
}
2088
2089
static void
2090
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2091
{
2092
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2093
  reqXSLTTree, reqUndefined;
2094
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2095
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2096
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2097
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2098
    int leftObjs = xmlXPathDebugObjCounterAll;
2099
2100
    reqAll = xmlXPathDebugObjTotalAll;
2101
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2102
    reqString = xmlXPathDebugObjTotalString;
2103
    reqBool = xmlXPathDebugObjTotalBool;
2104
    reqNumber = xmlXPathDebugObjTotalNumber;
2105
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2106
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2107
2108
    printf("# XPath object usage:\n");
2109
2110
    if (ctxt != NULL) {
2111
  if (ctxt->cache != NULL) {
2112
      xmlXPathContextCachePtr cache =
2113
    (xmlXPathContextCachePtr) ctxt->cache;
2114
2115
      reAll = cache->dbgReusedAll;
2116
      reqAll += reAll;
2117
      reNodeset = cache->dbgReusedNodeset;
2118
      reqNodeset += reNodeset;
2119
      reString = cache->dbgReusedString;
2120
      reqString += reString;
2121
      reBool = cache->dbgReusedBool;
2122
      reqBool += reBool;
2123
      reNumber = cache->dbgReusedNumber;
2124
      reqNumber += reNumber;
2125
      reXSLTTree = cache->dbgReusedXSLTTree;
2126
      reqXSLTTree += reXSLTTree;
2127
      reUndefined = cache->dbgReusedUndefined;
2128
      reqUndefined += reUndefined;
2129
2130
      caAll = cache->dbgCachedAll;
2131
      caBool = cache->dbgCachedBool;
2132
      caNodeset = cache->dbgCachedNodeset;
2133
      caString = cache->dbgCachedString;
2134
      caNumber = cache->dbgCachedNumber;
2135
      caXSLTTree = cache->dbgCachedXSLTTree;
2136
      caUndefined = cache->dbgCachedUndefined;
2137
2138
      if (cache->nodesetObjs)
2139
    leftObjs -= cache->nodesetObjs->number;
2140
      if (cache->stringObjs)
2141
    leftObjs -= cache->stringObjs->number;
2142
      if (cache->booleanObjs)
2143
    leftObjs -= cache->booleanObjs->number;
2144
      if (cache->numberObjs)
2145
    leftObjs -= cache->numberObjs->number;
2146
      if (cache->miscObjs)
2147
    leftObjs -= cache->miscObjs->number;
2148
  }
2149
    }
2150
2151
    printf("# all\n");
2152
    printf("#   total  : %d\n", reqAll);
2153
    printf("#   left  : %d\n", leftObjs);
2154
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2155
    printf("#   reused : %d\n", reAll);
2156
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2157
2158
    printf("# node-sets\n");
2159
    printf("#   total  : %d\n", reqNodeset);
2160
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2161
    printf("#   reused : %d\n", reNodeset);
2162
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2163
2164
    printf("# strings\n");
2165
    printf("#   total  : %d\n", reqString);
2166
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2167
    printf("#   reused : %d\n", reString);
2168
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2169
2170
    printf("# booleans\n");
2171
    printf("#   total  : %d\n", reqBool);
2172
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2173
    printf("#   reused : %d\n", reBool);
2174
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2175
2176
    printf("# numbers\n");
2177
    printf("#   total  : %d\n", reqNumber);
2178
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2179
    printf("#   reused : %d\n", reNumber);
2180
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2181
2182
    printf("# XSLT result tree fragments\n");
2183
    printf("#   total  : %d\n", reqXSLTTree);
2184
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2185
    printf("#   reused : %d\n", reXSLTTree);
2186
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2187
2188
    printf("# undefined\n");
2189
    printf("#   total  : %d\n", reqUndefined);
2190
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2191
    printf("#   reused : %d\n", reUndefined);
2192
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2193
2194
}
2195
2196
#endif /* XP_DEBUG_OBJ_USAGE */
2197
2198
#endif /* LIBXML_DEBUG_ENABLED */
2199
2200
/************************************************************************
2201
 *                  *
2202
 *      XPath object caching        *
2203
 *                  *
2204
 ************************************************************************/
2205
2206
/**
2207
 * xmlXPathNewCache:
2208
 *
2209
 * Create a new object cache
2210
 *
2211
 * Returns the xmlXPathCache just allocated.
2212
 */
2213
static xmlXPathContextCachePtr
2214
xmlXPathNewCache(void)
2215
37.7k
{
2216
37.7k
    xmlXPathContextCachePtr ret;
2217
2218
37.7k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219
37.7k
    if (ret == NULL) {
2220
25
        xmlXPathErrMemory(NULL, "creating object cache\n");
2221
25
  return(NULL);
2222
25
    }
2223
37.6k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2224
37.6k
    ret->maxNodeset = 100;
2225
37.6k
    ret->maxString = 100;
2226
37.6k
    ret->maxBoolean = 100;
2227
37.6k
    ret->maxNumber = 100;
2228
37.6k
    ret->maxMisc = 100;
2229
37.6k
    return(ret);
2230
37.7k
}
2231
2232
static void
2233
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234
25.8k
{
2235
25.8k
    int i;
2236
25.8k
    xmlXPathObjectPtr obj;
2237
2238
25.8k
    if (list == NULL)
2239
0
  return;
2240
2241
406k
    for (i = 0; i < list->number; i++) {
2242
380k
  obj = list->items[i];
2243
  /*
2244
  * Note that it is already assured that we don't need to
2245
  * look out for namespace nodes in the node-set.
2246
  */
2247
380k
  if (obj->nodesetval != NULL) {
2248
298k
      if (obj->nodesetval->nodeTab != NULL)
2249
264k
    xmlFree(obj->nodesetval->nodeTab);
2250
298k
      xmlFree(obj->nodesetval);
2251
298k
  }
2252
380k
  xmlFree(obj);
2253
#ifdef XP_DEBUG_OBJ_USAGE
2254
  xmlXPathDebugObjCounterAll--;
2255
#endif
2256
380k
    }
2257
25.8k
    xmlPointerListFree(list);
2258
25.8k
}
2259
2260
static void
2261
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262
37.6k
{
2263
37.6k
    if (cache == NULL)
2264
0
  return;
2265
37.6k
    if (cache->nodesetObjs)
2266
10.9k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267
37.6k
    if (cache->stringObjs)
2268
2.53k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2269
37.6k
    if (cache->booleanObjs)
2270
3.03k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271
37.6k
    if (cache->numberObjs)
2272
3.58k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2273
37.6k
    if (cache->miscObjs)
2274
5.75k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2275
37.6k
    xmlFree(cache);
2276
37.6k
}
2277
2278
/**
2279
 * xmlXPathContextSetCache:
2280
 *
2281
 * @ctxt:  the XPath context
2282
 * @active: enables/disables (creates/frees) the cache
2283
 * @value: a value with semantics dependent on @options
2284
 * @options: options (currently only the value 0 is used)
2285
 *
2286
 * Creates/frees an object cache on the XPath context.
2287
 * If activates XPath objects (xmlXPathObject) will be cached internally
2288
 * to be reused.
2289
 * @options:
2290
 *   0: This will set the XPath object caching:
2291
 *      @value:
2292
 *        This will set the maximum number of XPath objects
2293
 *        to be cached per slot
2294
 *        There are 5 slots for: node-set, string, number, boolean, and
2295
 *        misc objects. Use <0 for the default number (100).
2296
 *   Other values for @options have currently no effect.
2297
 *
2298
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2299
 */
2300
int
2301
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2302
      int active,
2303
      int value,
2304
      int options)
2305
37.7k
{
2306
37.7k
    if (ctxt == NULL)
2307
0
  return(-1);
2308
37.7k
    if (active) {
2309
37.7k
  xmlXPathContextCachePtr cache;
2310
2311
37.7k
  if (ctxt->cache == NULL) {
2312
37.7k
      ctxt->cache = xmlXPathNewCache();
2313
37.7k
      if (ctxt->cache == NULL)
2314
25
    return(-1);
2315
37.7k
  }
2316
37.6k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2317
37.6k
  if (options == 0) {
2318
37.6k
      if (value < 0)
2319
37.6k
    value = 100;
2320
37.6k
      cache->maxNodeset = value;
2321
37.6k
      cache->maxString = value;
2322
37.6k
      cache->maxNumber = value;
2323
37.6k
      cache->maxBoolean = value;
2324
37.6k
      cache->maxMisc = value;
2325
37.6k
  }
2326
37.6k
    } else if (ctxt->cache != NULL) {
2327
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328
0
  ctxt->cache = NULL;
2329
0
    }
2330
37.6k
    return(0);
2331
37.7k
}
2332
2333
/**
2334
 * xmlXPathCacheWrapNodeSet:
2335
 * @ctxt: the XPath context
2336
 * @val:  the NodePtr value
2337
 *
2338
 * This is the cached version of xmlXPathWrapNodeSet().
2339
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2340
 *
2341
 * Returns the created or reused object.
2342
 *
2343
 * In case of error the node set is destroyed and NULL is returned.
2344
 */
2345
static xmlXPathObjectPtr
2346
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2347
4.91M
{
2348
4.91M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349
4.89M
  xmlXPathContextCachePtr cache =
2350
4.89M
      (xmlXPathContextCachePtr) ctxt->cache;
2351
2352
4.89M
  if ((cache->miscObjs != NULL) &&
2353
4.89M
      (cache->miscObjs->number != 0))
2354
2.92M
  {
2355
2.92M
      xmlXPathObjectPtr ret;
2356
2357
2.92M
      ret = (xmlXPathObjectPtr)
2358
2.92M
    cache->miscObjs->items[--cache->miscObjs->number];
2359
2.92M
      ret->type = XPATH_NODESET;
2360
2.92M
      ret->nodesetval = val;
2361
#ifdef XP_DEBUG_OBJ_USAGE
2362
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363
#endif
2364
2.92M
      return(ret);
2365
2.92M
  }
2366
4.89M
    }
2367
2368
1.98M
    return(xmlXPathWrapNodeSet(val));
2369
2370
4.91M
}
2371
2372
/**
2373
 * xmlXPathCacheWrapString:
2374
 * @ctxt: the XPath context
2375
 * @val:  the xmlChar * value
2376
 *
2377
 * This is the cached version of xmlXPathWrapString().
2378
 * Wraps the @val string into an XPath object.
2379
 *
2380
 * Returns the created or reused object.
2381
 */
2382
static xmlXPathObjectPtr
2383
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2384
475k
{
2385
475k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386
475k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387
2388
475k
  if ((cache->stringObjs != NULL) &&
2389
475k
      (cache->stringObjs->number != 0))
2390
25.1k
  {
2391
2392
25.1k
      xmlXPathObjectPtr ret;
2393
2394
25.1k
      ret = (xmlXPathObjectPtr)
2395
25.1k
    cache->stringObjs->items[--cache->stringObjs->number];
2396
25.1k
      ret->type = XPATH_STRING;
2397
25.1k
      ret->stringval = val;
2398
#ifdef XP_DEBUG_OBJ_USAGE
2399
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400
#endif
2401
25.1k
      return(ret);
2402
449k
  } else if ((cache->miscObjs != NULL) &&
2403
449k
      (cache->miscObjs->number != 0))
2404
426k
  {
2405
426k
      xmlXPathObjectPtr ret;
2406
      /*
2407
      * Fallback to misc-cache.
2408
      */
2409
426k
      ret = (xmlXPathObjectPtr)
2410
426k
    cache->miscObjs->items[--cache->miscObjs->number];
2411
2412
426k
      ret->type = XPATH_STRING;
2413
426k
      ret->stringval = val;
2414
#ifdef XP_DEBUG_OBJ_USAGE
2415
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416
#endif
2417
426k
      return(ret);
2418
426k
  }
2419
475k
    }
2420
23.8k
    return(xmlXPathWrapString(val));
2421
475k
}
2422
2423
/**
2424
 * xmlXPathCacheNewNodeSet:
2425
 * @ctxt: the XPath context
2426
 * @val:  the NodePtr value
2427
 *
2428
 * This is the cached version of xmlXPathNewNodeSet().
2429
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2430
 * it with the single Node @val
2431
 *
2432
 * Returns the created or reused object.
2433
 */
2434
static xmlXPathObjectPtr
2435
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2436
9.24M
{
2437
9.24M
    if ((ctxt != NULL) && (ctxt->cache)) {
2438
9.24M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439
2440
9.24M
  if ((cache->nodesetObjs != NULL) &&
2441
9.24M
      (cache->nodesetObjs->number != 0))
2442
7.45M
  {
2443
7.45M
      xmlXPathObjectPtr ret;
2444
      /*
2445
      * Use the nodeset-cache.
2446
      */
2447
7.45M
      ret = (xmlXPathObjectPtr)
2448
7.45M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449
7.45M
      ret->type = XPATH_NODESET;
2450
7.45M
      ret->boolval = 0;
2451
7.45M
      if (val) {
2452
6.72M
    if ((ret->nodesetval->nodeMax == 0) ||
2453
6.72M
        (val->type == XML_NAMESPACE_DECL))
2454
1.00M
    {
2455
                    /* TODO: Check memory error. */
2456
1.00M
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457
5.72M
    } else {
2458
5.72M
        ret->nodesetval->nodeTab[0] = val;
2459
5.72M
        ret->nodesetval->nodeNr = 1;
2460
5.72M
    }
2461
6.72M
      }
2462
#ifdef XP_DEBUG_OBJ_USAGE
2463
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464
#endif
2465
7.45M
      return(ret);
2466
7.45M
  } else if ((cache->miscObjs != NULL) &&
2467
1.78M
      (cache->miscObjs->number != 0))
2468
141k
  {
2469
141k
      xmlXPathObjectPtr ret;
2470
141k
            xmlNodeSetPtr set;
2471
      /*
2472
      * Fallback to misc-cache.
2473
      */
2474
2475
141k
      set = xmlXPathNodeSetCreate(val);
2476
141k
      if (set == NULL) {
2477
126
    ctxt->lastError.domain = XML_FROM_XPATH;
2478
126
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2479
126
    return(NULL);
2480
126
      }
2481
2482
141k
      ret = (xmlXPathObjectPtr)
2483
141k
    cache->miscObjs->items[--cache->miscObjs->number];
2484
2485
141k
      ret->type = XPATH_NODESET;
2486
141k
      ret->boolval = 0;
2487
141k
      ret->nodesetval = set;
2488
#ifdef XP_DEBUG_OBJ_USAGE
2489
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490
#endif
2491
141k
      return(ret);
2492
141k
  }
2493
9.24M
    }
2494
1.64M
    return(xmlXPathNewNodeSet(val));
2495
9.24M
}
2496
2497
/**
2498
 * xmlXPathCacheNewString:
2499
 * @ctxt: the XPath context
2500
 * @val:  the xmlChar * value
2501
 *
2502
 * This is the cached version of xmlXPathNewString().
2503
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2504
 *
2505
 * Returns the created or reused object.
2506
 */
2507
static xmlXPathObjectPtr
2508
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2509
2.42M
{
2510
2.42M
    if ((ctxt != NULL) && (ctxt->cache)) {
2511
2.42M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512
2513
2.42M
  if ((cache->stringObjs != NULL) &&
2514
2.42M
      (cache->stringObjs->number != 0))
2515
2.14M
  {
2516
2.14M
      xmlXPathObjectPtr ret;
2517
2.14M
            xmlChar *copy;
2518
2519
2.14M
            if (val == NULL)
2520
1.44k
                val = BAD_CAST "";
2521
2.14M
            copy = xmlStrdup(val);
2522
2.14M
            if (copy == NULL) {
2523
433
                xmlXPathErrMemory(ctxt, NULL);
2524
433
                return(NULL);
2525
433
            }
2526
2527
2.14M
      ret = (xmlXPathObjectPtr)
2528
2.14M
    cache->stringObjs->items[--cache->stringObjs->number];
2529
2.14M
      ret->type = XPATH_STRING;
2530
2.14M
            ret->stringval = copy;
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
2.14M
      return(ret);
2535
2.14M
  } else if ((cache->miscObjs != NULL) &&
2536
283k
      (cache->miscObjs->number != 0))
2537
119k
  {
2538
119k
      xmlXPathObjectPtr ret;
2539
119k
            xmlChar *copy;
2540
2541
119k
            if (val == NULL)
2542
101
                val = BAD_CAST "";
2543
119k
            copy = xmlStrdup(val);
2544
119k
            if (copy == NULL) {
2545
900
                xmlXPathErrMemory(ctxt, NULL);
2546
900
                return(NULL);
2547
900
            }
2548
2549
118k
      ret = (xmlXPathObjectPtr)
2550
118k
    cache->miscObjs->items[--cache->miscObjs->number];
2551
2552
118k
      ret->type = XPATH_STRING;
2553
118k
            ret->stringval = copy;
2554
#ifdef XP_DEBUG_OBJ_USAGE
2555
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556
#endif
2557
118k
      return(ret);
2558
119k
  }
2559
2.42M
    }
2560
163k
    return(xmlXPathNewString(val));
2561
2.42M
}
2562
2563
/**
2564
 * xmlXPathCacheNewCString:
2565
 * @ctxt: the XPath context
2566
 * @val:  the char * value
2567
 *
2568
 * This is the cached version of xmlXPathNewCString().
2569
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2570
 *
2571
 * Returns the created or reused object.
2572
 */
2573
static xmlXPathObjectPtr
2574
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2575
10.6k
{
2576
10.6k
    return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2577
10.6k
}
2578
2579
/**
2580
 * xmlXPathCacheNewBoolean:
2581
 * @ctxt: the XPath context
2582
 * @val:  the boolean value
2583
 *
2584
 * This is the cached version of xmlXPathNewBoolean().
2585
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586
 *
2587
 * Returns the created or reused object.
2588
 */
2589
static xmlXPathObjectPtr
2590
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591
1.61M
{
2592
1.61M
    if ((ctxt != NULL) && (ctxt->cache)) {
2593
1.61M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595
1.61M
  if ((cache->booleanObjs != NULL) &&
2596
1.61M
      (cache->booleanObjs->number != 0))
2597
1.09M
  {
2598
1.09M
      xmlXPathObjectPtr ret;
2599
2600
1.09M
      ret = (xmlXPathObjectPtr)
2601
1.09M
    cache->booleanObjs->items[--cache->booleanObjs->number];
2602
1.09M
      ret->type = XPATH_BOOLEAN;
2603
1.09M
      ret->boolval = (val != 0);
2604
#ifdef XP_DEBUG_OBJ_USAGE
2605
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606
#endif
2607
1.09M
      return(ret);
2608
1.09M
  } else if ((cache->miscObjs != NULL) &&
2609
513k
      (cache->miscObjs->number != 0))
2610
144k
  {
2611
144k
      xmlXPathObjectPtr ret;
2612
2613
144k
      ret = (xmlXPathObjectPtr)
2614
144k
    cache->miscObjs->items[--cache->miscObjs->number];
2615
2616
144k
      ret->type = XPATH_BOOLEAN;
2617
144k
      ret->boolval = (val != 0);
2618
#ifdef XP_DEBUG_OBJ_USAGE
2619
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620
#endif
2621
144k
      return(ret);
2622
144k
  }
2623
1.61M
    }
2624
369k
    return(xmlXPathNewBoolean(val));
2625
1.61M
}
2626
2627
/**
2628
 * xmlXPathCacheNewFloat:
2629
 * @ctxt: the XPath context
2630
 * @val:  the double value
2631
 *
2632
 * This is the cached version of xmlXPathNewFloat().
2633
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2634
 *
2635
 * Returns the created or reused object.
2636
 */
2637
static xmlXPathObjectPtr
2638
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639
5.52M
{
2640
5.52M
     if ((ctxt != NULL) && (ctxt->cache)) {
2641
5.52M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643
5.52M
  if ((cache->numberObjs != NULL) &&
2644
5.52M
      (cache->numberObjs->number != 0))
2645
4.27M
  {
2646
4.27M
      xmlXPathObjectPtr ret;
2647
2648
4.27M
      ret = (xmlXPathObjectPtr)
2649
4.27M
    cache->numberObjs->items[--cache->numberObjs->number];
2650
4.27M
      ret->type = XPATH_NUMBER;
2651
4.27M
      ret->floatval = val;
2652
#ifdef XP_DEBUG_OBJ_USAGE
2653
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654
#endif
2655
4.27M
      return(ret);
2656
4.27M
  } else if ((cache->miscObjs != NULL) &&
2657
1.25M
      (cache->miscObjs->number != 0))
2658
450k
  {
2659
450k
      xmlXPathObjectPtr ret;
2660
2661
450k
      ret = (xmlXPathObjectPtr)
2662
450k
    cache->miscObjs->items[--cache->miscObjs->number];
2663
2664
450k
      ret->type = XPATH_NUMBER;
2665
450k
      ret->floatval = val;
2666
#ifdef XP_DEBUG_OBJ_USAGE
2667
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668
#endif
2669
450k
      return(ret);
2670
450k
  }
2671
5.52M
    }
2672
800k
    return(xmlXPathNewFloat(val));
2673
5.52M
}
2674
2675
/**
2676
 * xmlXPathCacheConvertString:
2677
 * @ctxt: the XPath context
2678
 * @val:  an XPath object
2679
 *
2680
 * This is the cached version of xmlXPathConvertString().
2681
 * Converts an existing object to its string() equivalent
2682
 *
2683
 * Returns a created or reused object, the old one is freed (cached)
2684
 *         (or the operation is done directly on @val)
2685
 */
2686
2687
static xmlXPathObjectPtr
2688
967k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689
967k
    xmlChar *res = NULL;
2690
2691
967k
    if (val == NULL)
2692
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694
967k
    switch (val->type) {
2695
0
    case XPATH_UNDEFINED:
2696
#ifdef DEBUG_EXPR
2697
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698
#endif
2699
0
  break;
2700
454k
    case XPATH_NODESET:
2701
454k
    case XPATH_XSLT_TREE:
2702
454k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2703
454k
  break;
2704
496k
    case XPATH_STRING:
2705
496k
  return(val);
2706
6.16k
    case XPATH_BOOLEAN:
2707
6.16k
  res = xmlXPathCastBooleanToString(val->boolval);
2708
6.16k
  break;
2709
10.1k
    case XPATH_NUMBER:
2710
10.1k
  res = xmlXPathCastNumberToString(val->floatval);
2711
10.1k
  break;
2712
0
    case XPATH_USERS:
2713
#ifdef LIBXML_XPTR_LOCS_ENABLED
2714
    case XPATH_POINT:
2715
    case XPATH_RANGE:
2716
    case XPATH_LOCATIONSET:
2717
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2718
0
  TODO;
2719
0
  break;
2720
967k
    }
2721
470k
    xmlXPathReleaseObject(ctxt, val);
2722
470k
    if (res == NULL)
2723
670
  return(xmlXPathCacheNewCString(ctxt, ""));
2724
470k
    return(xmlXPathCacheWrapString(ctxt, res));
2725
470k
}
2726
2727
/**
2728
 * xmlXPathCacheObjectCopy:
2729
 * @ctxt: the XPath context
2730
 * @val:  the original object
2731
 *
2732
 * This is the cached version of xmlXPathObjectCopy().
2733
 * Acquire a copy of a given object
2734
 *
2735
 * Returns a created or reused created object.
2736
 */
2737
static xmlXPathObjectPtr
2738
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739
921k
{
2740
921k
    if (val == NULL)
2741
0
  return(NULL);
2742
2743
921k
    if (XP_HAS_CACHE(ctxt)) {
2744
921k
  switch (val->type) {
2745
0
      case XPATH_NODESET:
2746
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2747
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748
166k
      case XPATH_STRING:
2749
166k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2750
0
      case XPATH_BOOLEAN:
2751
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752
754k
      case XPATH_NUMBER:
2753
754k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754
0
      default:
2755
0
    break;
2756
921k
  }
2757
921k
    }
2758
0
    return(xmlXPathObjectCopy(val));
2759
921k
}
2760
2761
/**
2762
 * xmlXPathCacheConvertBoolean:
2763
 * @ctxt: the XPath context
2764
 * @val:  an XPath object
2765
 *
2766
 * This is the cached version of xmlXPathConvertBoolean().
2767
 * Converts an existing object to its boolean() equivalent
2768
 *
2769
 * Returns a created or reused object, the old one is freed (or the operation
2770
 *         is done directly on @val)
2771
 */
2772
static xmlXPathObjectPtr
2773
308k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
308k
    xmlXPathObjectPtr ret;
2775
2776
308k
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2778
308k
    if (val->type == XPATH_BOOLEAN)
2779
40.8k
  return(val);
2780
268k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781
268k
    xmlXPathReleaseObject(ctxt, val);
2782
268k
    return(ret);
2783
308k
}
2784
2785
/**
2786
 * xmlXPathCacheConvertNumber:
2787
 * @ctxt: the XPath context
2788
 * @val:  an XPath object
2789
 *
2790
 * This is the cached version of xmlXPathConvertNumber().
2791
 * Converts an existing object to its number() equivalent
2792
 *
2793
 * Returns a created or reused object, the old one is freed (or the operation
2794
 *         is done directly on @val)
2795
 */
2796
static xmlXPathObjectPtr
2797
3.55M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798
3.55M
    xmlXPathObjectPtr ret;
2799
2800
3.55M
    if (val == NULL)
2801
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802
3.55M
    if (val->type == XPATH_NUMBER)
2803
1.14k
  return(val);
2804
3.55M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805
3.55M
    xmlXPathReleaseObject(ctxt, val);
2806
3.55M
    return(ret);
2807
3.55M
}
2808
2809
/************************************************************************
2810
 *                  *
2811
 *    Parser stacks related functions and macros    *
2812
 *                  *
2813
 ************************************************************************/
2814
2815
/**
2816
 * valuePop:
2817
 * @ctxt: an XPath evaluation context
2818
 *
2819
 * Pops the top XPath object from the value stack
2820
 *
2821
 * Returns the XPath object just removed
2822
 */
2823
xmlXPathObjectPtr
2824
valuePop(xmlXPathParserContextPtr ctxt)
2825
28.2M
{
2826
28.2M
    xmlXPathObjectPtr ret;
2827
2828
28.2M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829
49.7k
        return (NULL);
2830
2831
28.2M
    ctxt->valueNr--;
2832
28.2M
    if (ctxt->valueNr > 0)
2833
13.8M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834
14.3M
    else
2835
14.3M
        ctxt->value = NULL;
2836
28.2M
    ret = ctxt->valueTab[ctxt->valueNr];
2837
28.2M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2838
28.2M
    return (ret);
2839
28.2M
}
2840
/**
2841
 * valuePush:
2842
 * @ctxt:  an XPath evaluation context
2843
 * @value:  the XPath object
2844
 *
2845
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2846
 * a memory error is recorded in the parser context.
2847
 *
2848
 * Returns the number of items on the value stack, or -1 in case of error.
2849
 *
2850
 * The object is destroyed in case of error.
2851
 */
2852
int
2853
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854
28.7M
{
2855
28.7M
    if (ctxt == NULL) return(-1);
2856
28.7M
    if (value == NULL) {
2857
        /*
2858
         * A NULL value typically indicates that a memory allocation failed,
2859
         * so we set ctxt->error here to propagate the error.
2860
         */
2861
16.3k
  ctxt->error = XPATH_MEMORY_ERROR;
2862
16.3k
        return(-1);
2863
16.3k
    }
2864
28.7M
    if (ctxt->valueNr >= ctxt->valueMax) {
2865
32
        xmlXPathObjectPtr *tmp;
2866
2867
32
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2868
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2869
0
            xmlXPathFreeObject(value);
2870
0
            return (-1);
2871
0
        }
2872
32
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2873
32
                                             2 * ctxt->valueMax *
2874
32
                                             sizeof(ctxt->valueTab[0]));
2875
32
        if (tmp == NULL) {
2876
12
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2877
12
            xmlXPathFreeObject(value);
2878
12
            return (-1);
2879
12
        }
2880
20
        ctxt->valueMax *= 2;
2881
20
  ctxt->valueTab = tmp;
2882
20
    }
2883
28.7M
    ctxt->valueTab[ctxt->valueNr] = value;
2884
28.7M
    ctxt->value = value;
2885
28.7M
    return (ctxt->valueNr++);
2886
28.7M
}
2887
2888
/**
2889
 * xmlXPathPopBoolean:
2890
 * @ctxt:  an XPath parser context
2891
 *
2892
 * Pops a boolean from the stack, handling conversion if needed.
2893
 * Check error with #xmlXPathCheckError.
2894
 *
2895
 * Returns the boolean
2896
 */
2897
int
2898
520
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899
520
    xmlXPathObjectPtr obj;
2900
520
    int ret;
2901
2902
520
    obj = valuePop(ctxt);
2903
520
    if (obj == NULL) {
2904
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905
0
  return(0);
2906
0
    }
2907
520
    if (obj->type != XPATH_BOOLEAN)
2908
107
  ret = xmlXPathCastToBoolean(obj);
2909
413
    else
2910
413
        ret = obj->boolval;
2911
520
    xmlXPathReleaseObject(ctxt->context, obj);
2912
520
    return(ret);
2913
520
}
2914
2915
/**
2916
 * xmlXPathPopNumber:
2917
 * @ctxt:  an XPath parser context
2918
 *
2919
 * Pops a number from the stack, handling conversion if needed.
2920
 * Check error with #xmlXPathCheckError.
2921
 *
2922
 * Returns the number
2923
 */
2924
double
2925
1.62k
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2926
1.62k
    xmlXPathObjectPtr obj;
2927
1.62k
    double ret;
2928
2929
1.62k
    obj = valuePop(ctxt);
2930
1.62k
    if (obj == NULL) {
2931
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932
0
  return(0);
2933
0
    }
2934
1.62k
    if (obj->type != XPATH_NUMBER)
2935
1.29k
  ret = xmlXPathCastToNumber(obj);
2936
324
    else
2937
324
        ret = obj->floatval;
2938
1.62k
    xmlXPathReleaseObject(ctxt->context, obj);
2939
1.62k
    return(ret);
2940
1.62k
}
2941
2942
/**
2943
 * xmlXPathPopString:
2944
 * @ctxt:  an XPath parser context
2945
 *
2946
 * Pops a string from the stack, handling conversion if needed.
2947
 * Check error with #xmlXPathCheckError.
2948
 *
2949
 * Returns the string
2950
 */
2951
xmlChar *
2952
1.43M
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953
1.43M
    xmlXPathObjectPtr obj;
2954
1.43M
    xmlChar * ret;
2955
2956
1.43M
    obj = valuePop(ctxt);
2957
1.43M
    if (obj == NULL) {
2958
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959
0
  return(NULL);
2960
0
    }
2961
1.43M
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2962
    /* TODO: needs refactoring somewhere else */
2963
1.43M
    if (obj->stringval == ret)
2964
914
  obj->stringval = NULL;
2965
1.43M
    xmlXPathReleaseObject(ctxt->context, obj);
2966
1.43M
    return(ret);
2967
1.43M
}
2968
2969
/**
2970
 * xmlXPathPopNodeSet:
2971
 * @ctxt:  an XPath parser context
2972
 *
2973
 * Pops a node-set from the stack, handling conversion if needed.
2974
 * Check error with #xmlXPathCheckError.
2975
 *
2976
 * Returns the node-set
2977
 */
2978
xmlNodeSetPtr
2979
1.32M
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980
1.32M
    xmlXPathObjectPtr obj;
2981
1.32M
    xmlNodeSetPtr ret;
2982
2983
1.32M
    if (ctxt == NULL) return(NULL);
2984
1.32M
    if (ctxt->value == NULL) {
2985
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986
0
  return(NULL);
2987
0
    }
2988
1.32M
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2989
837
  xmlXPathSetTypeError(ctxt);
2990
837
  return(NULL);
2991
837
    }
2992
1.32M
    obj = valuePop(ctxt);
2993
1.32M
    ret = obj->nodesetval;
2994
#if 0
2995
    /* to fix memory leak of not clearing obj->user */
2996
    if (obj->boolval && obj->user != NULL)
2997
        xmlFreeNodeList((xmlNodePtr) obj->user);
2998
#endif
2999
1.32M
    obj->nodesetval = NULL;
3000
1.32M
    xmlXPathReleaseObject(ctxt->context, obj);
3001
1.32M
    return(ret);
3002
1.32M
}
3003
3004
/**
3005
 * xmlXPathPopExternal:
3006
 * @ctxt:  an XPath parser context
3007
 *
3008
 * Pops an external object from the stack, handling conversion if needed.
3009
 * Check error with #xmlXPathCheckError.
3010
 *
3011
 * Returns the object
3012
 */
3013
void *
3014
781
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3015
781
    xmlXPathObjectPtr obj;
3016
781
    void * ret;
3017
3018
781
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3019
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3020
0
  return(NULL);
3021
0
    }
3022
781
    if (ctxt->value->type != XPATH_USERS) {
3023
0
  xmlXPathSetTypeError(ctxt);
3024
0
  return(NULL);
3025
0
    }
3026
781
    obj = valuePop(ctxt);
3027
781
    ret = obj->user;
3028
781
    obj->user = NULL;
3029
781
    xmlXPathReleaseObject(ctxt->context, obj);
3030
781
    return(ret);
3031
781
}
3032
3033
/*
3034
 * Macros for accessing the content. Those should be used only by the parser,
3035
 * and not exported.
3036
 *
3037
 * Dirty macros, i.e. one need to make assumption on the context to use them
3038
 *
3039
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3040
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3041
 *           in ISO-Latin or UTF-8.
3042
 *           This should be used internally by the parser
3043
 *           only to compare to ASCII values otherwise it would break when
3044
 *           running with UTF-8 encoding.
3045
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3046
 *           to compare on ASCII based substring.
3047
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3048
 *           strings within the parser.
3049
 *   CURRENT Returns the current char value, with the full decoding of
3050
 *           UTF-8 if we are using this mode. It returns an int.
3051
 *   NEXT    Skip to the next character, this does the proper decoding
3052
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3053
 *           It returns the pointer to the current xmlChar.
3054
 */
3055
3056
1.02G
#define CUR (*ctxt->cur)
3057
842k
#define SKIP(val) ctxt->cur += (val)
3058
59.8M
#define NXT(val) ctxt->cur[(val)]
3059
492k
#define CUR_PTR ctxt->cur
3060
58.9M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061
3062
#define COPY_BUF(l,b,i,v)                                              \
3063
19.7M
    if (l == 1) b[i++] = v;                                            \
3064
19.7M
    else i += xmlCopyChar(l,&b[i],v)
3065
3066
45.4M
#define NEXTL(l)  ctxt->cur += l
3067
3068
#define SKIP_BLANKS             \
3069
585M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070
3071
#define CURRENT (*ctxt->cur)
3072
418M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3073
3074
3075
#ifndef DBL_DIG
3076
#define DBL_DIG 16
3077
#endif
3078
#ifndef DBL_EPSILON
3079
#define DBL_EPSILON 1E-9
3080
#endif
3081
3082
15.1k
#define UPPER_DOUBLE 1E9
3083
4.23k
#define LOWER_DOUBLE 1E-5
3084
#define LOWER_DOUBLE_EXP 5
3085
3086
#define INTEGER_DIGITS DBL_DIG
3087
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3088
11.8k
#define EXPONENT_DIGITS (3 + 2)
3089
3090
/**
3091
 * xmlXPathFormatNumber:
3092
 * @number:     number to format
3093
 * @buffer:     output buffer
3094
 * @buffersize: size of output buffer
3095
 *
3096
 * Convert the number into a string representation.
3097
 */
3098
static void
3099
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3100
117k
{
3101
117k
    switch (xmlXPathIsInf(number)) {
3102
0
    case 1:
3103
0
  if (buffersize > (int)sizeof("Infinity"))
3104
0
      snprintf(buffer, buffersize, "Infinity");
3105
0
  break;
3106
0
    case -1:
3107
0
  if (buffersize > (int)sizeof("-Infinity"))
3108
0
      snprintf(buffer, buffersize, "-Infinity");
3109
0
  break;
3110
117k
    default:
3111
117k
  if (xmlXPathIsNaN(number)) {
3112
0
      if (buffersize > (int)sizeof("NaN"))
3113
0
    snprintf(buffer, buffersize, "NaN");
3114
117k
  } else if (number == 0) {
3115
            /* Omit sign for negative zero. */
3116
0
      snprintf(buffer, buffersize, "0");
3117
117k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3118
117k
                   (number == (int) number)) {
3119
102k
      char work[30];
3120
102k
      char *ptr, *cur;
3121
102k
      int value = (int) number;
3122
3123
102k
            ptr = &buffer[0];
3124
102k
      if (value == 0) {
3125
0
    *ptr++ = '0';
3126
102k
      } else {
3127
102k
    snprintf(work, 29, "%d", value);
3128
102k
    cur = &work[0];
3129
278k
    while ((*cur) && (ptr - buffer < buffersize)) {
3130
176k
        *ptr++ = *cur++;
3131
176k
    }
3132
102k
      }
3133
102k
      if (ptr - buffer < buffersize) {
3134
102k
    *ptr = 0;
3135
102k
      } else if (buffersize > 0) {
3136
0
    ptr--;
3137
0
    *ptr = 0;
3138
0
      }
3139
102k
  } else {
3140
      /*
3141
        For the dimension of work,
3142
            DBL_DIG is number of significant digits
3143
      EXPONENT is only needed for "scientific notation"
3144
            3 is sign, decimal point, and terminating zero
3145
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3146
        Note that this dimension is slightly (a few characters)
3147
        larger than actually necessary.
3148
      */
3149
15.1k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3150
15.1k
      int integer_place, fraction_place;
3151
15.1k
      char *ptr;
3152
15.1k
      char *after_fraction;
3153
15.1k
      double absolute_value;
3154
15.1k
      int size;
3155
3156
15.1k
      absolute_value = fabs(number);
3157
3158
      /*
3159
       * First choose format - scientific or regular floating point.
3160
       * In either case, result is in work, and after_fraction points
3161
       * just past the fractional part.
3162
      */
3163
15.1k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3164
15.1k
      (absolute_value < LOWER_DOUBLE)) &&
3165
15.1k
     (absolute_value != 0.0) ) {
3166
    /* Use scientific notation */
3167
11.8k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3168
11.8k
    fraction_place = DBL_DIG - 1;
3169
11.8k
    size = snprintf(work, sizeof(work),"%*.*e",
3170
11.8k
       integer_place, fraction_place, number);
3171
59.9k
    while ((size > 0) && (work[size] != 'e')) size--;
3172
3173
11.8k
      }
3174
3.28k
      else {
3175
    /* Use regular notation */
3176
3.28k
    if (absolute_value > 0.0) {
3177
3.28k
        integer_place = (int)log10(absolute_value);
3178
3.28k
        if (integer_place > 0)
3179
641
            fraction_place = DBL_DIG - integer_place - 1;
3180
2.64k
        else
3181
2.64k
            fraction_place = DBL_DIG - integer_place;
3182
3.28k
    } else {
3183
0
        fraction_place = 1;
3184
0
    }
3185
3.28k
    size = snprintf(work, sizeof(work), "%0.*f",
3186
3.28k
        fraction_place, number);
3187
3.28k
      }
3188
3189
      /* Remove leading spaces sometimes inserted by snprintf */
3190
25.4k
      while (work[0] == ' ') {
3191
215k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192
10.2k
    size--;
3193
10.2k
      }
3194
3195
      /* Remove fractional trailing zeroes */
3196
15.1k
      after_fraction = work + size;
3197
15.1k
      ptr = after_fraction;
3198
73.7k
      while (*(--ptr) == '0')
3199
58.5k
    ;
3200
15.1k
      if (*ptr != '.')
3201
14.5k
          ptr++;
3202
63.2k
      while ((*ptr++ = *after_fraction++) != 0);
3203
3204
      /* Finally copy result back to caller */
3205
15.1k
      size = strlen(work) + 1;
3206
15.1k
      if (size > buffersize) {
3207
0
    work[buffersize - 1] = 0;
3208
0
    size = buffersize;
3209
0
      }
3210
15.1k
      memmove(buffer, work, size);
3211
15.1k
  }
3212
117k
  break;
3213
117k
    }
3214
117k
}
3215
3216
3217
/************************************************************************
3218
 *                  *
3219
 *      Routines to handle NodeSets     *
3220
 *                  *
3221
 ************************************************************************/
3222
3223
/**
3224
 * xmlXPathOrderDocElems:
3225
 * @doc:  an input document
3226
 *
3227
 * Call this routine to speed up XPath computation on static documents.
3228
 * This stamps all the element nodes with the document order
3229
 * Like for line information, the order is kept in the element->content
3230
 * field, the value stored is actually - the node number (starting at -1)
3231
 * to be able to differentiate from line numbers.
3232
 *
3233
 * Returns the number of elements found in the document or -1 in case
3234
 *    of error.
3235
 */
3236
long
3237
14.5k
xmlXPathOrderDocElems(xmlDocPtr doc) {
3238
14.5k
    ptrdiff_t count = 0;
3239
14.5k
    xmlNodePtr cur;
3240
3241
14.5k
    if (doc == NULL)
3242
0
  return(-1);
3243
14.5k
    cur = doc->children;
3244
2.00M
    while (cur != NULL) {
3245
1.98M
  if (cur->type == XML_ELEMENT_NODE) {
3246
1.67M
      cur->content = (void *) (-(++count));
3247
1.67M
      if (cur->children != NULL) {
3248
106k
    cur = cur->children;
3249
106k
    continue;
3250
106k
      }
3251
1.67M
  }
3252
1.88M
  if (cur->next != NULL) {
3253
1.80M
      cur = cur->next;
3254
1.80M
      continue;
3255
1.80M
  }
3256
120k
  do {
3257
120k
      cur = cur->parent;
3258
120k
      if (cur == NULL)
3259
0
    break;
3260
120k
      if (cur == (xmlNodePtr) doc) {
3261
14.5k
    cur = NULL;
3262
14.5k
    break;
3263
14.5k
      }
3264
106k
      if (cur->next != NULL) {
3265
58.3k
    cur = cur->next;
3266
58.3k
    break;
3267
58.3k
      }
3268
106k
  } while (cur != NULL);
3269
72.8k
    }
3270
14.5k
    return(count);
3271
14.5k
}
3272
3273
/**
3274
 * xmlXPathCmpNodes:
3275
 * @node1:  the first node
3276
 * @node2:  the second node
3277
 *
3278
 * Compare two nodes w.r.t document order
3279
 *
3280
 * Returns -2 in case of error 1 if first point < second point, 0 if
3281
 *         it's the same node, -1 otherwise
3282
 */
3283
int
3284
16.1k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285
16.1k
    int depth1, depth2;
3286
16.1k
    int attr1 = 0, attr2 = 0;
3287
16.1k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288
16.1k
    xmlNodePtr cur, root;
3289
3290
16.1k
    if ((node1 == NULL) || (node2 == NULL))
3291
0
  return(-2);
3292
    /*
3293
     * a couple of optimizations which will avoid computations in most cases
3294
     */
3295
16.1k
    if (node1 == node2)    /* trivial case */
3296
0
  return(0);
3297
16.1k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3298
0
  attr1 = 1;
3299
0
  attrNode1 = node1;
3300
0
  node1 = node1->parent;
3301
0
    }
3302
16.1k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr2 = 1;
3304
0
  attrNode2 = node2;
3305
0
  node2 = node2->parent;
3306
0
    }
3307
16.1k
    if (node1 == node2) {
3308
0
  if (attr1 == attr2) {
3309
      /* not required, but we keep attributes in order */
3310
0
      if (attr1 != 0) {
3311
0
          cur = attrNode2->prev;
3312
0
    while (cur != NULL) {
3313
0
        if (cur == attrNode1)
3314
0
            return (1);
3315
0
        cur = cur->prev;
3316
0
    }
3317
0
    return (-1);
3318
0
      }
3319
0
      return(0);
3320
0
  }
3321
0
  if (attr2 == 1)
3322
0
      return(1);
3323
0
  return(-1);
3324
0
    }
3325
16.1k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3326
16.1k
        (node2->type == XML_NAMESPACE_DECL))
3327
825
  return(1);
3328
15.2k
    if (node1 == node2->prev)
3329
18
  return(1);
3330
15.2k
    if (node1 == node2->next)
3331
0
  return(-1);
3332
3333
    /*
3334
     * Speedup using document order if available.
3335
     */
3336
15.2k
    if ((node1->type == XML_ELEMENT_NODE) &&
3337
15.2k
  (node2->type == XML_ELEMENT_NODE) &&
3338
15.2k
  (0 > (ptrdiff_t) node1->content) &&
3339
15.2k
  (0 > (ptrdiff_t) node2->content) &&
3340
15.2k
  (node1->doc == node2->doc)) {
3341
430
  ptrdiff_t l1, l2;
3342
3343
430
  l1 = -((ptrdiff_t) node1->content);
3344
430
  l2 = -((ptrdiff_t) node2->content);
3345
430
  if (l1 < l2)
3346
426
      return(1);
3347
4
  if (l1 > l2)
3348
4
      return(-1);
3349
4
    }
3350
3351
    /*
3352
     * compute depth to root
3353
     */
3354
318k
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355
304k
  if (cur->parent == node1)
3356
495
      return(1);
3357
304k
  depth2++;
3358
304k
    }
3359
14.3k
    root = cur;
3360
55.5k
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361
41.1k
  if (cur->parent == node2)
3362
0
      return(-1);
3363
41.1k
  depth1++;
3364
41.1k
    }
3365
    /*
3366
     * Distinct document (or distinct entities :-( ) case.
3367
     */
3368
14.3k
    if (root != cur) {
3369
1.04k
  return(-2);
3370
1.04k
    }
3371
    /*
3372
     * get the nearest common ancestor.
3373
     */
3374
13.4k
    while (depth1 > depth2) {
3375
158
  depth1--;
3376
158
  node1 = node1->parent;
3377
158
    }
3378
270k
    while (depth2 > depth1) {
3379
257k
  depth2--;
3380
257k
  node2 = node2->parent;
3381
257k
    }
3382
25.8k
    while (node1->parent != node2->parent) {
3383
12.5k
  node1 = node1->parent;
3384
12.5k
  node2 = node2->parent;
3385
  /* should not happen but just in case ... */
3386
12.5k
  if ((node1 == NULL) || (node2 == NULL))
3387
0
      return(-2);
3388
12.5k
    }
3389
    /*
3390
     * Find who's first.
3391
     */
3392
13.2k
    if (node1 == node2->prev)
3393
1.09k
  return(1);
3394
12.1k
    if (node1 == node2->next)
3395
0
  return(-1);
3396
    /*
3397
     * Speedup using document order if available.
3398
     */
3399
12.1k
    if ((node1->type == XML_ELEMENT_NODE) &&
3400
12.1k
  (node2->type == XML_ELEMENT_NODE) &&
3401
12.1k
  (0 > (ptrdiff_t) node1->content) &&
3402
12.1k
  (0 > (ptrdiff_t) node2->content) &&
3403
12.1k
  (node1->doc == node2->doc)) {
3404
10.9k
  ptrdiff_t l1, l2;
3405
3406
10.9k
  l1 = -((ptrdiff_t) node1->content);
3407
10.9k
  l2 = -((ptrdiff_t) node2->content);
3408
10.9k
  if (l1 < l2)
3409
10.9k
      return(1);
3410
0
  if (l1 > l2)
3411
0
      return(-1);
3412
0
    }
3413
3414
4.63k
    for (cur = node1->next;cur != NULL;cur = cur->next)
3415
4.63k
  if (cur == node2)
3416
1.22k
      return(1);
3417
0
    return(-1); /* assume there is no sibling list corruption */
3418
1.22k
}
3419
3420
/**
3421
 * xmlXPathNodeSetSort:
3422
 * @set:  the node set
3423
 *
3424
 * Sort the node set in document order
3425
 */
3426
void
3427
1.39M
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428
#ifndef WITH_TIM_SORT
3429
    int i, j, incr, len;
3430
    xmlNodePtr tmp;
3431
#endif
3432
3433
1.39M
    if (set == NULL)
3434
0
  return;
3435
3436
#ifndef WITH_TIM_SORT
3437
    /*
3438
     * Use the old Shell's sort implementation to sort the node-set
3439
     * Timsort ought to be quite faster
3440
     */
3441
    len = set->nodeNr;
3442
    for (incr = len / 2; incr > 0; incr /= 2) {
3443
  for (i = incr; i < len; i++) {
3444
      j = i - incr;
3445
      while (j >= 0) {
3446
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3447
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3448
      set->nodeTab[j + incr]) == -1)
3449
#else
3450
    if (xmlXPathCmpNodes(set->nodeTab[j],
3451
      set->nodeTab[j + incr]) == -1)
3452
#endif
3453
    {
3454
        tmp = set->nodeTab[j];
3455
        set->nodeTab[j] = set->nodeTab[j + incr];
3456
        set->nodeTab[j + incr] = tmp;
3457
        j -= incr;
3458
    } else
3459
        break;
3460
      }
3461
  }
3462
    }
3463
#else /* WITH_TIM_SORT */
3464
1.39M
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465
1.39M
#endif /* WITH_TIM_SORT */
3466
1.39M
}
3467
3468
14.1M
#define XML_NODESET_DEFAULT 10
3469
/**
3470
 * xmlXPathNodeSetDupNs:
3471
 * @node:  the parent node of the namespace XPath node
3472
 * @ns:  the libxml namespace declaration node.
3473
 *
3474
 * Namespace node in libxml don't match the XPath semantic. In a node set
3475
 * the namespace nodes are duplicated and the next pointer is set to the
3476
 * parent node in the XPath semantic.
3477
 *
3478
 * Returns the newly created object.
3479
 */
3480
static xmlNodePtr
3481
881k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482
881k
    xmlNsPtr cur;
3483
3484
881k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485
0
  return(NULL);
3486
881k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3487
0
  return((xmlNodePtr) ns);
3488
3489
    /*
3490
     * Allocate a new Namespace and fill the fields.
3491
     */
3492
881k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493
881k
    if (cur == NULL) {
3494
1.33k
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495
1.33k
  return(NULL);
3496
1.33k
    }
3497
879k
    memset(cur, 0, sizeof(xmlNs));
3498
879k
    cur->type = XML_NAMESPACE_DECL;
3499
879k
    if (ns->href != NULL)
3500
879k
  cur->href = xmlStrdup(ns->href);
3501
879k
    if (ns->prefix != NULL)
3502
863k
  cur->prefix = xmlStrdup(ns->prefix);
3503
879k
    cur->next = (xmlNsPtr) node;
3504
879k
    return((xmlNodePtr) cur);
3505
881k
}
3506
3507
/**
3508
 * xmlXPathNodeSetFreeNs:
3509
 * @ns:  the XPath namespace node found in a nodeset.
3510
 *
3511
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3512
 * the namespace nodes are duplicated and the next pointer is set to the
3513
 * parent node in the XPath semantic. Check if such a node needs to be freed
3514
 */
3515
void
3516
879k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517
879k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518
0
  return;
3519
3520
879k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521
879k
  if (ns->href != NULL)
3522
879k
      xmlFree((xmlChar *)ns->href);
3523
879k
  if (ns->prefix != NULL)
3524
863k
      xmlFree((xmlChar *)ns->prefix);
3525
879k
  xmlFree(ns);
3526
879k
    }
3527
879k
}
3528
3529
/**
3530
 * xmlXPathNodeSetCreate:
3531
 * @val:  an initial xmlNodePtr, or NULL
3532
 *
3533
 * Create a new xmlNodeSetPtr of type double and of value @val
3534
 *
3535
 * Returns the newly created object.
3536
 */
3537
xmlNodeSetPtr
3538
8.69M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3539
8.69M
    xmlNodeSetPtr ret;
3540
3541
8.69M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542
8.69M
    if (ret == NULL) {
3543
11.9k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3544
11.9k
  return(NULL);
3545
11.9k
    }
3546
8.68M
    memset(ret, 0 , sizeof(xmlNodeSet));
3547
8.68M
    if (val != NULL) {
3548
1.04M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549
1.04M
               sizeof(xmlNodePtr));
3550
1.04M
  if (ret->nodeTab == NULL) {
3551
91
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3552
91
      xmlFree(ret);
3553
91
      return(NULL);
3554
91
  }
3555
1.04M
  memset(ret->nodeTab, 0 ,
3556
1.04M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557
1.04M
        ret->nodeMax = XML_NODESET_DEFAULT;
3558
1.04M
  if (val->type == XML_NAMESPACE_DECL) {
3559
2.32k
      xmlNsPtr ns = (xmlNsPtr) val;
3560
2.32k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3561
3562
2.32k
            if (nsNode == NULL) {
3563
2
                xmlXPathFreeNodeSet(ret);
3564
2
                return(NULL);
3565
2
            }
3566
2.32k
      ret->nodeTab[ret->nodeNr++] = nsNode;
3567
2.32k
  } else
3568
1.03M
      ret->nodeTab[ret->nodeNr++] = val;
3569
1.04M
    }
3570
8.68M
    return(ret);
3571
8.68M
}
3572
3573
/**
3574
 * xmlXPathNodeSetContains:
3575
 * @cur:  the node-set
3576
 * @val:  the node
3577
 *
3578
 * checks whether @cur contains @val
3579
 *
3580
 * Returns true (1) if @cur contains @val, false (0) otherwise
3581
 */
3582
int
3583
19.5k
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3584
19.5k
    int i;
3585
3586
19.5k
    if ((cur == NULL) || (val == NULL)) return(0);
3587
19.5k
    if (val->type == XML_NAMESPACE_DECL) {
3588
23.4k
  for (i = 0; i < cur->nodeNr; i++) {
3589
22.4k
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3590
20.8k
    xmlNsPtr ns1, ns2;
3591
3592
20.8k
    ns1 = (xmlNsPtr) val;
3593
20.8k
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3594
20.8k
    if (ns1 == ns2)
3595
0
        return(1);
3596
20.8k
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3597
20.8k
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3598
163
        return(1);
3599
20.8k
      }
3600
22.4k
  }
3601
18.3k
    } else {
3602
1.00M
  for (i = 0; i < cur->nodeNr; i++) {
3603
998k
      if (cur->nodeTab[i] == val)
3604
9.15k
    return(1);
3605
998k
  }
3606
18.3k
    }
3607
10.1k
    return(0);
3608
19.5k
}
3609
3610
/**
3611
 * xmlXPathNodeSetAddNs:
3612
 * @cur:  the initial node set
3613
 * @node:  the hosting node
3614
 * @ns:  a the namespace node
3615
 *
3616
 * add a new namespace node to an existing NodeSet
3617
 *
3618
 * Returns 0 in case of success and -1 in case of error
3619
 */
3620
int
3621
669k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622
669k
    int i;
3623
669k
    xmlNodePtr nsNode;
3624
3625
669k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626
669k
        (ns->type != XML_NAMESPACE_DECL) ||
3627
669k
  (node->type != XML_ELEMENT_NODE))
3628
0
  return(-1);
3629
3630
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3631
    /*
3632
     * prevent duplicates
3633
     */
3634
1.91M
    for (i = 0;i < cur->nodeNr;i++) {
3635
1.24M
        if ((cur->nodeTab[i] != NULL) &&
3636
1.24M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637
1.24M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638
1.24M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639
6
      return(0);
3640
1.24M
    }
3641
3642
    /*
3643
     * grow the nodeTab if needed
3644
     */
3645
669k
    if (cur->nodeMax == 0) {
3646
32.9k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647
32.9k
               sizeof(xmlNodePtr));
3648
32.9k
  if (cur->nodeTab == NULL) {
3649
15
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3650
15
      return(-1);
3651
15
  }
3652
32.9k
  memset(cur->nodeTab, 0 ,
3653
32.9k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654
32.9k
        cur->nodeMax = XML_NODESET_DEFAULT;
3655
636k
    } else if (cur->nodeNr == cur->nodeMax) {
3656
1.89k
        xmlNodePtr *temp;
3657
3658
1.89k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660
0
            return(-1);
3661
0
        }
3662
1.89k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663
1.89k
              sizeof(xmlNodePtr));
3664
1.89k
  if (temp == NULL) {
3665
1
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3666
1
      return(-1);
3667
1
  }
3668
1.89k
        cur->nodeMax *= 2;
3669
1.89k
  cur->nodeTab = temp;
3670
1.89k
    }
3671
669k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3672
669k
    if(nsNode == NULL)
3673
133
        return(-1);
3674
669k
    cur->nodeTab[cur->nodeNr++] = nsNode;
3675
669k
    return(0);
3676
669k
}
3677
3678
/**
3679
 * xmlXPathNodeSetAdd:
3680
 * @cur:  the initial node set
3681
 * @val:  a new xmlNodePtr
3682
 *
3683
 * add a new xmlNodePtr to an existing NodeSet
3684
 *
3685
 * Returns 0 in case of success, and -1 in case of error
3686
 */
3687
int
3688
26.0M
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3689
26.0M
    int i;
3690
3691
26.0M
    if ((cur == NULL) || (val == NULL)) return(-1);
3692
3693
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3694
    /*
3695
     * prevent duplicates
3696
     */
3697
30.7G
    for (i = 0;i < cur->nodeNr;i++)
3698
30.6G
        if (cur->nodeTab[i] == val) return(0);
3699
3700
    /*
3701
     * grow the nodeTab if needed
3702
     */
3703
25.4M
    if (cur->nodeMax == 0) {
3704
62.7k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705
62.7k
               sizeof(xmlNodePtr));
3706
62.7k
  if (cur->nodeTab == NULL) {
3707
1.50k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3708
1.50k
      return(-1);
3709
1.50k
  }
3710
61.1k
  memset(cur->nodeTab, 0 ,
3711
61.1k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712
61.1k
        cur->nodeMax = XML_NODESET_DEFAULT;
3713
25.3M
    } else if (cur->nodeNr == cur->nodeMax) {
3714
162k
        xmlNodePtr *temp;
3715
3716
162k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3717
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3718
0
            return(-1);
3719
0
        }
3720
162k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3721
162k
              sizeof(xmlNodePtr));
3722
162k
  if (temp == NULL) {
3723
3.73k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3724
3.73k
      return(-1);
3725
3.73k
  }
3726
158k
        cur->nodeMax *= 2;
3727
158k
  cur->nodeTab = temp;
3728
158k
    }
3729
25.4M
    if (val->type == XML_NAMESPACE_DECL) {
3730
1.17k
  xmlNsPtr ns = (xmlNsPtr) val;
3731
1.17k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3732
3733
1.17k
        if (nsNode == NULL)
3734
259
            return(-1);
3735
911
  cur->nodeTab[cur->nodeNr++] = nsNode;
3736
911
    } else
3737
25.4M
  cur->nodeTab[cur->nodeNr++] = val;
3738
25.4M
    return(0);
3739
25.4M
}
3740
3741
/**
3742
 * xmlXPathNodeSetAddUnique:
3743
 * @cur:  the initial node set
3744
 * @val:  a new xmlNodePtr
3745
 *
3746
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3747
 * when we are sure the node is not already in the set.
3748
 *
3749
 * Returns 0 in case of success and -1 in case of failure
3750
 */
3751
int
3752
30.7M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753
30.7M
    if ((cur == NULL) || (val == NULL)) return(-1);
3754
3755
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3756
    /*
3757
     * grow the nodeTab if needed
3758
     */
3759
30.7M
    if (cur->nodeMax == 0) {
3760
3.29M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761
3.29M
               sizeof(xmlNodePtr));
3762
3.29M
  if (cur->nodeTab == NULL) {
3763
12.0k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3764
12.0k
      return(-1);
3765
12.0k
  }
3766
3.28M
  memset(cur->nodeTab, 0 ,
3767
3.28M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768
3.28M
        cur->nodeMax = XML_NODESET_DEFAULT;
3769
27.4M
    } else if (cur->nodeNr == cur->nodeMax) {
3770
881k
        xmlNodePtr *temp;
3771
3772
881k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774
0
            return(-1);
3775
0
        }
3776
881k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777
881k
              sizeof(xmlNodePtr));
3778
881k
  if (temp == NULL) {
3779
864
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3780
864
      return(-1);
3781
864
  }
3782
880k
  cur->nodeTab = temp;
3783
880k
        cur->nodeMax *= 2;
3784
880k
    }
3785
30.7M
    if (val->type == XML_NAMESPACE_DECL) {
3786
125k
  xmlNsPtr ns = (xmlNsPtr) val;
3787
125k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788
3789
125k
        if (nsNode == NULL)
3790
916
            return(-1);
3791
124k
  cur->nodeTab[cur->nodeNr++] = nsNode;
3792
124k
    } else
3793
30.6M
  cur->nodeTab[cur->nodeNr++] = val;
3794
30.7M
    return(0);
3795
30.7M
}
3796
3797
/**
3798
 * xmlXPathNodeSetMerge:
3799
 * @val1:  the first NodeSet or NULL
3800
 * @val2:  the second NodeSet
3801
 *
3802
 * Merges two nodesets, all nodes from @val2 are added to @val1
3803
 * if @val1 is NULL, a new set is created and copied from @val2
3804
 *
3805
 * Returns @val1 once extended or NULL in case of error.
3806
 *
3807
 * Frees @val1 in case of error.
3808
 */
3809
xmlNodeSetPtr
3810
1.80M
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811
1.80M
    int i, j, initNr, skip;
3812
1.80M
    xmlNodePtr n1, n2;
3813
3814
1.80M
    if (val2 == NULL) return(val1);
3815
1.53M
    if (val1 == NULL) {
3816
273k
  val1 = xmlXPathNodeSetCreate(NULL);
3817
273k
        if (val1 == NULL)
3818
344
            return (NULL);
3819
273k
    }
3820
3821
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822
1.53M
    initNr = val1->nodeNr;
3823
3824
15.1M
    for (i = 0;i < val2->nodeNr;i++) {
3825
13.6M
  n2 = val2->nodeTab[i];
3826
  /*
3827
   * check against duplicates
3828
   */
3829
13.6M
  skip = 0;
3830
74.5M
  for (j = 0; j < initNr; j++) {
3831
61.7M
      n1 = val1->nodeTab[j];
3832
61.7M
      if (n1 == n2) {
3833
841k
    skip = 1;
3834
841k
    break;
3835
60.8M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836
60.8M
           (n2->type == XML_NAMESPACE_DECL)) {
3837
38.7k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3838
38.7k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3839
7.32k
      ((xmlNsPtr) n2)->prefix)))
3840
1.93k
    {
3841
1.93k
        skip = 1;
3842
1.93k
        break;
3843
1.93k
    }
3844
38.7k
      }
3845
61.7M
  }
3846
13.6M
  if (skip)
3847
843k
      continue;
3848
3849
  /*
3850
   * grow the nodeTab if needed
3851
   */
3852
12.8M
  if (val1->nodeMax == 0) {
3853
208k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854
208k
                sizeof(xmlNodePtr));
3855
208k
      if (val1->nodeTab == NULL) {
3856
390
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3857
390
    goto error;
3858
390
      }
3859
208k
      memset(val1->nodeTab, 0 ,
3860
208k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861
208k
      val1->nodeMax = XML_NODESET_DEFAULT;
3862
12.5M
  } else if (val1->nodeNr == val1->nodeMax) {
3863
281k
      xmlNodePtr *temp;
3864
3865
281k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867
0
                goto error;
3868
0
            }
3869
281k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870
281k
               sizeof(xmlNodePtr));
3871
281k
      if (temp == NULL) {
3872
83
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3873
83
    goto error;
3874
83
      }
3875
281k
      val1->nodeTab = temp;
3876
281k
      val1->nodeMax *= 2;
3877
281k
  }
3878
12.8M
  if (n2->type == XML_NAMESPACE_DECL) {
3879
82.9k
      xmlNsPtr ns = (xmlNsPtr) n2;
3880
82.9k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881
3882
82.9k
            if (nsNode == NULL)
3883
27
                goto error;
3884
82.8k
      val1->nodeTab[val1->nodeNr++] = nsNode;
3885
82.8k
  } else
3886
12.7M
      val1->nodeTab[val1->nodeNr++] = n2;
3887
12.8M
    }
3888
3889
1.53M
    return(val1);
3890
3891
500
error:
3892
500
    xmlXPathFreeNodeSet(val1);
3893
500
    return(NULL);
3894
1.53M
}
3895
3896
3897
/**
3898
 * xmlXPathNodeSetMergeAndClear:
3899
 * @set1:  the first NodeSet or NULL
3900
 * @set2:  the second NodeSet
3901
 *
3902
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3903
 * Checks for duplicate nodes. Clears set2.
3904
 *
3905
 * Returns @set1 once extended or NULL in case of error.
3906
 *
3907
 * Frees @set1 in case of error.
3908
 */
3909
static xmlNodeSetPtr
3910
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3911
641k
{
3912
641k
    {
3913
641k
  int i, j, initNbSet1;
3914
641k
  xmlNodePtr n1, n2;
3915
3916
641k
  initNbSet1 = set1->nodeNr;
3917
1.47M
  for (i = 0;i < set2->nodeNr;i++) {
3918
837k
      n2 = set2->nodeTab[i];
3919
      /*
3920
      * Skip duplicates.
3921
      */
3922
36.6M
      for (j = 0; j < initNbSet1; j++) {
3923
36.5M
    n1 = set1->nodeTab[j];
3924
36.5M
    if (n1 == n2) {
3925
721k
        goto skip_node;
3926
35.8M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3927
35.8M
        (n2->type == XML_NAMESPACE_DECL))
3928
2.21M
    {
3929
2.21M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930
2.21M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931
244k
      ((xmlNsPtr) n2)->prefix)))
3932
3
        {
3933
      /*
3934
      * Free the namespace node.
3935
      */
3936
3
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3937
3
      goto skip_node;
3938
3
        }
3939
2.21M
    }
3940
36.5M
      }
3941
      /*
3942
      * grow the nodeTab if needed
3943
      */
3944
115k
      if (set1->nodeMax == 0) {
3945
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3946
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3947
0
    if (set1->nodeTab == NULL) {
3948
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3949
0
        goto error;
3950
0
    }
3951
0
    memset(set1->nodeTab, 0,
3952
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3953
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3954
115k
      } else if (set1->nodeNr >= set1->nodeMax) {
3955
5.52k
    xmlNodePtr *temp;
3956
3957
5.52k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959
0
                    goto error;
3960
0
                }
3961
5.52k
    temp = (xmlNodePtr *) xmlRealloc(
3962
5.52k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963
5.52k
    if (temp == NULL) {
3964
20
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3965
20
        goto error;
3966
20
    }
3967
5.50k
    set1->nodeTab = temp;
3968
5.50k
    set1->nodeMax *= 2;
3969
5.50k
      }
3970
115k
      set1->nodeTab[set1->nodeNr++] = n2;
3971
837k
skip_node:
3972
837k
            set2->nodeTab[i] = NULL;
3973
837k
  }
3974
641k
    }
3975
641k
    set2->nodeNr = 0;
3976
641k
    return(set1);
3977
3978
20
error:
3979
20
    xmlXPathFreeNodeSet(set1);
3980
20
    xmlXPathNodeSetClear(set2, 1);
3981
20
    return(NULL);
3982
641k
}
3983
3984
/**
3985
 * xmlXPathNodeSetMergeAndClearNoDupls:
3986
 * @set1:  the first NodeSet or NULL
3987
 * @set2:  the second NodeSet
3988
 *
3989
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3990
 * Doesn't check for duplicate nodes. Clears set2.
3991
 *
3992
 * Returns @set1 once extended or NULL in case of error.
3993
 *
3994
 * Frees @set1 in case of error.
3995
 */
3996
static xmlNodeSetPtr
3997
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3998
388k
{
3999
388k
    {
4000
388k
  int i;
4001
388k
  xmlNodePtr n2;
4002
4003
1.53M
  for (i = 0;i < set2->nodeNr;i++) {
4004
1.14M
      n2 = set2->nodeTab[i];
4005
1.14M
      if (set1->nodeMax == 0) {
4006
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008
0
    if (set1->nodeTab == NULL) {
4009
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4010
0
        goto error;
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
1.14M
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
29.0k
    xmlNodePtr *temp;
4017
4018
29.0k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    goto error;
4021
0
                }
4022
29.0k
    temp = (xmlNodePtr *) xmlRealloc(
4023
29.0k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
29.0k
    if (temp == NULL) {
4025
42
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
42
        goto error;
4027
42
    }
4028
29.0k
    set1->nodeTab = temp;
4029
29.0k
    set1->nodeMax *= 2;
4030
29.0k
      }
4031
1.14M
      set1->nodeTab[set1->nodeNr++] = n2;
4032
1.14M
            set2->nodeTab[i] = NULL;
4033
1.14M
  }
4034
388k
    }
4035
388k
    set2->nodeNr = 0;
4036
388k
    return(set1);
4037
4038
42
error:
4039
42
    xmlXPathFreeNodeSet(set1);
4040
42
    xmlXPathNodeSetClear(set2, 1);
4041
42
    return(NULL);
4042
388k
}
4043
4044
/**
4045
 * xmlXPathNodeSetDel:
4046
 * @cur:  the initial node set
4047
 * @val:  an xmlNodePtr
4048
 *
4049
 * Removes an xmlNodePtr from an existing NodeSet
4050
 */
4051
void
4052
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4053
0
    int i;
4054
4055
0
    if (cur == NULL) return;
4056
0
    if (val == NULL) return;
4057
4058
    /*
4059
     * find node in nodeTab
4060
     */
4061
0
    for (i = 0;i < cur->nodeNr;i++)
4062
0
        if (cur->nodeTab[i] == val) break;
4063
4064
0
    if (i >= cur->nodeNr) { /* not found */
4065
#ifdef DEBUG
4066
        xmlGenericError(xmlGenericErrorContext,
4067
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4068
    val->name);
4069
#endif
4070
0
        return;
4071
0
    }
4072
0
    if ((cur->nodeTab[i] != NULL) &&
4073
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4075
0
    cur->nodeNr--;
4076
0
    for (;i < cur->nodeNr;i++)
4077
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4078
0
    cur->nodeTab[cur->nodeNr] = NULL;
4079
0
}
4080
4081
/**
4082
 * xmlXPathNodeSetRemove:
4083
 * @cur:  the initial node set
4084
 * @val:  the index to remove
4085
 *
4086
 * Removes an entry from an existing NodeSet list.
4087
 */
4088
void
4089
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4090
0
    if (cur == NULL) return;
4091
0
    if (val >= cur->nodeNr) return;
4092
0
    if ((cur->nodeTab[val] != NULL) &&
4093
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4094
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4095
0
    cur->nodeNr--;
4096
0
    for (;val < cur->nodeNr;val++)
4097
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4098
0
    cur->nodeTab[cur->nodeNr] = NULL;
4099
0
}
4100
4101
/**
4102
 * xmlXPathFreeNodeSet:
4103
 * @obj:  the xmlNodeSetPtr to free
4104
 *
4105
 * Free the NodeSet compound (not the actual nodes !).
4106
 */
4107
void
4108
8.41M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109
8.41M
    if (obj == NULL) return;
4110
8.38M
    if (obj->nodeTab != NULL) {
4111
4.36M
  int i;
4112
4113
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114
61.3M
  for (i = 0;i < obj->nodeNr;i++)
4115
57.0M
      if ((obj->nodeTab[i] != NULL) &&
4116
57.0M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117
761k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118
4.36M
  xmlFree(obj->nodeTab);
4119
4.36M
    }
4120
8.38M
    xmlFree(obj);
4121
8.38M
}
4122
4123
/**
4124
 * xmlXPathNodeSetClearFromPos:
4125
 * @set: the node set to be cleared
4126
 * @pos: the start position to clear from
4127
 *
4128
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4129
 * are feed) starting with the entry at @pos, but does *not* free the list
4130
 * itself. Sets the length of the list to @pos.
4131
 */
4132
static void
4133
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4134
13.1k
{
4135
13.1k
    if ((set == NULL) || (pos >= set->nodeNr))
4136
0
  return;
4137
13.1k
    else if ((hasNsNodes)) {
4138
12.7k
  int i;
4139
12.7k
  xmlNodePtr node;
4140
4141
56.4k
  for (i = pos; i < set->nodeNr; i++) {
4142
43.7k
      node = set->nodeTab[i];
4143
43.7k
      if ((node != NULL) &&
4144
43.7k
    (node->type == XML_NAMESPACE_DECL))
4145
25.5k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146
43.7k
  }
4147
12.7k
    }
4148
13.1k
    set->nodeNr = pos;
4149
13.1k
}
4150
4151
/**
4152
 * xmlXPathNodeSetClear:
4153
 * @set:  the node set to clear
4154
 *
4155
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4156
 * are feed), but does *not* free the list itself. Sets the length of the
4157
 * list to 0.
4158
 */
4159
static void
4160
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4161
6.84k
{
4162
6.84k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4163
6.84k
}
4164
4165
/**
4166
 * xmlXPathNodeSetKeepLast:
4167
 * @set: the node set to be cleared
4168
 *
4169
 * Move the last node to the first position and clear temporary XPath objects
4170
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4171
 * to 1.
4172
 */
4173
static void
4174
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4175
12.4k
{
4176
12.4k
    int i;
4177
12.4k
    xmlNodePtr node;
4178
4179
12.4k
    if ((set == NULL) || (set->nodeNr <= 1))
4180
0
  return;
4181
785k
    for (i = 0; i < set->nodeNr - 1; i++) {
4182
773k
        node = set->nodeTab[i];
4183
773k
        if ((node != NULL) &&
4184
773k
            (node->type == XML_NAMESPACE_DECL))
4185
187
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
773k
    }
4187
12.4k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188
12.4k
    set->nodeNr = 1;
4189
12.4k
}
4190
4191
/**
4192
 * xmlXPathFreeValueTree:
4193
 * @obj:  the xmlNodeSetPtr to free
4194
 *
4195
 * Free the NodeSet compound and the actual tree, this is different
4196
 * from xmlXPathFreeNodeSet()
4197
 */
4198
static void
4199
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4200
0
    int i;
4201
4202
0
    if (obj == NULL) return;
4203
4204
0
    if (obj->nodeTab != NULL) {
4205
0
  for (i = 0;i < obj->nodeNr;i++) {
4206
0
      if (obj->nodeTab[i] != NULL) {
4207
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4208
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4209
0
    } else {
4210
0
        xmlFreeNodeList(obj->nodeTab[i]);
4211
0
    }
4212
0
      }
4213
0
  }
4214
0
  xmlFree(obj->nodeTab);
4215
0
    }
4216
0
    xmlFree(obj);
4217
0
}
4218
4219
#if defined(DEBUG) || defined(DEBUG_STEP)
4220
/**
4221
 * xmlGenericErrorContextNodeSet:
4222
 * @output:  a FILE * for the output
4223
 * @obj:  the xmlNodeSetPtr to display
4224
 *
4225
 * Quick display of a NodeSet
4226
 */
4227
void
4228
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4229
    int i;
4230
4231
    if (output == NULL) output = xmlGenericErrorContext;
4232
    if (obj == NULL)  {
4233
        fprintf(output, "NodeSet == NULL !\n");
4234
  return;
4235
    }
4236
    if (obj->nodeNr == 0) {
4237
        fprintf(output, "NodeSet is empty\n");
4238
  return;
4239
    }
4240
    if (obj->nodeTab == NULL) {
4241
  fprintf(output, " nodeTab == NULL !\n");
4242
  return;
4243
    }
4244
    for (i = 0; i < obj->nodeNr; i++) {
4245
        if (obj->nodeTab[i] == NULL) {
4246
      fprintf(output, " NULL !\n");
4247
      return;
4248
        }
4249
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4250
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4251
      fprintf(output, " /");
4252
  else if (obj->nodeTab[i]->name == NULL)
4253
      fprintf(output, " noname!");
4254
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4255
    }
4256
    fprintf(output, "\n");
4257
}
4258
#endif
4259
4260
/**
4261
 * xmlXPathNewNodeSet:
4262
 * @val:  the NodePtr value
4263
 *
4264
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4265
 * it with the single Node @val
4266
 *
4267
 * Returns the newly created object.
4268
 */
4269
xmlXPathObjectPtr
4270
3.72M
xmlXPathNewNodeSet(xmlNodePtr val) {
4271
3.72M
    xmlXPathObjectPtr ret;
4272
4273
3.72M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274
3.72M
    if (ret == NULL) {
4275
2.18k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4276
2.18k
  return(NULL);
4277
2.18k
    }
4278
3.72M
    memset(ret, 0 , sizeof(xmlXPathObject));
4279
3.72M
    ret->type = XPATH_NODESET;
4280
3.72M
    ret->boolval = 0;
4281
    /* TODO: Check memory error. */
4282
3.72M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4283
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4284
#ifdef XP_DEBUG_OBJ_USAGE
4285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4286
#endif
4287
3.72M
    return(ret);
4288
3.72M
}
4289
4290
/**
4291
 * xmlXPathNewValueTree:
4292
 * @val:  the NodePtr value
4293
 *
4294
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4295
 * it with the tree root @val
4296
 *
4297
 * Returns the newly created object.
4298
 */
4299
xmlXPathObjectPtr
4300
22.8k
xmlXPathNewValueTree(xmlNodePtr val) {
4301
22.8k
    xmlXPathObjectPtr ret;
4302
4303
22.8k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304
22.8k
    if (ret == NULL) {
4305
1.76k
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4306
1.76k
  return(NULL);
4307
1.76k
    }
4308
21.0k
    memset(ret, 0 , sizeof(xmlXPathObject));
4309
21.0k
    ret->type = XPATH_XSLT_TREE;
4310
21.0k
    ret->boolval = 1;
4311
21.0k
    ret->user = (void *) val;
4312
21.0k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4313
#ifdef XP_DEBUG_OBJ_USAGE
4314
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4315
#endif
4316
21.0k
    return(ret);
4317
22.8k
}
4318
4319
/**
4320
 * xmlXPathNewNodeSetList:
4321
 * @val:  an existing NodeSet
4322
 *
4323
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4324
 * it with the Nodeset @val
4325
 *
4326
 * Returns the newly created object.
4327
 */
4328
xmlXPathObjectPtr
4329
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4330
0
{
4331
0
    xmlXPathObjectPtr ret;
4332
0
    int i;
4333
4334
0
    if (val == NULL)
4335
0
        ret = NULL;
4336
0
    else if (val->nodeTab == NULL)
4337
0
        ret = xmlXPathNewNodeSet(NULL);
4338
0
    else {
4339
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4340
0
        if (ret) {
4341
0
            for (i = 1; i < val->nodeNr; ++i) {
4342
                /* TODO: Propagate memory error. */
4343
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4344
0
        < 0) break;
4345
0
      }
4346
0
  }
4347
0
    }
4348
4349
0
    return (ret);
4350
0
}
4351
4352
/**
4353
 * xmlXPathWrapNodeSet:
4354
 * @val:  the NodePtr value
4355
 *
4356
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4357
 *
4358
 * Returns the newly created object.
4359
 *
4360
 * In case of error the node set is destroyed and NULL is returned.
4361
 */
4362
xmlXPathObjectPtr
4363
2.04M
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364
2.04M
    xmlXPathObjectPtr ret;
4365
4366
2.04M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367
2.04M
    if (ret == NULL) {
4368
5.86k
        xmlXPathErrMemory(NULL, "creating node set object\n");
4369
5.86k
        xmlXPathFreeNodeSet(val);
4370
5.86k
  return(NULL);
4371
5.86k
    }
4372
2.03M
    memset(ret, 0 , sizeof(xmlXPathObject));
4373
2.03M
    ret->type = XPATH_NODESET;
4374
2.03M
    ret->nodesetval = val;
4375
#ifdef XP_DEBUG_OBJ_USAGE
4376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377
#endif
4378
2.03M
    return(ret);
4379
2.04M
}
4380
4381
/**
4382
 * xmlXPathFreeNodeSetList:
4383
 * @obj:  an existing NodeSetList object
4384
 *
4385
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4386
 * the list contrary to xmlXPathFreeObject().
4387
 */
4388
void
4389
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4390
0
    if (obj == NULL) return;
4391
#ifdef XP_DEBUG_OBJ_USAGE
4392
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4393
#endif
4394
0
    xmlFree(obj);
4395
0
}
4396
4397
/**
4398
 * xmlXPathDifference:
4399
 * @nodes1:  a node-set
4400
 * @nodes2:  a node-set
4401
 *
4402
 * Implements the EXSLT - Sets difference() function:
4403
 *    node-set set:difference (node-set, node-set)
4404
 *
4405
 * Returns the difference between the two node sets, or nodes1 if
4406
 *         nodes2 is empty
4407
 */
4408
xmlNodeSetPtr
4409
17.5k
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4410
17.5k
    xmlNodeSetPtr ret;
4411
17.5k
    int i, l1;
4412
17.5k
    xmlNodePtr cur;
4413
4414
17.5k
    if (xmlXPathNodeSetIsEmpty(nodes2))
4415
17.0k
  return(nodes1);
4416
4417
    /* TODO: Check memory error. */
4418
424
    ret = xmlXPathNodeSetCreate(NULL);
4419
424
    if (xmlXPathNodeSetIsEmpty(nodes1))
4420
125
  return(ret);
4421
4422
299
    l1 = xmlXPathNodeSetGetLength(nodes1);
4423
4424
16.7k
    for (i = 0; i < l1; i++) {
4425
16.4k
  cur = xmlXPathNodeSetItem(nodes1, i);
4426
16.4k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4427
            /* TODO: Propagate memory error. */
4428
8.07k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4429
5
          break;
4430
8.07k
  }
4431
16.4k
    }
4432
299
    return(ret);
4433
424
}
4434
4435
/**
4436
 * xmlXPathIntersection:
4437
 * @nodes1:  a node-set
4438
 * @nodes2:  a node-set
4439
 *
4440
 * Implements the EXSLT - Sets intersection() function:
4441
 *    node-set set:intersection (node-set, node-set)
4442
 *
4443
 * Returns a node set comprising the nodes that are within both the
4444
 *         node sets passed as arguments
4445
 */
4446
xmlNodeSetPtr
4447
415
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4448
415
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4449
415
    int i, l1;
4450
415
    xmlNodePtr cur;
4451
4452
415
    if (ret == NULL)
4453
1
        return(ret);
4454
414
    if (xmlXPathNodeSetIsEmpty(nodes1))
4455
132
  return(ret);
4456
282
    if (xmlXPathNodeSetIsEmpty(nodes2))
4457
150
  return(ret);
4458
4459
132
    l1 = xmlXPathNodeSetGetLength(nodes1);
4460
4461
1.45k
    for (i = 0; i < l1; i++) {
4462
1.32k
  cur = xmlXPathNodeSetItem(nodes1, i);
4463
1.32k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4464
            /* TODO: Propagate memory error. */
4465
557
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4466
1
          break;
4467
557
  }
4468
1.32k
    }
4469
132
    return(ret);
4470
282
}
4471
4472
/**
4473
 * xmlXPathDistinctSorted:
4474
 * @nodes:  a node-set, sorted by document order
4475
 *
4476
 * Implements the EXSLT - Sets distinct() function:
4477
 *    node-set set:distinct (node-set)
4478
 *
4479
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4480
 *         it is empty
4481
 */
4482
xmlNodeSetPtr
4483
233
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4484
233
    xmlNodeSetPtr ret;
4485
233
    xmlHashTablePtr hash;
4486
233
    int i, l;
4487
233
    xmlChar * strval;
4488
233
    xmlNodePtr cur;
4489
4490
233
    if (xmlXPathNodeSetIsEmpty(nodes))
4491
38
  return(nodes);
4492
4493
195
    ret = xmlXPathNodeSetCreate(NULL);
4494
195
    if (ret == NULL)
4495
1
        return(ret);
4496
194
    l = xmlXPathNodeSetGetLength(nodes);
4497
194
    hash = xmlHashCreate (l);
4498
125k
    for (i = 0; i < l; i++) {
4499
125k
  cur = xmlXPathNodeSetItem(nodes, i);
4500
125k
  strval = xmlXPathCastNodeToString(cur);
4501
125k
  if (xmlHashLookup(hash, strval) == NULL) {
4502
11.3k
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
4503
10
                xmlFree(strval);
4504
10
                goto error;
4505
10
            }
4506
11.3k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4507
1
          goto error;
4508
114k
  } else {
4509
114k
      xmlFree(strval);
4510
114k
  }
4511
125k
    }
4512
183
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4513
183
    return(ret);
4514
4515
11
error:
4516
11
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4517
11
    xmlXPathFreeNodeSet(ret);
4518
11
    return(NULL);
4519
194
}
4520
4521
/**
4522
 * xmlXPathDistinct:
4523
 * @nodes:  a node-set
4524
 *
4525
 * Implements the EXSLT - Sets distinct() function:
4526
 *    node-set set:distinct (node-set)
4527
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4528
 * is called with the sorted node-set
4529
 *
4530
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4531
 *         it is empty
4532
 */
4533
xmlNodeSetPtr
4534
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4535
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
0
  return(nodes);
4537
4538
0
    xmlXPathNodeSetSort(nodes);
4539
0
    return(xmlXPathDistinctSorted(nodes));
4540
0
}
4541
4542
/**
4543
 * xmlXPathHasSameNodes:
4544
 * @nodes1:  a node-set
4545
 * @nodes2:  a node-set
4546
 *
4547
 * Implements the EXSLT - Sets has-same-nodes function:
4548
 *    boolean set:has-same-node(node-set, node-set)
4549
 *
4550
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4551
 *         otherwise
4552
 */
4553
int
4554
1.60k
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4555
1.60k
    int i, l;
4556
1.60k
    xmlNodePtr cur;
4557
4558
1.60k
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4559
1.60k
  xmlXPathNodeSetIsEmpty(nodes2))
4560
1.31k
  return(0);
4561
4562
294
    l = xmlXPathNodeSetGetLength(nodes1);
4563
1.52k
    for (i = 0; i < l; i++) {
4564
1.40k
  cur = xmlXPathNodeSetItem(nodes1, i);
4565
1.40k
  if (xmlXPathNodeSetContains(nodes2, cur))
4566
169
      return(1);
4567
1.40k
    }
4568
125
    return(0);
4569
294
}
4570
4571
/**
4572
 * xmlXPathNodeLeadingSorted:
4573
 * @nodes: a node-set, sorted by document order
4574
 * @node: a node
4575
 *
4576
 * Implements the EXSLT - Sets leading() function:
4577
 *    node-set set:leading (node-set, node-set)
4578
 *
4579
 * Returns the nodes in @nodes that precede @node in document order,
4580
 *         @nodes if @node is NULL or an empty node-set if @nodes
4581
 *         doesn't contain @node
4582
 */
4583
xmlNodeSetPtr
4584
399
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4585
399
    int i, l;
4586
399
    xmlNodePtr cur;
4587
399
    xmlNodeSetPtr ret;
4588
4589
399
    if (node == NULL)
4590
0
  return(nodes);
4591
4592
399
    ret = xmlXPathNodeSetCreate(NULL);
4593
399
    if (ret == NULL)
4594
2
        return(ret);
4595
397
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4596
397
  (!xmlXPathNodeSetContains(nodes, node)))
4597
320
  return(ret);
4598
4599
77
    l = xmlXPathNodeSetGetLength(nodes);
4600
482
    for (i = 0; i < l; i++) {
4601
439
  cur = xmlXPathNodeSetItem(nodes, i);
4602
439
  if (cur == node)
4603
33
      break;
4604
        /* TODO: Propagate memory error. */
4605
406
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4606
1
      break;
4607
406
    }
4608
77
    return(ret);
4609
397
}
4610
4611
/**
4612
 * xmlXPathNodeLeading:
4613
 * @nodes:  a node-set
4614
 * @node:  a node
4615
 *
4616
 * Implements the EXSLT - Sets leading() function:
4617
 *    node-set set:leading (node-set, node-set)
4618
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4619
 * is called.
4620
 *
4621
 * Returns the nodes in @nodes that precede @node in document order,
4622
 *         @nodes if @node is NULL or an empty node-set if @nodes
4623
 *         doesn't contain @node
4624
 */
4625
xmlNodeSetPtr
4626
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627
0
    xmlXPathNodeSetSort(nodes);
4628
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4629
0
}
4630
4631
/**
4632
 * xmlXPathLeadingSorted:
4633
 * @nodes1:  a node-set, sorted by document order
4634
 * @nodes2:  a node-set, sorted by document order
4635
 *
4636
 * Implements the EXSLT - Sets leading() function:
4637
 *    node-set set:leading (node-set, node-set)
4638
 *
4639
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4640
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4642
 */
4643
xmlNodeSetPtr
4644
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4646
0
  return(nodes1);
4647
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4648
0
             xmlXPathNodeSetItem(nodes2, 1)));
4649
0
}
4650
4651
/**
4652
 * xmlXPathLeading:
4653
 * @nodes1:  a node-set
4654
 * @nodes2:  a node-set
4655
 *
4656
 * Implements the EXSLT - Sets leading() function:
4657
 *    node-set set:leading (node-set, node-set)
4658
 * @nodes1 and @nodes2 are sorted by document order, then
4659
 * #exslSetsLeadingSorted is called.
4660
 *
4661
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4662
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4664
 */
4665
xmlNodeSetPtr
4666
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4668
0
  return(nodes1);
4669
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4670
0
  return(xmlXPathNodeSetCreate(NULL));
4671
0
    xmlXPathNodeSetSort(nodes1);
4672
0
    xmlXPathNodeSetSort(nodes2);
4673
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4674
0
             xmlXPathNodeSetItem(nodes2, 1)));
4675
0
}
4676
4677
/**
4678
 * xmlXPathNodeTrailingSorted:
4679
 * @nodes: a node-set, sorted by document order
4680
 * @node: a node
4681
 *
4682
 * Implements the EXSLT - Sets trailing() function:
4683
 *    node-set set:trailing (node-set, node-set)
4684
 *
4685
 * Returns the nodes in @nodes that follow @node in document order,
4686
 *         @nodes if @node is NULL or an empty node-set if @nodes
4687
 *         doesn't contain @node
4688
 */
4689
xmlNodeSetPtr
4690
497
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4691
497
    int i, l;
4692
497
    xmlNodePtr cur;
4693
497
    xmlNodeSetPtr ret;
4694
4695
497
    if (node == NULL)
4696
0
  return(nodes);
4697
4698
497
    ret = xmlXPathNodeSetCreate(NULL);
4699
497
    if (ret == NULL)
4700
1
        return(ret);
4701
496
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4702
496
  (!xmlXPathNodeSetContains(nodes, node)))
4703
330
  return(ret);
4704
4705
166
    l = xmlXPathNodeSetGetLength(nodes);
4706
2.19k
    for (i = l - 1; i >= 0; i--) {
4707
2.19k
  cur = xmlXPathNodeSetItem(nodes, i);
4708
2.19k
  if (cur == node)
4709
165
      break;
4710
        /* TODO: Propagate memory error. */
4711
2.02k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4712
1
      break;
4713
2.02k
    }
4714
166
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4715
166
    return(ret);
4716
496
}
4717
4718
/**
4719
 * xmlXPathNodeTrailing:
4720
 * @nodes:  a node-set
4721
 * @node:  a node
4722
 *
4723
 * Implements the EXSLT - Sets trailing() function:
4724
 *    node-set set:trailing (node-set, node-set)
4725
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4726
 * is called.
4727
 *
4728
 * Returns the nodes in @nodes that follow @node in document order,
4729
 *         @nodes if @node is NULL or an empty node-set if @nodes
4730
 *         doesn't contain @node
4731
 */
4732
xmlNodeSetPtr
4733
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4734
0
    xmlXPathNodeSetSort(nodes);
4735
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4736
0
}
4737
4738
/**
4739
 * xmlXPathTrailingSorted:
4740
 * @nodes1:  a node-set, sorted by document order
4741
 * @nodes2:  a node-set, sorted by document order
4742
 *
4743
 * Implements the EXSLT - Sets trailing() function:
4744
 *    node-set set:trailing (node-set, node-set)
4745
 *
4746
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4747
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4748
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4749
 */
4750
xmlNodeSetPtr
4751
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4752
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4753
0
  return(nodes1);
4754
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4755
0
              xmlXPathNodeSetItem(nodes2, 0)));
4756
0
}
4757
4758
/**
4759
 * xmlXPathTrailing:
4760
 * @nodes1:  a node-set
4761
 * @nodes2:  a node-set
4762
 *
4763
 * Implements the EXSLT - Sets trailing() function:
4764
 *    node-set set:trailing (node-set, node-set)
4765
 * @nodes1 and @nodes2 are sorted by document order, then
4766
 * #xmlXPathTrailingSorted is called.
4767
 *
4768
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4769
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4770
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4771
 */
4772
xmlNodeSetPtr
4773
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4774
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4775
0
  return(nodes1);
4776
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4777
0
  return(xmlXPathNodeSetCreate(NULL));
4778
0
    xmlXPathNodeSetSort(nodes1);
4779
0
    xmlXPathNodeSetSort(nodes2);
4780
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4781
0
              xmlXPathNodeSetItem(nodes2, 0)));
4782
0
}
4783
4784
/************************************************************************
4785
 *                  *
4786
 *    Routines to handle extra functions      *
4787
 *                  *
4788
 ************************************************************************/
4789
4790
/**
4791
 * xmlXPathRegisterFunc:
4792
 * @ctxt:  the XPath context
4793
 * @name:  the function name
4794
 * @f:  the function implementation or NULL
4795
 *
4796
 * Register a new function. If @f is NULL it unregisters the function
4797
 *
4798
 * Returns 0 in case of success, -1 in case of error
4799
 */
4800
int
4801
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4802
1.75M
         xmlXPathFunction f) {
4803
1.75M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4804
1.75M
}
4805
4806
/**
4807
 * xmlXPathRegisterFuncNS:
4808
 * @ctxt:  the XPath context
4809
 * @name:  the function name
4810
 * @ns_uri:  the function namespace URI
4811
 * @f:  the function implementation or NULL
4812
 *
4813
 * Register a new function. If @f is NULL it unregisters the function
4814
 *
4815
 * Returns 0 in case of success, -1 in case of error
4816
 */
4817
int
4818
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4819
1.81M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4820
1.81M
    if (ctxt == NULL)
4821
0
  return(-1);
4822
1.81M
    if (name == NULL)
4823
0
  return(-1);
4824
4825
1.81M
    if (ctxt->funcHash == NULL)
4826
196
  ctxt->funcHash = xmlHashCreate(0);
4827
1.81M
    if (ctxt->funcHash == NULL)
4828
196
  return(-1);
4829
1.81M
    if (f == NULL)
4830
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831
1.81M
XML_IGNORE_FPTR_CAST_WARNINGS
4832
1.81M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833
1.81M
XML_POP_WARNINGS
4834
1.81M
}
4835
4836
/**
4837
 * xmlXPathRegisterFuncLookup:
4838
 * @ctxt:  the XPath context
4839
 * @f:  the lookup function
4840
 * @funcCtxt:  the lookup data
4841
 *
4842
 * Registers an external mechanism to do function lookup.
4843
 */
4844
void
4845
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4846
          xmlXPathFuncLookupFunc f,
4847
14.5k
          void *funcCtxt) {
4848
14.5k
    if (ctxt == NULL)
4849
0
  return;
4850
14.5k
    ctxt->funcLookupFunc = f;
4851
14.5k
    ctxt->funcLookupData = funcCtxt;
4852
14.5k
}
4853
4854
/**
4855
 * xmlXPathFunctionLookup:
4856
 * @ctxt:  the XPath context
4857
 * @name:  the function name
4858
 *
4859
 * Search in the Function array of the context for the given
4860
 * function.
4861
 *
4862
 * Returns the xmlXPathFunction or NULL if not found
4863
 */
4864
xmlXPathFunction
4865
56.6k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4866
56.6k
    if (ctxt == NULL)
4867
0
  return (NULL);
4868
4869
56.6k
    if (ctxt->funcLookupFunc != NULL) {
4870
56.6k
  xmlXPathFunction ret;
4871
56.6k
  xmlXPathFuncLookupFunc f;
4872
4873
56.6k
  f = ctxt->funcLookupFunc;
4874
56.6k
  ret = f(ctxt->funcLookupData, name, NULL);
4875
56.6k
  if (ret != NULL)
4876
0
      return(ret);
4877
56.6k
    }
4878
56.6k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4879
56.6k
}
4880
4881
/**
4882
 * xmlXPathFunctionLookupNS:
4883
 * @ctxt:  the XPath context
4884
 * @name:  the function name
4885
 * @ns_uri:  the function namespace URI
4886
 *
4887
 * Search in the Function array of the context for the given
4888
 * function.
4889
 *
4890
 * Returns the xmlXPathFunction or NULL if not found
4891
 */
4892
xmlXPathFunction
4893
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4894
522k
       const xmlChar *ns_uri) {
4895
522k
    xmlXPathFunction ret;
4896
4897
522k
    if (ctxt == NULL)
4898
0
  return(NULL);
4899
522k
    if (name == NULL)
4900
0
  return(NULL);
4901
4902
522k
    if (ctxt->funcLookupFunc != NULL) {
4903
522k
  xmlXPathFuncLookupFunc f;
4904
4905
522k
  f = ctxt->funcLookupFunc;
4906
522k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4907
522k
  if (ret != NULL)
4908
449k
      return(ret);
4909
522k
    }
4910
4911
72.7k
    if (ctxt->funcHash == NULL)
4912
0
  return(NULL);
4913
4914
72.7k
XML_IGNORE_FPTR_CAST_WARNINGS
4915
72.7k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4916
72.7k
XML_POP_WARNINGS
4917
72.7k
    return(ret);
4918
72.7k
}
4919
4920
/**
4921
 * xmlXPathRegisteredFuncsCleanup:
4922
 * @ctxt:  the XPath context
4923
 *
4924
 * Cleanup the XPath context data associated to registered functions
4925
 */
4926
void
4927
60.0k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928
60.0k
    if (ctxt == NULL)
4929
0
  return;
4930
4931
60.0k
    xmlHashFree(ctxt->funcHash, NULL);
4932
60.0k
    ctxt->funcHash = NULL;
4933
60.0k
}
4934
4935
/************************************************************************
4936
 *                  *
4937
 *      Routines to handle Variables      *
4938
 *                  *
4939
 ************************************************************************/
4940
4941
/**
4942
 * xmlXPathRegisterVariable:
4943
 * @ctxt:  the XPath context
4944
 * @name:  the variable name
4945
 * @value:  the variable value or NULL
4946
 *
4947
 * Register a new variable value. If @value is NULL it unregisters
4948
 * the variable
4949
 *
4950
 * Returns 0 in case of success, -1 in case of error
4951
 */
4952
int
4953
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4954
1.59k
       xmlXPathObjectPtr value) {
4955
1.59k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956
1.59k
}
4957
4958
/**
4959
 * xmlXPathRegisterVariableNS:
4960
 * @ctxt:  the XPath context
4961
 * @name:  the variable name
4962
 * @ns_uri:  the variable namespace URI
4963
 * @value:  the variable value or NULL
4964
 *
4965
 * Register a new variable value. If @value is NULL it unregisters
4966
 * the variable
4967
 *
4968
 * Returns 0 in case of success, -1 in case of error
4969
 */
4970
int
4971
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972
         const xmlChar *ns_uri,
4973
1.59k
         xmlXPathObjectPtr value) {
4974
1.59k
    if (ctxt == NULL)
4975
0
  return(-1);
4976
1.59k
    if (name == NULL)
4977
0
  return(-1);
4978
4979
1.59k
    if (ctxt->varHash == NULL)
4980
399
  ctxt->varHash = xmlHashCreate(0);
4981
1.59k
    if (ctxt->varHash == NULL)
4982
0
  return(-1);
4983
1.59k
    if (value == NULL)
4984
3
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985
3
                             xmlXPathFreeObjectEntry));
4986
1.59k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987
1.59k
             (void *) value, xmlXPathFreeObjectEntry));
4988
1.59k
}
4989
4990
/**
4991
 * xmlXPathRegisterVariableLookup:
4992
 * @ctxt:  the XPath context
4993
 * @f:  the lookup function
4994
 * @data:  the lookup data
4995
 *
4996
 * register an external mechanism to do variable lookup
4997
 */
4998
void
4999
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5000
14.5k
   xmlXPathVariableLookupFunc f, void *data) {
5001
14.5k
    if (ctxt == NULL)
5002
0
  return;
5003
14.5k
    ctxt->varLookupFunc = f;
5004
14.5k
    ctxt->varLookupData = data;
5005
14.5k
}
5006
5007
/**
5008
 * xmlXPathVariableLookup:
5009
 * @ctxt:  the XPath context
5010
 * @name:  the variable name
5011
 *
5012
 * Search in the Variable array of the context for the given
5013
 * variable value.
5014
 *
5015
 * Returns a copy of the value or NULL if not found
5016
 */
5017
xmlXPathObjectPtr
5018
84.7k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5019
84.7k
    if (ctxt == NULL)
5020
0
  return(NULL);
5021
5022
84.7k
    if (ctxt->varLookupFunc != NULL) {
5023
84.7k
  xmlXPathObjectPtr ret;
5024
5025
84.7k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5026
84.7k
          (ctxt->varLookupData, name, NULL);
5027
84.7k
  return(ret);
5028
84.7k
    }
5029
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5030
84.7k
}
5031
5032
/**
5033
 * xmlXPathVariableLookupNS:
5034
 * @ctxt:  the XPath context
5035
 * @name:  the variable name
5036
 * @ns_uri:  the variable namespace URI
5037
 *
5038
 * Search in the Variable array of the context for the given
5039
 * variable value.
5040
 *
5041
 * Returns the a copy of the value or NULL if not found
5042
 */
5043
xmlXPathObjectPtr
5044
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5045
356
       const xmlChar *ns_uri) {
5046
356
    if (ctxt == NULL)
5047
0
  return(NULL);
5048
5049
356
    if (ctxt->varLookupFunc != NULL) {
5050
356
  xmlXPathObjectPtr ret;
5051
5052
356
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5053
356
          (ctxt->varLookupData, name, ns_uri);
5054
356
  if (ret != NULL) return(ret);
5055
356
    }
5056
5057
356
    if (ctxt->varHash == NULL)
5058
356
  return(NULL);
5059
0
    if (name == NULL)
5060
0
  return(NULL);
5061
5062
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5063
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5064
0
}
5065
5066
/**
5067
 * xmlXPathRegisteredVariablesCleanup:
5068
 * @ctxt:  the XPath context
5069
 *
5070
 * Cleanup the XPath context data associated to registered variables
5071
 */
5072
void
5073
60.0k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074
60.0k
    if (ctxt == NULL)
5075
0
  return;
5076
5077
60.0k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078
60.0k
    ctxt->varHash = NULL;
5079
60.0k
}
5080
5081
/**
5082
 * xmlXPathRegisterNs:
5083
 * @ctxt:  the XPath context
5084
 * @prefix:  the namespace prefix cannot be NULL or empty string
5085
 * @ns_uri:  the namespace name
5086
 *
5087
 * Register a new namespace. If @ns_uri is NULL it unregisters
5088
 * the namespace
5089
 *
5090
 * Returns 0 in case of success, -1 in case of error
5091
 */
5092
int
5093
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5094
4.38k
         const xmlChar *ns_uri) {
5095
4.38k
    xmlChar *copy;
5096
5097
4.38k
    if (ctxt == NULL)
5098
0
  return(-1);
5099
4.38k
    if (prefix == NULL)
5100
0
  return(-1);
5101
4.38k
    if (prefix[0] == 0)
5102
0
  return(-1);
5103
5104
4.38k
    if (ctxt->nsHash == NULL)
5105
399
  ctxt->nsHash = xmlHashCreate(10);
5106
4.38k
    if (ctxt->nsHash == NULL)
5107
0
  return(-1);
5108
4.38k
    if (ns_uri == NULL)
5109
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110
0
                            xmlHashDefaultDeallocator));
5111
5112
4.38k
    copy = xmlStrdup(ns_uri);
5113
4.38k
    if (copy == NULL)
5114
0
        return(-1);
5115
4.38k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116
4.38k
                           xmlHashDefaultDeallocator) < 0) {
5117
0
        xmlFree(copy);
5118
0
        return(-1);
5119
0
    }
5120
5121
4.38k
    return(0);
5122
4.38k
}
5123
5124
/**
5125
 * xmlXPathNsLookup:
5126
 * @ctxt:  the XPath context
5127
 * @prefix:  the namespace prefix value
5128
 *
5129
 * Search in the namespace declaration array of the context for the given
5130
 * namespace name associated to the given prefix
5131
 *
5132
 * Returns the value or NULL if not found
5133
 */
5134
const xmlChar *
5135
803k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136
803k
    if (ctxt == NULL)
5137
0
  return(NULL);
5138
803k
    if (prefix == NULL)
5139
0
  return(NULL);
5140
5141
803k
#ifdef XML_XML_NAMESPACE
5142
803k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143
8.61k
  return(XML_XML_NAMESPACE);
5144
794k
#endif
5145
5146
794k
    if (ctxt->namespaces != NULL) {
5147
673k
  int i;
5148
5149
4.69M
  for (i = 0;i < ctxt->nsNr;i++) {
5150
4.57M
      if ((ctxt->namespaces[i] != NULL) &&
5151
4.57M
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5152
553k
    return(ctxt->namespaces[i]->href);
5153
4.57M
  }
5154
673k
    }
5155
5156
241k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157
794k
}
5158
5159
/**
5160
 * xmlXPathRegisteredNsCleanup:
5161
 * @ctxt:  the XPath context
5162
 *
5163
 * Cleanup the XPath context data associated to registered variables
5164
 */
5165
void
5166
60.4k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167
60.4k
    if (ctxt == NULL)
5168
11
  return;
5169
5170
60.4k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171
60.4k
    ctxt->nsHash = NULL;
5172
60.4k
}
5173
5174
/************************************************************************
5175
 *                  *
5176
 *      Routines to handle Values     *
5177
 *                  *
5178
 ************************************************************************/
5179
5180
/* Allocations are terrible, one needs to optimize all this !!! */
5181
5182
/**
5183
 * xmlXPathNewFloat:
5184
 * @val:  the double value
5185
 *
5186
 * Create a new xmlXPathObjectPtr of type double and of value @val
5187
 *
5188
 * Returns the newly created object.
5189
 */
5190
xmlXPathObjectPtr
5191
1.17M
xmlXPathNewFloat(double val) {
5192
1.17M
    xmlXPathObjectPtr ret;
5193
5194
1.17M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195
1.17M
    if (ret == NULL) {
5196
2.44k
        xmlXPathErrMemory(NULL, "creating float object\n");
5197
2.44k
  return(NULL);
5198
2.44k
    }
5199
1.17M
    memset(ret, 0 , sizeof(xmlXPathObject));
5200
1.17M
    ret->type = XPATH_NUMBER;
5201
1.17M
    ret->floatval = val;
5202
#ifdef XP_DEBUG_OBJ_USAGE
5203
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204
#endif
5205
1.17M
    return(ret);
5206
1.17M
}
5207
5208
/**
5209
 * xmlXPathNewBoolean:
5210
 * @val:  the boolean value
5211
 *
5212
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5213
 *
5214
 * Returns the newly created object.
5215
 */
5216
xmlXPathObjectPtr
5217
380k
xmlXPathNewBoolean(int val) {
5218
380k
    xmlXPathObjectPtr ret;
5219
5220
380k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221
380k
    if (ret == NULL) {
5222
2.53k
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5223
2.53k
  return(NULL);
5224
2.53k
    }
5225
378k
    memset(ret, 0 , sizeof(xmlXPathObject));
5226
378k
    ret->type = XPATH_BOOLEAN;
5227
378k
    ret->boolval = (val != 0);
5228
#ifdef XP_DEBUG_OBJ_USAGE
5229
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230
#endif
5231
378k
    return(ret);
5232
380k
}
5233
5234
/**
5235
 * xmlXPathNewString:
5236
 * @val:  the xmlChar * value
5237
 *
5238
 * Create a new xmlXPathObjectPtr of type string and of value @val
5239
 *
5240
 * Returns the newly created object.
5241
 */
5242
xmlXPathObjectPtr
5243
225k
xmlXPathNewString(const xmlChar *val) {
5244
225k
    xmlXPathObjectPtr ret;
5245
5246
225k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
225k
    if (ret == NULL) {
5248
4.93k
        xmlXPathErrMemory(NULL, "creating string object\n");
5249
4.93k
  return(NULL);
5250
4.93k
    }
5251
220k
    memset(ret, 0 , sizeof(xmlXPathObject));
5252
220k
    ret->type = XPATH_STRING;
5253
220k
    if (val == NULL)
5254
135
        val = BAD_CAST "";
5255
220k
    ret->stringval = xmlStrdup(val);
5256
220k
    if (ret->stringval == NULL) {
5257
40
        xmlFree(ret);
5258
40
        return(NULL);
5259
40
    }
5260
#ifdef XP_DEBUG_OBJ_USAGE
5261
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5262
#endif
5263
220k
    return(ret);
5264
220k
}
5265
5266
/**
5267
 * xmlXPathWrapString:
5268
 * @val:  the xmlChar * value
5269
 *
5270
 * Wraps the @val string into an XPath object.
5271
 *
5272
 * Returns the newly created object.
5273
 *
5274
 * Frees @val in case of error.
5275
 */
5276
xmlXPathObjectPtr
5277
663k
xmlXPathWrapString (xmlChar *val) {
5278
663k
    xmlXPathObjectPtr ret;
5279
5280
663k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281
663k
    if (ret == NULL) {
5282
112
        xmlXPathErrMemory(NULL, "creating string object\n");
5283
112
        xmlFree(val);
5284
112
  return(NULL);
5285
112
    }
5286
663k
    memset(ret, 0 , sizeof(xmlXPathObject));
5287
663k
    ret->type = XPATH_STRING;
5288
663k
    ret->stringval = val;
5289
#ifdef XP_DEBUG_OBJ_USAGE
5290
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291
#endif
5292
663k
    return(ret);
5293
663k
}
5294
5295
/**
5296
 * xmlXPathNewCString:
5297
 * @val:  the char * value
5298
 *
5299
 * Create a new xmlXPathObjectPtr of type string and of value @val
5300
 *
5301
 * Returns the newly created object.
5302
 */
5303
xmlXPathObjectPtr
5304
44.9k
xmlXPathNewCString(const char *val) {
5305
44.9k
    return(xmlXPathNewString(BAD_CAST val));
5306
44.9k
}
5307
5308
/**
5309
 * xmlXPathWrapCString:
5310
 * @val:  the char * value
5311
 *
5312
 * Wraps a string into an XPath object.
5313
 *
5314
 * Returns the newly created object.
5315
 */
5316
xmlXPathObjectPtr
5317
0
xmlXPathWrapCString (char * val) {
5318
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5319
0
}
5320
5321
/**
5322
 * xmlXPathWrapExternal:
5323
 * @val:  the user data
5324
 *
5325
 * Wraps the @val data into an XPath object.
5326
 *
5327
 * Returns the newly created object.
5328
 */
5329
xmlXPathObjectPtr
5330
917
xmlXPathWrapExternal (void *val) {
5331
917
    xmlXPathObjectPtr ret;
5332
5333
917
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334
917
    if (ret == NULL) {
5335
5
        xmlXPathErrMemory(NULL, "creating user object\n");
5336
5
  return(NULL);
5337
5
    }
5338
912
    memset(ret, 0 , sizeof(xmlXPathObject));
5339
912
    ret->type = XPATH_USERS;
5340
912
    ret->user = val;
5341
#ifdef XP_DEBUG_OBJ_USAGE
5342
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343
#endif
5344
912
    return(ret);
5345
917
}
5346
5347
/**
5348
 * xmlXPathObjectCopy:
5349
 * @val:  the original object
5350
 *
5351
 * allocate a new copy of a given object
5352
 *
5353
 * Returns the newly created object.
5354
 */
5355
xmlXPathObjectPtr
5356
429k
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5357
429k
    xmlXPathObjectPtr ret;
5358
5359
429k
    if (val == NULL)
5360
1
  return(NULL);
5361
5362
429k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5363
429k
    if (ret == NULL) {
5364
314
        xmlXPathErrMemory(NULL, "copying object\n");
5365
314
  return(NULL);
5366
314
    }
5367
429k
    memcpy(ret, val , sizeof(xmlXPathObject));
5368
#ifdef XP_DEBUG_OBJ_USAGE
5369
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5370
#endif
5371
429k
    switch (val->type) {
5372
5
  case XPATH_BOOLEAN:
5373
7.50k
  case XPATH_NUMBER:
5374
#ifdef LIBXML_XPTR_LOCS_ENABLED
5375
  case XPATH_POINT:
5376
  case XPATH_RANGE:
5377
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5378
7.50k
      break;
5379
38.9k
  case XPATH_STRING:
5380
38.9k
      ret->stringval = xmlStrdup(val->stringval);
5381
38.9k
            if (ret->stringval == NULL) {
5382
18
                xmlFree(ret);
5383
18
                return(NULL);
5384
18
            }
5385
38.8k
      break;
5386
38.8k
  case XPATH_XSLT_TREE:
5387
#if 0
5388
/*
5389
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390
  this previous handling is no longer correct, and can cause some serious
5391
  problems (ref. bug 145547)
5392
*/
5393
      if ((val->nodesetval != NULL) &&
5394
    (val->nodesetval->nodeTab != NULL)) {
5395
    xmlNodePtr cur, tmp;
5396
    xmlDocPtr top;
5397
5398
    ret->boolval = 1;
5399
    top =  xmlNewDoc(NULL);
5400
    top->name = (char *)
5401
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5402
    ret->user = top;
5403
    if (top != NULL) {
5404
        top->doc = top;
5405
        cur = val->nodesetval->nodeTab[0]->children;
5406
        while (cur != NULL) {
5407
      tmp = xmlDocCopyNode(cur, top, 1);
5408
      xmlAddChild((xmlNodePtr) top, tmp);
5409
      cur = cur->next;
5410
        }
5411
    }
5412
5413
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5414
      } else
5415
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5416
      /* Deallocate the copied tree value */
5417
      break;
5418
#endif
5419
383k
  case XPATH_NODESET:
5420
            /* TODO: Check memory error. */
5421
383k
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5422
      /* Do not deallocate the copied tree value */
5423
383k
      ret->boolval = 0;
5424
383k
      break;
5425
#ifdef LIBXML_XPTR_LOCS_ENABLED
5426
  case XPATH_LOCATIONSET:
5427
  {
5428
      xmlLocationSetPtr loc = val->user;
5429
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5430
      break;
5431
  }
5432
#endif
5433
0
        case XPATH_USERS:
5434
0
      ret->user = val->user;
5435
0
      break;
5436
0
        case XPATH_UNDEFINED:
5437
0
      xmlGenericError(xmlGenericErrorContext,
5438
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5439
0
        val->type);
5440
0
      break;
5441
429k
    }
5442
429k
    return(ret);
5443
429k
}
5444
5445
/**
5446
 * xmlXPathFreeObject:
5447
 * @obj:  the object to free
5448
 *
5449
 * Free up an xmlXPathObjectPtr object.
5450
 */
5451
void
5452
8.01M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453
8.01M
    if (obj == NULL) return;
5454
7.82M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455
4.63M
  if (obj->boolval) {
5456
#if 0
5457
      if (obj->user != NULL) {
5458
                xmlXPathFreeNodeSet(obj->nodesetval);
5459
    xmlFreeNodeList((xmlNodePtr) obj->user);
5460
      } else
5461
#endif
5462
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5463
0
      if (obj->nodesetval != NULL)
5464
0
    xmlXPathFreeValueTree(obj->nodesetval);
5465
4.63M
  } else {
5466
4.63M
      if (obj->nodesetval != NULL)
5467
4.17M
    xmlXPathFreeNodeSet(obj->nodesetval);
5468
4.63M
  }
5469
#ifdef LIBXML_XPTR_LOCS_ENABLED
5470
    } else if (obj->type == XPATH_LOCATIONSET) {
5471
  if (obj->user != NULL)
5472
      xmlXPtrFreeLocationSet(obj->user);
5473
#endif
5474
4.63M
    } else if (obj->type == XPATH_STRING) {
5475
1.27M
  if (obj->stringval != NULL)
5476
1.24M
      xmlFree(obj->stringval);
5477
1.27M
    }
5478
#ifdef XP_DEBUG_OBJ_USAGE
5479
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480
#endif
5481
7.82M
    xmlFree(obj);
5482
7.82M
}
5483
5484
static void
5485
1.59k
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486
1.59k
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487
1.59k
}
5488
5489
/**
5490
 * xmlXPathReleaseObject:
5491
 * @obj:  the xmlXPathObjectPtr to free or to cache
5492
 *
5493
 * Depending on the state of the cache this frees the given
5494
 * XPath object or stores it in the cache.
5495
 */
5496
static void
5497
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5498
20.0M
{
5499
20.0M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500
29.8k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501
19.5M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502
5503
22.9M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504
5505
20.0M
    if (obj == NULL)
5506
21.4k
  return;
5507
20.0M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508
16.2k
   xmlXPathFreeObject(obj);
5509
20.0M
    } else {
5510
20.0M
  xmlXPathContextCachePtr cache =
5511
20.0M
      (xmlXPathContextCachePtr) ctxt->cache;
5512
5513
20.0M
  switch (obj->type) {
5514
12.0M
      case XPATH_NODESET:
5515
12.0M
      case XPATH_XSLT_TREE:
5516
12.0M
    if (obj->nodesetval != NULL) {
5517
10.3M
        if (obj->boolval) {
5518
      /*
5519
      * It looks like the @boolval is used for
5520
      * evaluation if this an XSLT Result Tree Fragment.
5521
      * TODO: Check if this assumption is correct.
5522
      */
5523
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5524
0
      xmlXPathFreeValueTree(obj->nodesetval);
5525
0
      obj->nodesetval = NULL;
5526
10.3M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5527
10.3M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5528
10.3M
          cache->maxNodeset)))
5529
7.75M
        {
5530
7.75M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5531
7.75M
      goto obj_cached;
5532
7.75M
        } else {
5533
2.58M
      xmlXPathFreeNodeSet(obj->nodesetval);
5534
2.58M
      obj->nodesetval = NULL;
5535
2.58M
        }
5536
10.3M
    }
5537
4.28M
    break;
5538
4.28M
      case XPATH_STRING:
5539
2.36M
    if (obj->stringval != NULL)
5540
2.36M
        xmlFree(obj->stringval);
5541
5542
2.36M
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543
2.17M
        XP_CACHE_ADD(cache->stringObjs, obj);
5544
2.17M
        goto obj_cached;
5545
2.17M
    }
5546
183k
    break;
5547
1.11M
      case XPATH_BOOLEAN:
5548
1.11M
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549
1.11M
        XP_CACHE_ADD(cache->booleanObjs, obj);
5550
1.10M
        goto obj_cached;
5551
1.11M
    }
5552
570
    break;
5553
4.50M
      case XPATH_NUMBER:
5554
4.50M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555
4.30M
        XP_CACHE_ADD(cache->numberObjs, obj);
5556
4.29M
        goto obj_cached;
5557
4.29M
    }
5558
201k
    break;
5559
#ifdef LIBXML_XPTR_LOCS_ENABLED
5560
      case XPATH_LOCATIONSET:
5561
    if (obj->user != NULL) {
5562
        xmlXPtrFreeLocationSet(obj->user);
5563
    }
5564
    goto free_obj;
5565
#endif
5566
201k
      default:
5567
909
    goto free_obj;
5568
20.0M
  }
5569
5570
  /*
5571
  * Fallback to adding to the misc-objects slot.
5572
  */
5573
4.66M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574
4.24M
      XP_CACHE_ADD(cache->miscObjs, obj);
5575
4.24M
  } else
5576
423k
      goto free_obj;
5577
5578
19.5M
obj_cached:
5579
5580
#ifdef XP_DEBUG_OBJ_USAGE
5581
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582
#endif
5583
5584
19.5M
  if (obj->nodesetval != NULL) {
5585
7.75M
      xmlNodeSetPtr tmpset = obj->nodesetval;
5586
5587
      /*
5588
      * TODO: Due to those nasty ns-nodes, we need to traverse
5589
      *  the list and free the ns-nodes.
5590
      * URGENT TODO: Check if it's actually slowing things down.
5591
      *  Maybe we shouldn't try to preserve the list.
5592
      */
5593
7.75M
      if (tmpset->nodeNr > 1) {
5594
690k
    int i;
5595
690k
    xmlNodePtr node;
5596
5597
10.9M
    for (i = 0; i < tmpset->nodeNr; i++) {
5598
10.2M
        node = tmpset->nodeTab[i];
5599
10.2M
        if ((node != NULL) &&
5600
10.2M
      (node->type == XML_NAMESPACE_DECL))
5601
17.2k
        {
5602
17.2k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603
17.2k
        }
5604
10.2M
    }
5605
7.06M
      } else if (tmpset->nodeNr == 1) {
5606
6.02M
    if ((tmpset->nodeTab[0] != NULL) &&
5607
6.02M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608
63.3k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609
6.02M
      }
5610
7.75M
      tmpset->nodeNr = 0;
5611
7.75M
      memset(obj, 0, sizeof(xmlXPathObject));
5612
7.75M
      obj->nodesetval = tmpset;
5613
7.75M
  } else
5614
11.8M
      memset(obj, 0, sizeof(xmlXPathObject));
5615
5616
19.5M
  return;
5617
5618
442k
free_obj:
5619
  /*
5620
  * Cache is full; free the object.
5621
  */
5622
442k
  if (obj->nodesetval != NULL)
5623
8.43k
      xmlXPathFreeNodeSet(obj->nodesetval);
5624
#ifdef XP_DEBUG_OBJ_USAGE
5625
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626
#endif
5627
442k
  xmlFree(obj);
5628
442k
    }
5629
458k
    return;
5630
20.0M
}
5631
5632
5633
/************************************************************************
5634
 *                  *
5635
 *      Type Casting Routines       *
5636
 *                  *
5637
 ************************************************************************/
5638
5639
/**
5640
 * xmlXPathCastBooleanToString:
5641
 * @val:  a boolean
5642
 *
5643
 * Converts a boolean to its string value.
5644
 *
5645
 * Returns a newly allocated string.
5646
 */
5647
xmlChar *
5648
92.3k
xmlXPathCastBooleanToString (int val) {
5649
92.3k
    xmlChar *ret;
5650
92.3k
    if (val)
5651
20.2k
  ret = xmlStrdup((const xmlChar *) "true");
5652
72.0k
    else
5653
72.0k
  ret = xmlStrdup((const xmlChar *) "false");
5654
92.3k
    return(ret);
5655
92.3k
}
5656
5657
/**
5658
 * xmlXPathCastNumberToString:
5659
 * @val:  a number
5660
 *
5661
 * Converts a number to its string value.
5662
 *
5663
 * Returns a newly allocated string.
5664
 */
5665
xmlChar *
5666
435k
xmlXPathCastNumberToString (double val) {
5667
435k
    xmlChar *ret;
5668
435k
    switch (xmlXPathIsInf(val)) {
5669
222
    case 1:
5670
222
  ret = xmlStrdup((const xmlChar *) "Infinity");
5671
222
  break;
5672
207
    case -1:
5673
207
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5674
207
  break;
5675
434k
    default:
5676
434k
  if (xmlXPathIsNaN(val)) {
5677
291k
      ret = xmlStrdup((const xmlChar *) "NaN");
5678
291k
  } else if (val == 0) {
5679
            /* Omit sign for negative zero. */
5680
26.3k
      ret = xmlStrdup((const xmlChar *) "0");
5681
117k
  } else {
5682
      /* could be improved */
5683
117k
      char buf[100];
5684
117k
      xmlXPathFormatNumber(val, buf, 99);
5685
117k
      buf[99] = 0;
5686
117k
      ret = xmlStrdup((const xmlChar *) buf);
5687
117k
  }
5688
435k
    }
5689
435k
    return(ret);
5690
435k
}
5691
5692
/**
5693
 * xmlXPathCastNodeToString:
5694
 * @node:  a node
5695
 *
5696
 * Converts a node to its string value.
5697
 *
5698
 * Returns a newly allocated string.
5699
 */
5700
xmlChar *
5701
4.91M
xmlXPathCastNodeToString (xmlNodePtr node) {
5702
4.91M
xmlChar *ret;
5703
4.91M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5704
17.8k
  ret = xmlStrdup((const xmlChar *) "");
5705
4.91M
    return(ret);
5706
4.91M
}
5707
5708
/**
5709
 * xmlXPathCastNodeSetToString:
5710
 * @ns:  a node-set
5711
 *
5712
 * Converts a node-set to its string value.
5713
 *
5714
 * Returns a newly allocated string.
5715
 */
5716
xmlChar *
5717
3.67M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718
3.67M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719
1.08M
  return(xmlStrdup((const xmlChar *) ""));
5720
5721
2.59M
    if (ns->nodeNr > 1)
5722
88.5k
  xmlXPathNodeSetSort(ns);
5723
2.59M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724
3.67M
}
5725
5726
/**
5727
 * xmlXPathCastToString:
5728
 * @val:  an XPath object
5729
 *
5730
 * Converts an existing object to its string() equivalent
5731
 *
5732
 * Returns the allocated string value of the object, NULL in case of error.
5733
 *         It's up to the caller to free the string memory with xmlFree().
5734
 */
5735
xmlChar *
5736
1.91M
xmlXPathCastToString(xmlXPathObjectPtr val) {
5737
1.91M
    xmlChar *ret = NULL;
5738
5739
1.91M
    if (val == NULL)
5740
0
  return(xmlStrdup((const xmlChar *) ""));
5741
1.91M
    switch (val->type) {
5742
0
  case XPATH_UNDEFINED:
5743
#ifdef DEBUG_EXPR
5744
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5745
#endif
5746
0
      ret = xmlStrdup((const xmlChar *) "");
5747
0
      break;
5748
1.46M
        case XPATH_NODESET:
5749
1.46M
        case XPATH_XSLT_TREE:
5750
1.46M
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751
1.46M
      break;
5752
129k
  case XPATH_STRING:
5753
129k
      return(xmlStrdup(val->stringval));
5754
80.1k
        case XPATH_BOOLEAN:
5755
80.1k
      ret = xmlXPathCastBooleanToString(val->boolval);
5756
80.1k
      break;
5757
237k
  case XPATH_NUMBER: {
5758
237k
      ret = xmlXPathCastNumberToString(val->floatval);
5759
237k
      break;
5760
1.46M
  }
5761
0
  case XPATH_USERS:
5762
#ifdef LIBXML_XPTR_LOCS_ENABLED
5763
  case XPATH_POINT:
5764
  case XPATH_RANGE:
5765
  case XPATH_LOCATIONSET:
5766
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5767
0
      TODO
5768
0
      ret = xmlStrdup((const xmlChar *) "");
5769
0
      break;
5770
1.91M
    }
5771
1.78M
    return(ret);
5772
1.91M
}
5773
5774
/**
5775
 * xmlXPathConvertString:
5776
 * @val:  an XPath object
5777
 *
5778
 * Converts an existing object to its string() equivalent
5779
 *
5780
 * Returns the new object, the old one is freed (or the operation
5781
 *         is done directly on @val)
5782
 */
5783
xmlXPathObjectPtr
5784
371k
xmlXPathConvertString(xmlXPathObjectPtr val) {
5785
371k
    xmlChar *res = NULL;
5786
5787
371k
    if (val == NULL)
5788
0
  return(xmlXPathNewCString(""));
5789
5790
371k
    switch (val->type) {
5791
0
    case XPATH_UNDEFINED:
5792
#ifdef DEBUG_EXPR
5793
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5794
#endif
5795
0
  break;
5796
345k
    case XPATH_NODESET:
5797
346k
    case XPATH_XSLT_TREE:
5798
346k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5799
346k
  break;
5800
0
    case XPATH_STRING:
5801
0
  return(val);
5802
6.02k
    case XPATH_BOOLEAN:
5803
6.02k
  res = xmlXPathCastBooleanToString(val->boolval);
5804
6.02k
  break;
5805
19.5k
    case XPATH_NUMBER:
5806
19.5k
  res = xmlXPathCastNumberToString(val->floatval);
5807
19.5k
  break;
5808
0
    case XPATH_USERS:
5809
#ifdef LIBXML_XPTR_LOCS_ENABLED
5810
    case XPATH_POINT:
5811
    case XPATH_RANGE:
5812
    case XPATH_LOCATIONSET:
5813
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5814
0
  TODO;
5815
0
  break;
5816
371k
    }
5817
371k
    xmlXPathFreeObject(val);
5818
371k
    if (res == NULL)
5819
205
  return(xmlXPathNewCString(""));
5820
371k
    return(xmlXPathWrapString(res));
5821
371k
}
5822
5823
/**
5824
 * xmlXPathCastBooleanToNumber:
5825
 * @val:  a boolean
5826
 *
5827
 * Converts a boolean to its number value
5828
 *
5829
 * Returns the number value
5830
 */
5831
double
5832
294k
xmlXPathCastBooleanToNumber(int val) {
5833
294k
    if (val)
5834
12.5k
  return(1.0);
5835
281k
    return(0.0);
5836
294k
}
5837
5838
/**
5839
 * xmlXPathCastStringToNumber:
5840
 * @val:  a string
5841
 *
5842
 * Converts a string to its number value
5843
 *
5844
 * Returns the number value
5845
 */
5846
double
5847
3.73M
xmlXPathCastStringToNumber(const xmlChar * val) {
5848
3.73M
    return(xmlXPathStringEvalNumber(val));
5849
3.73M
}
5850
5851
/**
5852
 * xmlXPathCastNodeToNumber:
5853
 * @node:  a node
5854
 *
5855
 * Converts a node to its number value
5856
 *
5857
 * Returns the number value
5858
 */
5859
double
5860
81.2k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861
81.2k
    xmlChar *strval;
5862
81.2k
    double ret;
5863
5864
81.2k
    if (node == NULL)
5865
0
  return(xmlXPathNAN);
5866
81.2k
    strval = xmlXPathCastNodeToString(node);
5867
81.2k
    if (strval == NULL)
5868
281
  return(xmlXPathNAN);
5869
80.9k
    ret = xmlXPathCastStringToNumber(strval);
5870
80.9k
    xmlFree(strval);
5871
5872
80.9k
    return(ret);
5873
81.2k
}
5874
5875
/**
5876
 * xmlXPathCastNodeSetToNumber:
5877
 * @ns:  a node-set
5878
 *
5879
 * Converts a node-set to its number value
5880
 *
5881
 * Returns the number value
5882
 */
5883
double
5884
1.45M
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885
1.45M
    xmlChar *str;
5886
1.45M
    double ret;
5887
5888
1.45M
    if (ns == NULL)
5889
48.2k
  return(xmlXPathNAN);
5890
1.40M
    str = xmlXPathCastNodeSetToString(ns);
5891
1.40M
    ret = xmlXPathCastStringToNumber(str);
5892
1.40M
    xmlFree(str);
5893
1.40M
    return(ret);
5894
1.45M
}
5895
5896
/**
5897
 * xmlXPathCastToNumber:
5898
 * @val:  an XPath object
5899
 *
5900
 * Converts an XPath object to its number value
5901
 *
5902
 * Returns the number value
5903
 */
5904
double
5905
4.56M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906
4.56M
    double ret = 0.0;
5907
5908
4.56M
    if (val == NULL)
5909
0
  return(xmlXPathNAN);
5910
4.56M
    switch (val->type) {
5911
0
    case XPATH_UNDEFINED:
5912
#ifdef DEBUG_EXPR
5913
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5914
#endif
5915
0
  ret = xmlXPathNAN;
5916
0
  break;
5917
1.45M
    case XPATH_NODESET:
5918
1.45M
    case XPATH_XSLT_TREE:
5919
1.45M
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920
1.45M
  break;
5921
2.24M
    case XPATH_STRING:
5922
2.24M
  ret = xmlXPathCastStringToNumber(val->stringval);
5923
2.24M
  break;
5924
568k
    case XPATH_NUMBER:
5925
568k
  ret = val->floatval;
5926
568k
  break;
5927
294k
    case XPATH_BOOLEAN:
5928
294k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5929
294k
  break;
5930
96
    case XPATH_USERS:
5931
#ifdef LIBXML_XPTR_LOCS_ENABLED
5932
    case XPATH_POINT:
5933
    case XPATH_RANGE:
5934
    case XPATH_LOCATIONSET:
5935
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5936
96
  TODO;
5937
96
  ret = xmlXPathNAN;
5938
96
  break;
5939
4.56M
    }
5940
4.56M
    return(ret);
5941
4.56M
}
5942
5943
/**
5944
 * xmlXPathConvertNumber:
5945
 * @val:  an XPath object
5946
 *
5947
 * Converts an existing object to its number() equivalent
5948
 *
5949
 * Returns the new object, the old one is freed (or the operation
5950
 *         is done directly on @val)
5951
 */
5952
xmlXPathObjectPtr
5953
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954
0
    xmlXPathObjectPtr ret;
5955
5956
0
    if (val == NULL)
5957
0
  return(xmlXPathNewFloat(0.0));
5958
0
    if (val->type == XPATH_NUMBER)
5959
0
  return(val);
5960
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961
0
    xmlXPathFreeObject(val);
5962
0
    return(ret);
5963
0
}
5964
5965
/**
5966
 * xmlXPathCastNumberToBoolean:
5967
 * @val:  a number
5968
 *
5969
 * Converts a number to its boolean value
5970
 *
5971
 * Returns the boolean value
5972
 */
5973
int
5974
239k
xmlXPathCastNumberToBoolean (double val) {
5975
239k
     if (xmlXPathIsNaN(val) || (val == 0.0))
5976
164k
   return(0);
5977
74.8k
     return(1);
5978
239k
}
5979
5980
/**
5981
 * xmlXPathCastStringToBoolean:
5982
 * @val:  a string
5983
 *
5984
 * Converts a string to its boolean value
5985
 *
5986
 * Returns the boolean value
5987
 */
5988
int
5989
2.56k
xmlXPathCastStringToBoolean (const xmlChar *val) {
5990
2.56k
    if ((val == NULL) || (xmlStrlen(val) == 0))
5991
1.82k
  return(0);
5992
739
    return(1);
5993
2.56k
}
5994
5995
/**
5996
 * xmlXPathCastNodeSetToBoolean:
5997
 * @ns:  a node-set
5998
 *
5999
 * Converts a node-set to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
207k
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005
207k
    if ((ns == NULL) || (ns->nodeNr == 0))
6006
194k
  return(0);
6007
12.2k
    return(1);
6008
207k
}
6009
6010
/**
6011
 * xmlXPathCastToBoolean:
6012
 * @val:  an XPath object
6013
 *
6014
 * Converts an XPath object to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
268k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020
268k
    int ret = 0;
6021
6022
268k
    if (val == NULL)
6023
0
  return(0);
6024
268k
    switch (val->type) {
6025
0
    case XPATH_UNDEFINED:
6026
#ifdef DEBUG_EXPR
6027
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028
#endif
6029
0
  ret = 0;
6030
0
  break;
6031
206k
    case XPATH_NODESET:
6032
207k
    case XPATH_XSLT_TREE:
6033
207k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034
207k
  break;
6035
2.56k
    case XPATH_STRING:
6036
2.56k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6037
2.56k
  break;
6038
59.3k
    case XPATH_NUMBER:
6039
59.3k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040
59.3k
  break;
6041
0
    case XPATH_BOOLEAN:
6042
0
  ret = val->boolval;
6043
0
  break;
6044
0
    case XPATH_USERS:
6045
#ifdef LIBXML_XPTR_LOCS_ENABLED
6046
    case XPATH_POINT:
6047
    case XPATH_RANGE:
6048
    case XPATH_LOCATIONSET:
6049
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6050
0
  TODO;
6051
0
  ret = 0;
6052
0
  break;
6053
268k
    }
6054
268k
    return(ret);
6055
268k
}
6056
6057
6058
/**
6059
 * xmlXPathConvertBoolean:
6060
 * @val:  an XPath object
6061
 *
6062
 * Converts an existing object to its boolean() equivalent
6063
 *
6064
 * Returns the new object, the old one is freed (or the operation
6065
 *         is done directly on @val)
6066
 */
6067
xmlXPathObjectPtr
6068
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6069
0
    xmlXPathObjectPtr ret;
6070
6071
0
    if (val == NULL)
6072
0
  return(xmlXPathNewBoolean(0));
6073
0
    if (val->type == XPATH_BOOLEAN)
6074
0
  return(val);
6075
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6076
0
    xmlXPathFreeObject(val);
6077
0
    return(ret);
6078
0
}
6079
6080
/************************************************************************
6081
 *                  *
6082
 *    Routines to handle XPath contexts     *
6083
 *                  *
6084
 ************************************************************************/
6085
6086
/**
6087
 * xmlXPathNewContext:
6088
 * @doc:  the XML document
6089
 *
6090
 * Create a new xmlXPathContext
6091
 *
6092
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6093
 */
6094
xmlXPathContextPtr
6095
60.0k
xmlXPathNewContext(xmlDocPtr doc) {
6096
60.0k
    xmlXPathContextPtr ret;
6097
6098
60.0k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099
60.0k
    if (ret == NULL) {
6100
19
        xmlXPathErrMemory(NULL, "creating context\n");
6101
19
  return(NULL);
6102
19
    }
6103
60.0k
    memset(ret, 0 , sizeof(xmlXPathContext));
6104
60.0k
    ret->doc = doc;
6105
60.0k
    ret->node = NULL;
6106
6107
60.0k
    ret->varHash = NULL;
6108
6109
60.0k
    ret->nb_types = 0;
6110
60.0k
    ret->max_types = 0;
6111
60.0k
    ret->types = NULL;
6112
6113
60.0k
    ret->funcHash = xmlHashCreate(0);
6114
6115
60.0k
    ret->nb_axis = 0;
6116
60.0k
    ret->max_axis = 0;
6117
60.0k
    ret->axis = NULL;
6118
6119
60.0k
    ret->nsHash = NULL;
6120
60.0k
    ret->user = NULL;
6121
6122
60.0k
    ret->contextSize = -1;
6123
60.0k
    ret->proximityPosition = -1;
6124
6125
#ifdef XP_DEFAULT_CACHE_ON
6126
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6127
  xmlXPathFreeContext(ret);
6128
  return(NULL);
6129
    }
6130
#endif
6131
6132
60.0k
    xmlXPathRegisterAllFunctions(ret);
6133
6134
60.0k
    return(ret);
6135
60.0k
}
6136
6137
/**
6138
 * xmlXPathFreeContext:
6139
 * @ctxt:  the context to free
6140
 *
6141
 * Free up an xmlXPathContext
6142
 */
6143
void
6144
60.0k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145
60.0k
    if (ctxt == NULL) return;
6146
6147
60.0k
    if (ctxt->cache != NULL)
6148
37.6k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149
60.0k
    xmlXPathRegisteredNsCleanup(ctxt);
6150
60.0k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6151
60.0k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6152
60.0k
    xmlResetError(&ctxt->lastError);
6153
60.0k
    xmlFree(ctxt);
6154
60.0k
}
6155
6156
/************************************************************************
6157
 *                  *
6158
 *    Routines to handle XPath parser contexts    *
6159
 *                  *
6160
 ************************************************************************/
6161
6162
#define CHECK_CTXT(ctxt)            \
6163
40.8k
    if (ctxt == NULL) {           \
6164
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6165
0
    NULL, NULL, XML_FROM_XPATH,       \
6166
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6167
0
    __FILE__, __LINE__,         \
6168
0
    NULL, NULL, NULL, 0, 0,         \
6169
0
    "NULL context pointer\n");        \
6170
0
  return(NULL);             \
6171
0
    }                  \
6172
6173
#define CHECK_CTXT_NEG(ctxt)            \
6174
5.02M
    if (ctxt == NULL) {           \
6175
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6176
0
    NULL, NULL, XML_FROM_XPATH,       \
6177
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6178
0
    __FILE__, __LINE__,         \
6179
0
    NULL, NULL, NULL, 0, 0,         \
6180
0
    "NULL context pointer\n");        \
6181
0
  return(-1);             \
6182
0
    }                  \
6183
6184
6185
#define CHECK_CONTEXT(ctxt)           \
6186
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6187
        (ctxt->doc->children == NULL)) {        \
6188
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6189
  return(NULL);             \
6190
    }
6191
6192
6193
/**
6194
 * xmlXPathNewParserContext:
6195
 * @str:  the XPath expression
6196
 * @ctxt:  the XPath context
6197
 *
6198
 * Create a new xmlXPathParserContext
6199
 *
6200
 * Returns the xmlXPathParserContext just allocated.
6201
 */
6202
xmlXPathParserContextPtr
6203
1.12M
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204
1.12M
    xmlXPathParserContextPtr ret;
6205
6206
1.12M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207
1.12M
    if (ret == NULL) {
6208
3.17k
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6209
3.17k
  return(NULL);
6210
3.17k
    }
6211
1.12M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6212
1.12M
    ret->cur = ret->base = str;
6213
1.12M
    ret->context = ctxt;
6214
6215
1.12M
    ret->comp = xmlXPathNewCompExpr();
6216
1.12M
    if (ret->comp == NULL) {
6217
166
  xmlFree(ret->valueTab);
6218
166
  xmlFree(ret);
6219
166
  return(NULL);
6220
166
    }
6221
1.12M
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222
97.1k
        ret->comp->dict = ctxt->dict;
6223
97.1k
  xmlDictReference(ret->comp->dict);
6224
97.1k
    }
6225
6226
1.12M
    return(ret);
6227
1.12M
}
6228
6229
/**
6230
 * xmlXPathCompParserContext:
6231
 * @comp:  the XPath compiled expression
6232
 * @ctxt:  the XPath context
6233
 *
6234
 * Create a new xmlXPathParserContext when processing a compiled expression
6235
 *
6236
 * Returns the xmlXPathParserContext just allocated.
6237
 */
6238
static xmlXPathParserContextPtr
6239
5.01M
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240
5.01M
    xmlXPathParserContextPtr ret;
6241
6242
5.01M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243
5.01M
    if (ret == NULL) {
6244
44.3k
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245
44.3k
  return(NULL);
6246
44.3k
    }
6247
4.97M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6248
6249
    /* Allocate the value stack */
6250
4.97M
    ret->valueTab = (xmlXPathObjectPtr *)
6251
4.97M
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252
4.97M
    if (ret->valueTab == NULL) {
6253
266
  xmlFree(ret);
6254
266
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255
266
  return(NULL);
6256
266
    }
6257
4.97M
    ret->valueNr = 0;
6258
4.97M
    ret->valueMax = 10;
6259
4.97M
    ret->value = NULL;
6260
6261
4.97M
    ret->context = ctxt;
6262
4.97M
    ret->comp = comp;
6263
6264
4.97M
    return(ret);
6265
4.97M
}
6266
6267
/**
6268
 * xmlXPathFreeParserContext:
6269
 * @ctxt:  the context to free
6270
 *
6271
 * Free up an xmlXPathParserContext
6272
 */
6273
void
6274
6.09M
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275
6.09M
    int i;
6276
6277
6.09M
    if (ctxt->valueTab != NULL) {
6278
5.53M
        for (i = 0; i < ctxt->valueNr; i++) {
6279
518k
            if (ctxt->context)
6280
518k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281
0
            else
6282
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6283
518k
        }
6284
5.01M
        xmlFree(ctxt->valueTab);
6285
5.01M
    }
6286
6.09M
    if (ctxt->comp != NULL) {
6287
749k
#ifdef XPATH_STREAMING
6288
749k
  if (ctxt->comp->stream != NULL) {
6289
3.59k
      xmlFreePatternList(ctxt->comp->stream);
6290
3.59k
      ctxt->comp->stream = NULL;
6291
3.59k
  }
6292
749k
#endif
6293
749k
  xmlXPathFreeCompExpr(ctxt->comp);
6294
749k
    }
6295
6.09M
    xmlFree(ctxt);
6296
6.09M
}
6297
6298
/************************************************************************
6299
 *                  *
6300
 *    The implicit core function library      *
6301
 *                  *
6302
 ************************************************************************/
6303
6304
/**
6305
 * xmlXPathNodeValHash:
6306
 * @node:  a node pointer
6307
 *
6308
 * Function computing the beginning of the string value of the node,
6309
 * used to speed up comparisons
6310
 *
6311
 * Returns an int usable as a hash
6312
 */
6313
static unsigned int
6314
170k
xmlXPathNodeValHash(xmlNodePtr node) {
6315
170k
    int len = 2;
6316
170k
    const xmlChar * string = NULL;
6317
170k
    xmlNodePtr tmp = NULL;
6318
170k
    unsigned int ret = 0;
6319
6320
170k
    if (node == NULL)
6321
0
  return(0);
6322
6323
170k
    if (node->type == XML_DOCUMENT_NODE) {
6324
24.2k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325
24.2k
  if (tmp == NULL)
6326
8.73k
      node = node->children;
6327
15.4k
  else
6328
15.4k
      node = tmp;
6329
6330
24.2k
  if (node == NULL)
6331
785
      return(0);
6332
24.2k
    }
6333
6334
169k
    switch (node->type) {
6335
1.50k
  case XML_COMMENT_NODE:
6336
1.69k
  case XML_PI_NODE:
6337
1.69k
  case XML_CDATA_SECTION_NODE:
6338
31.4k
  case XML_TEXT_NODE:
6339
31.4k
      string = node->content;
6340
31.4k
      if (string == NULL)
6341
192
    return(0);
6342
31.2k
      if (string[0] == 0)
6343
0
    return(0);
6344
31.2k
      return(string[0] + (string[1] << 8));
6345
35.0k
  case XML_NAMESPACE_DECL:
6346
35.0k
      string = ((xmlNsPtr)node)->href;
6347
35.0k
      if (string == NULL)
6348
1
    return(0);
6349
35.0k
      if (string[0] == 0)
6350
618
    return(0);
6351
34.4k
      return(string[0] + (string[1] << 8));
6352
15.1k
  case XML_ATTRIBUTE_NODE:
6353
15.1k
      tmp = ((xmlAttrPtr) node)->children;
6354
15.1k
      break;
6355
87.7k
  case XML_ELEMENT_NODE:
6356
87.7k
      tmp = node->children;
6357
87.7k
      break;
6358
0
  default:
6359
0
      return(0);
6360
169k
    }
6361
146k
    while (tmp != NULL) {
6362
109k
  switch (tmp->type) {
6363
0
      case XML_CDATA_SECTION_NODE:
6364
72.0k
      case XML_TEXT_NODE:
6365
72.0k
    string = tmp->content;
6366
72.0k
    break;
6367
37.7k
      default:
6368
37.7k
                string = NULL;
6369
37.7k
    break;
6370
109k
  }
6371
109k
  if ((string != NULL) && (string[0] != 0)) {
6372
71.9k
      if (len == 1) {
6373
3.52k
    return(ret + (string[0] << 8));
6374
3.52k
      }
6375
68.4k
      if (string[1] == 0) {
6376
6.21k
    len = 1;
6377
6.21k
    ret = string[0];
6378
62.2k
      } else {
6379
62.2k
    return(string[0] + (string[1] << 8));
6380
62.2k
      }
6381
68.4k
  }
6382
  /*
6383
   * Skip to next node
6384
   */
6385
44.0k
        if ((tmp->children != NULL) &&
6386
44.0k
            (tmp->type != XML_DTD_NODE) &&
6387
44.0k
            (tmp->type != XML_ENTITY_REF_NODE) &&
6388
44.0k
            (tmp->children->type != XML_ENTITY_DECL)) {
6389
27.3k
            tmp = tmp->children;
6390
27.3k
            continue;
6391
27.3k
  }
6392
16.7k
  if (tmp == node)
6393
0
      break;
6394
6395
16.7k
  if (tmp->next != NULL) {
6396
10.7k
      tmp = tmp->next;
6397
10.7k
      continue;
6398
10.7k
  }
6399
6400
9.34k
  do {
6401
9.34k
      tmp = tmp->parent;
6402
9.34k
      if (tmp == NULL)
6403
0
    break;
6404
9.34k
      if (tmp == node) {
6405
3.20k
    tmp = NULL;
6406
3.20k
    break;
6407
3.20k
      }
6408
6.14k
      if (tmp->next != NULL) {
6409
2.80k
    tmp = tmp->next;
6410
2.80k
    break;
6411
2.80k
      }
6412
6.14k
  } while (tmp != NULL);
6413
6.01k
    }
6414
37.1k
    return(ret);
6415
102k
}
6416
6417
/**
6418
 * xmlXPathStringHash:
6419
 * @string:  a string
6420
 *
6421
 * Function computing the beginning of the string value of the node,
6422
 * used to speed up comparisons
6423
 *
6424
 * Returns an int usable as a hash
6425
 */
6426
static unsigned int
6427
10.7k
xmlXPathStringHash(const xmlChar * string) {
6428
10.7k
    if (string == NULL)
6429
0
  return(0);
6430
10.7k
    if (string[0] == 0)
6431
2.16k
  return(0);
6432
8.58k
    return(string[0] + (string[1] << 8));
6433
10.7k
}
6434
6435
/**
6436
 * xmlXPathCompareNodeSetFloat:
6437
 * @ctxt:  the XPath Parser context
6438
 * @inf:  less than (1) or greater than (0)
6439
 * @strict:  is the comparison strict
6440
 * @arg:  the node set
6441
 * @f:  the value
6442
 *
6443
 * Implement the compare operation between a nodeset and a number
6444
 *     @ns < @val    (1, 1, ...
6445
 *     @ns <= @val   (1, 0, ...
6446
 *     @ns > @val    (0, 1, ...
6447
 *     @ns >= @val   (0, 0, ...
6448
 *
6449
 * If one object to be compared is a node-set and the other is a number,
6450
 * then the comparison will be true if and only if there is a node in the
6451
 * node-set such that the result of performing the comparison on the number
6452
 * to be compared and on the result of converting the string-value of that
6453
 * node to a number using the number function is true.
6454
 *
6455
 * Returns 0 or 1 depending on the results of the test.
6456
 */
6457
static int
6458
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6459
164k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6460
164k
    int i, ret = 0;
6461
164k
    xmlNodeSetPtr ns;
6462
164k
    xmlChar *str2;
6463
6464
164k
    if ((f == NULL) || (arg == NULL) ||
6465
164k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6466
0
  xmlXPathReleaseObject(ctxt->context, arg);
6467
0
  xmlXPathReleaseObject(ctxt->context, f);
6468
0
        return(0);
6469
0
    }
6470
164k
    ns = arg->nodesetval;
6471
164k
    if (ns != NULL) {
6472
221k
  for (i = 0;i < ns->nodeNr;i++) {
6473
77.5k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6474
77.5k
       if (str2 != NULL) {
6475
76.5k
     valuePush(ctxt,
6476
76.5k
         xmlXPathCacheNewString(ctxt->context, str2));
6477
76.5k
     xmlFree(str2);
6478
76.5k
     xmlXPathNumberFunction(ctxt, 1);
6479
76.5k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6480
76.5k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6481
76.5k
     if (ret)
6482
926
         break;
6483
76.5k
       }
6484
77.5k
  }
6485
144k
    }
6486
164k
    xmlXPathReleaseObject(ctxt->context, arg);
6487
164k
    xmlXPathReleaseObject(ctxt->context, f);
6488
164k
    return(ret);
6489
164k
}
6490
6491
/**
6492
 * xmlXPathCompareNodeSetString:
6493
 * @ctxt:  the XPath Parser context
6494
 * @inf:  less than (1) or greater than (0)
6495
 * @strict:  is the comparison strict
6496
 * @arg:  the node set
6497
 * @s:  the value
6498
 *
6499
 * Implement the compare operation between a nodeset and a string
6500
 *     @ns < @val    (1, 1, ...
6501
 *     @ns <= @val   (1, 0, ...
6502
 *     @ns > @val    (0, 1, ...
6503
 *     @ns >= @val   (0, 0, ...
6504
 *
6505
 * If one object to be compared is a node-set and the other is a string,
6506
 * then the comparison will be true if and only if there is a node in
6507
 * the node-set such that the result of performing the comparison on the
6508
 * string-value of the node and the other string is true.
6509
 *
6510
 * Returns 0 or 1 depending on the results of the test.
6511
 */
6512
static int
6513
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6514
8.03k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6515
8.03k
    int i, ret = 0;
6516
8.03k
    xmlNodeSetPtr ns;
6517
8.03k
    xmlChar *str2;
6518
6519
8.03k
    if ((s == NULL) || (arg == NULL) ||
6520
8.03k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6521
0
  xmlXPathReleaseObject(ctxt->context, arg);
6522
0
  xmlXPathReleaseObject(ctxt->context, s);
6523
0
        return(0);
6524
0
    }
6525
8.03k
    ns = arg->nodesetval;
6526
8.03k
    if (ns != NULL) {
6527
10.6k
  for (i = 0;i < ns->nodeNr;i++) {
6528
3.60k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6529
3.60k
       if (str2 != NULL) {
6530
3.56k
     valuePush(ctxt,
6531
3.56k
         xmlXPathCacheNewString(ctxt->context, str2));
6532
3.56k
     xmlFree(str2);
6533
3.56k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6534
3.56k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6535
3.56k
     if (ret)
6536
0
         break;
6537
3.56k
       }
6538
3.60k
  }
6539
7.05k
    }
6540
8.03k
    xmlXPathReleaseObject(ctxt->context, arg);
6541
8.03k
    xmlXPathReleaseObject(ctxt->context, s);
6542
8.03k
    return(ret);
6543
8.03k
}
6544
6545
/**
6546
 * xmlXPathCompareNodeSets:
6547
 * @inf:  less than (1) or greater than (0)
6548
 * @strict:  is the comparison strict
6549
 * @arg1:  the first node set object
6550
 * @arg2:  the second node set object
6551
 *
6552
 * Implement the compare operation on nodesets:
6553
 *
6554
 * If both objects to be compared are node-sets, then the comparison
6555
 * will be true if and only if there is a node in the first node-set
6556
 * and a node in the second node-set such that the result of performing
6557
 * the comparison on the string-values of the two nodes is true.
6558
 * ....
6559
 * When neither object to be compared is a node-set and the operator
6560
 * is <=, <, >= or >, then the objects are compared by converting both
6561
 * objects to numbers and comparing the numbers according to IEEE 754.
6562
 * ....
6563
 * The number function converts its argument to a number as follows:
6564
 *  - a string that consists of optional whitespace followed by an
6565
 *    optional minus sign followed by a Number followed by whitespace
6566
 *    is converted to the IEEE 754 number that is nearest (according
6567
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6568
 *    represented by the string; any other string is converted to NaN
6569
 *
6570
 * Conclusion all nodes need to be converted first to their string value
6571
 * and then the comparison must be done when possible
6572
 */
6573
static int
6574
xmlXPathCompareNodeSets(int inf, int strict,
6575
284k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6576
284k
    int i, j, init = 0;
6577
284k
    double val1;
6578
284k
    double *values2;
6579
284k
    int ret = 0;
6580
284k
    xmlNodeSetPtr ns1;
6581
284k
    xmlNodeSetPtr ns2;
6582
6583
284k
    if ((arg1 == NULL) ||
6584
284k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6585
0
  xmlXPathFreeObject(arg2);
6586
0
        return(0);
6587
0
    }
6588
284k
    if ((arg2 == NULL) ||
6589
284k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6590
0
  xmlXPathFreeObject(arg1);
6591
0
  xmlXPathFreeObject(arg2);
6592
0
        return(0);
6593
0
    }
6594
6595
284k
    ns1 = arg1->nodesetval;
6596
284k
    ns2 = arg2->nodesetval;
6597
6598
284k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6599
268k
  xmlXPathFreeObject(arg1);
6600
268k
  xmlXPathFreeObject(arg2);
6601
268k
  return(0);
6602
268k
    }
6603
16.7k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6604
7.71k
  xmlXPathFreeObject(arg1);
6605
7.71k
  xmlXPathFreeObject(arg2);
6606
7.71k
  return(0);
6607
7.71k
    }
6608
6609
9.04k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6610
9.04k
    if (values2 == NULL) {
6611
        /* TODO: Propagate memory error. */
6612
76
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6613
76
  xmlXPathFreeObject(arg1);
6614
76
  xmlXPathFreeObject(arg2);
6615
76
  return(0);
6616
76
    }
6617
18.7k
    for (i = 0;i < ns1->nodeNr;i++) {
6618
10.9k
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6619
10.9k
  if (xmlXPathIsNaN(val1))
6620
9.46k
      continue;
6621
2.83k
  for (j = 0;j < ns2->nodeNr;j++) {
6622
2.51k
      if (init == 0) {
6623
1.96k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6624
1.96k
      }
6625
2.51k
      if (xmlXPathIsNaN(values2[j]))
6626
857
    continue;
6627
1.65k
      if (inf && strict)
6628
0
    ret = (val1 < values2[j]);
6629
1.65k
      else if (inf && !strict)
6630
0
    ret = (val1 <= values2[j]);
6631
1.65k
      else if (!inf && strict)
6632
540
    ret = (val1 > values2[j]);
6633
1.11k
      else if (!inf && !strict)
6634
1.11k
    ret = (val1 >= values2[j]);
6635
1.65k
      if (ret)
6636
1.19k
    break;
6637
1.65k
  }
6638
1.51k
  if (ret)
6639
1.19k
      break;
6640
318
  init = 1;
6641
318
    }
6642
8.97k
    xmlFree(values2);
6643
8.97k
    xmlXPathFreeObject(arg1);
6644
8.97k
    xmlXPathFreeObject(arg2);
6645
8.97k
    return(ret);
6646
9.04k
}
6647
6648
/**
6649
 * xmlXPathCompareNodeSetValue:
6650
 * @ctxt:  the XPath Parser context
6651
 * @inf:  less than (1) or greater than (0)
6652
 * @strict:  is the comparison strict
6653
 * @arg:  the node set
6654
 * @val:  the value
6655
 *
6656
 * Implement the compare operation between a nodeset and a value
6657
 *     @ns < @val    (1, 1, ...
6658
 *     @ns <= @val   (1, 0, ...
6659
 *     @ns > @val    (0, 1, ...
6660
 *     @ns >= @val   (0, 0, ...
6661
 *
6662
 * If one object to be compared is a node-set and the other is a boolean,
6663
 * then the comparison will be true if and only if the result of performing
6664
 * the comparison on the boolean and on the result of converting
6665
 * the node-set to a boolean using the boolean function is true.
6666
 *
6667
 * Returns 0 or 1 depending on the results of the test.
6668
 */
6669
static int
6670
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6671
313k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6672
313k
    if ((val == NULL) || (arg == NULL) ||
6673
313k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674
0
        return(0);
6675
6676
313k
    switch(val->type) {
6677
164k
        case XPATH_NUMBER:
6678
164k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6679
0
        case XPATH_NODESET:
6680
0
        case XPATH_XSLT_TREE:
6681
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6682
8.03k
        case XPATH_STRING:
6683
8.03k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6684
140k
        case XPATH_BOOLEAN:
6685
140k
      valuePush(ctxt, arg);
6686
140k
      xmlXPathBooleanFunction(ctxt, 1);
6687
140k
      valuePush(ctxt, val);
6688
140k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6689
0
  default:
6690
0
            xmlGenericError(xmlGenericErrorContext,
6691
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6692
0
                    "and object of type %d\n",
6693
0
                    val->type);
6694
0
            xmlXPathReleaseObject(ctxt->context, arg);
6695
0
            xmlXPathReleaseObject(ctxt->context, val);
6696
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6697
313k
    }
6698
0
    return(0);
6699
313k
}
6700
6701
/**
6702
 * xmlXPathEqualNodeSetString:
6703
 * @arg:  the nodeset object argument
6704
 * @str:  the string to compare to.
6705
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6706
 *
6707
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6708
 * If one object to be compared is a node-set and the other is a string,
6709
 * then the comparison will be true if and only if there is a node in
6710
 * the node-set such that the result of performing the comparison on the
6711
 * string-value of the node and the other string is true.
6712
 *
6713
 * Returns 0 or 1 depending on the results of the test.
6714
 */
6715
static int
6716
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6717
26.3k
{
6718
26.3k
    int i;
6719
26.3k
    xmlNodeSetPtr ns;
6720
26.3k
    xmlChar *str2;
6721
26.3k
    unsigned int hash;
6722
6723
26.3k
    if ((str == NULL) || (arg == NULL) ||
6724
26.3k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6725
0
        return (0);
6726
26.3k
    ns = arg->nodesetval;
6727
    /*
6728
     * A NULL nodeset compared with a string is always false
6729
     * (since there is no node equal, and no node not equal)
6730
     */
6731
26.3k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6732
15.6k
        return (0);
6733
10.7k
    hash = xmlXPathStringHash(str);
6734
72.9k
    for (i = 0; i < ns->nodeNr; i++) {
6735
66.6k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6736
18.1k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6737
18.1k
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6738
2.51k
                xmlFree(str2);
6739
2.51k
    if (neq)
6740
577
        continue;
6741
1.94k
                return (1);
6742
15.6k
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6743
6
    if (neq)
6744
0
        continue;
6745
6
                return (1);
6746
15.6k
            } else if (neq) {
6747
164
    if (str2 != NULL)
6748
162
        xmlFree(str2);
6749
164
    return (1);
6750
164
      }
6751
15.4k
            if (str2 != NULL)
6752
15.0k
                xmlFree(str2);
6753
48.5k
        } else if (neq)
6754
2.31k
      return (1);
6755
66.6k
    }
6756
6.32k
    return (0);
6757
10.7k
}
6758
6759
/**
6760
 * xmlXPathEqualNodeSetFloat:
6761
 * @arg:  the nodeset object argument
6762
 * @f:  the float to compare to
6763
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6764
 *
6765
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6766
 * If one object to be compared is a node-set and the other is a number,
6767
 * then the comparison will be true if and only if there is a node in
6768
 * the node-set such that the result of performing the comparison on the
6769
 * number to be compared and on the result of converting the string-value
6770
 * of that node to a number using the number function is true.
6771
 *
6772
 * Returns 0 or 1 depending on the results of the test.
6773
 */
6774
static int
6775
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6776
96.2k
    xmlXPathObjectPtr arg, double f, int neq) {
6777
96.2k
  int i, ret=0;
6778
96.2k
  xmlNodeSetPtr ns;
6779
96.2k
  xmlChar *str2;
6780
96.2k
  xmlXPathObjectPtr val;
6781
96.2k
  double v;
6782
6783
96.2k
    if ((arg == NULL) ||
6784
96.2k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6785
0
        return(0);
6786
6787
96.2k
    ns = arg->nodesetval;
6788
96.2k
    if (ns != NULL) {
6789
2.00M
  for (i=0;i<ns->nodeNr;i++) {
6790
1.91M
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6791
1.91M
      if (str2 != NULL) {
6792
1.91M
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6793
1.91M
    xmlFree(str2);
6794
1.91M
    xmlXPathNumberFunction(ctxt, 1);
6795
1.91M
                CHECK_ERROR0;
6796
1.91M
    val = valuePop(ctxt);
6797
1.91M
    v = val->floatval;
6798
1.91M
    xmlXPathReleaseObject(ctxt->context, val);
6799
1.91M
    if (!xmlXPathIsNaN(v)) {
6800
4.08k
        if ((!neq) && (v==f)) {
6801
1.23k
      ret = 1;
6802
1.23k
      break;
6803
2.85k
        } else if ((neq) && (v!=f)) {
6804
277
      ret = 1;
6805
277
      break;
6806
277
        }
6807
1.90M
    } else { /* NaN is unequal to any value */
6808
1.90M
        if (neq)
6809
84.3k
      ret = 1;
6810
1.90M
    }
6811
1.91M
      }
6812
1.91M
  }
6813
92.1k
    }
6814
6815
96.2k
    return(ret);
6816
96.2k
}
6817
6818
6819
/**
6820
 * xmlXPathEqualNodeSets:
6821
 * @arg1:  first nodeset object argument
6822
 * @arg2:  second nodeset object argument
6823
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6824
 *
6825
 * Implement the equal / not equal operation on XPath nodesets:
6826
 * @arg1 == @arg2  or  @arg1 != @arg2
6827
 * If both objects to be compared are node-sets, then the comparison
6828
 * will be true if and only if there is a node in the first node-set and
6829
 * a node in the second node-set such that the result of performing the
6830
 * comparison on the string-values of the two nodes is true.
6831
 *
6832
 * (needless to say, this is a costly operation)
6833
 *
6834
 * Returns 0 or 1 depending on the results of the test.
6835
 */
6836
static int
6837
83.8k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6838
83.8k
    int i, j;
6839
83.8k
    unsigned int *hashs1;
6840
83.8k
    unsigned int *hashs2;
6841
83.8k
    xmlChar **values1;
6842
83.8k
    xmlChar **values2;
6843
83.8k
    int ret = 0;
6844
83.8k
    xmlNodeSetPtr ns1;
6845
83.8k
    xmlNodeSetPtr ns2;
6846
6847
83.8k
    if ((arg1 == NULL) ||
6848
83.8k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6849
0
        return(0);
6850
83.8k
    if ((arg2 == NULL) ||
6851
83.8k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6852
0
        return(0);
6853
6854
83.8k
    ns1 = arg1->nodesetval;
6855
83.8k
    ns2 = arg2->nodesetval;
6856
6857
83.8k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6858
29.6k
  return(0);
6859
54.1k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6860
18.8k
  return(0);
6861
6862
    /*
6863
     * for equal, check if there is a node pertaining to both sets
6864
     */
6865
35.3k
    if (neq == 0)
6866
77.3k
  for (i = 0;i < ns1->nodeNr;i++)
6867
120k
      for (j = 0;j < ns2->nodeNr;j++)
6868
61.6k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6869
2.09k
        return(1);
6870
6871
33.2k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6872
33.2k
    if (values1 == NULL) {
6873
        /* TODO: Propagate memory error. */
6874
302
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6875
302
  return(0);
6876
302
    }
6877
32.9k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6878
32.9k
    if (hashs1 == NULL) {
6879
        /* TODO: Propagate memory error. */
6880
6
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6881
6
  xmlFree(values1);
6882
6
  return(0);
6883
6
    }
6884
32.9k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6885
32.9k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6886
32.9k
    if (values2 == NULL) {
6887
        /* TODO: Propagate memory error. */
6888
5
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6889
5
  xmlFree(hashs1);
6890
5
  xmlFree(values1);
6891
5
  return(0);
6892
5
    }
6893
32.9k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6894
32.9k
    if (hashs2 == NULL) {
6895
        /* TODO: Propagate memory error. */
6896
7
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6897
7
  xmlFree(hashs1);
6898
7
  xmlFree(values1);
6899
7
  xmlFree(values2);
6900
7
  return(0);
6901
7
    }
6902
32.9k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6903
83.2k
    for (i = 0;i < ns1->nodeNr;i++) {
6904
70.0k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6905
121k
  for (j = 0;j < ns2->nodeNr;j++) {
6906
70.7k
      if (i == 0)
6907
33.5k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6908
70.7k
      if (hashs1[i] != hashs2[j]) {
6909
64.6k
    if (neq) {
6910
15.7k
        ret = 1;
6911
15.7k
        break;
6912
15.7k
    }
6913
64.6k
      }
6914
6.11k
      else {
6915
6.11k
    if (values1[i] == NULL)
6916
5.91k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6917
6.11k
    if (values2[j] == NULL)
6918
5.47k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6919
6.11k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6920
6.11k
    if (ret)
6921
3.91k
        break;
6922
6.11k
      }
6923
70.7k
  }
6924
70.0k
  if (ret)
6925
19.6k
      break;
6926
70.0k
    }
6927
108k
    for (i = 0;i < ns1->nodeNr;i++)
6928
75.2k
  if (values1[i] != NULL)
6929
5.89k
      xmlFree(values1[i]);
6930
86.7k
    for (j = 0;j < ns2->nodeNr;j++)
6931
53.8k
  if (values2[j] != NULL)
6932
5.45k
      xmlFree(values2[j]);
6933
32.9k
    xmlFree(values1);
6934
32.9k
    xmlFree(values2);
6935
32.9k
    xmlFree(hashs1);
6936
32.9k
    xmlFree(hashs2);
6937
32.9k
    return(ret);
6938
32.9k
}
6939
6940
static int
6941
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6942
326k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6943
326k
    int ret = 0;
6944
    /*
6945
     *At this point we are assured neither arg1 nor arg2
6946
     *is a nodeset, so we can just pick the appropriate routine.
6947
     */
6948
326k
    switch (arg1->type) {
6949
0
        case XPATH_UNDEFINED:
6950
#ifdef DEBUG_EXPR
6951
      xmlGenericError(xmlGenericErrorContext,
6952
        "Equal: undefined\n");
6953
#endif
6954
0
      break;
6955
199k
        case XPATH_BOOLEAN:
6956
199k
      switch (arg2->type) {
6957
0
          case XPATH_UNDEFINED:
6958
#ifdef DEBUG_EXPR
6959
        xmlGenericError(xmlGenericErrorContext,
6960
          "Equal: undefined\n");
6961
#endif
6962
0
        break;
6963
31.9k
    case XPATH_BOOLEAN:
6964
#ifdef DEBUG_EXPR
6965
        xmlGenericError(xmlGenericErrorContext,
6966
          "Equal: %d boolean %d \n",
6967
          arg1->boolval, arg2->boolval);
6968
#endif
6969
31.9k
        ret = (arg1->boolval == arg2->boolval);
6970
31.9k
        break;
6971
162k
    case XPATH_NUMBER:
6972
162k
        ret = (arg1->boolval ==
6973
162k
         xmlXPathCastNumberToBoolean(arg2->floatval));
6974
162k
        break;
6975
4.54k
    case XPATH_STRING:
6976
4.54k
        if ((arg2->stringval == NULL) ||
6977
4.54k
      (arg2->stringval[0] == 0)) ret = 0;
6978
3.21k
        else
6979
3.21k
      ret = 1;
6980
4.54k
        ret = (arg1->boolval == ret);
6981
4.54k
        break;
6982
10
    case XPATH_USERS:
6983
#ifdef LIBXML_XPTR_LOCS_ENABLED
6984
    case XPATH_POINT:
6985
    case XPATH_RANGE:
6986
    case XPATH_LOCATIONSET:
6987
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6988
10
        TODO
6989
10
        break;
6990
0
    case XPATH_NODESET:
6991
0
    case XPATH_XSLT_TREE:
6992
0
        break;
6993
199k
      }
6994
199k
      break;
6995
199k
        case XPATH_NUMBER:
6996
125k
      switch (arg2->type) {
6997
0
          case XPATH_UNDEFINED:
6998
#ifdef DEBUG_EXPR
6999
        xmlGenericError(xmlGenericErrorContext,
7000
          "Equal: undefined\n");
7001
#endif
7002
0
        break;
7003
17.7k
    case XPATH_BOOLEAN:
7004
17.7k
        ret = (arg2->boolval==
7005
17.7k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7006
17.7k
        break;
7007
31.9k
    case XPATH_STRING:
7008
31.9k
        valuePush(ctxt, arg2);
7009
31.9k
        xmlXPathNumberFunction(ctxt, 1);
7010
31.9k
        arg2 = valuePop(ctxt);
7011
31.9k
                    if (ctxt->error)
7012
1
                        break;
7013
                    /* Falls through. */
7014
107k
    case XPATH_NUMBER:
7015
        /* Hand check NaN and Infinity equalities */
7016
107k
        if (xmlXPathIsNaN(arg1->floatval) ||
7017
107k
          xmlXPathIsNaN(arg2->floatval)) {
7018
87.4k
            ret = 0;
7019
87.4k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020
289
            if (xmlXPathIsInf(arg2->floatval) == 1)
7021
78
          ret = 1;
7022
211
      else
7023
211
          ret = 0;
7024
19.8k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025
3.24k
      if (xmlXPathIsInf(arg2->floatval) == -1)
7026
105
          ret = 1;
7027
3.13k
      else
7028
3.13k
          ret = 0;
7029
16.6k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030
78
      if (xmlXPathIsInf(arg1->floatval) == 1)
7031
0
          ret = 1;
7032
78
      else
7033
78
          ret = 0;
7034
16.5k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035
134
      if (xmlXPathIsInf(arg1->floatval) == -1)
7036
0
          ret = 1;
7037
134
      else
7038
134
          ret = 0;
7039
16.4k
        } else {
7040
16.4k
            ret = (arg1->floatval == arg2->floatval);
7041
16.4k
        }
7042
107k
        break;
7043
21
    case XPATH_USERS:
7044
#ifdef LIBXML_XPTR_LOCS_ENABLED
7045
    case XPATH_POINT:
7046
    case XPATH_RANGE:
7047
    case XPATH_LOCATIONSET:
7048
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7049
21
        TODO
7050
21
        break;
7051
0
    case XPATH_NODESET:
7052
0
    case XPATH_XSLT_TREE:
7053
0
        break;
7054
125k
      }
7055
125k
      break;
7056
125k
        case XPATH_STRING:
7057
1.53k
      switch (arg2->type) {
7058
0
          case XPATH_UNDEFINED:
7059
#ifdef DEBUG_EXPR
7060
        xmlGenericError(xmlGenericErrorContext,
7061
          "Equal: undefined\n");
7062
#endif
7063
0
        break;
7064
277
    case XPATH_BOOLEAN:
7065
277
        if ((arg1->stringval == NULL) ||
7066
277
      (arg1->stringval[0] == 0)) ret = 0;
7067
185
        else
7068
185
      ret = 1;
7069
277
        ret = (arg2->boolval == ret);
7070
277
        break;
7071
497
    case XPATH_STRING:
7072
497
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7073
497
        break;
7074
759
    case XPATH_NUMBER:
7075
759
        valuePush(ctxt, arg1);
7076
759
        xmlXPathNumberFunction(ctxt, 1);
7077
759
        arg1 = valuePop(ctxt);
7078
759
                    if (ctxt->error)
7079
2
                        break;
7080
        /* Hand check NaN and Infinity equalities */
7081
757
        if (xmlXPathIsNaN(arg1->floatval) ||
7082
757
          xmlXPathIsNaN(arg2->floatval)) {
7083
735
            ret = 0;
7084
735
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7085
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7086
0
          ret = 1;
7087
0
      else
7088
0
          ret = 0;
7089
22
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7090
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7091
0
          ret = 1;
7092
0
      else
7093
0
          ret = 0;
7094
22
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7095
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7096
0
          ret = 1;
7097
0
      else
7098
0
          ret = 0;
7099
22
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7100
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7101
0
          ret = 1;
7102
0
      else
7103
0
          ret = 0;
7104
22
        } else {
7105
22
            ret = (arg1->floatval == arg2->floatval);
7106
22
        }
7107
757
        break;
7108
0
    case XPATH_USERS:
7109
#ifdef LIBXML_XPTR_LOCS_ENABLED
7110
    case XPATH_POINT:
7111
    case XPATH_RANGE:
7112
    case XPATH_LOCATIONSET:
7113
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7114
0
        TODO
7115
0
        break;
7116
0
    case XPATH_NODESET:
7117
0
    case XPATH_XSLT_TREE:
7118
0
        break;
7119
1.53k
      }
7120
1.53k
      break;
7121
1.53k
        case XPATH_USERS:
7122
#ifdef LIBXML_XPTR_LOCS_ENABLED
7123
  case XPATH_POINT:
7124
  case XPATH_RANGE:
7125
  case XPATH_LOCATIONSET:
7126
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7127
0
      TODO
7128
0
      break;
7129
0
  case XPATH_NODESET:
7130
0
  case XPATH_XSLT_TREE:
7131
0
      break;
7132
326k
    }
7133
326k
    xmlXPathReleaseObject(ctxt->context, arg1);
7134
326k
    xmlXPathReleaseObject(ctxt->context, arg2);
7135
326k
    return(ret);
7136
326k
}
7137
7138
/**
7139
 * xmlXPathEqualValues:
7140
 * @ctxt:  the XPath Parser context
7141
 *
7142
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7143
 *
7144
 * Returns 0 or 1 depending on the results of the test.
7145
 */
7146
int
7147
406k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7148
406k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7149
406k
    int ret = 0;
7150
7151
406k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7152
406k
    arg2 = valuePop(ctxt);
7153
406k
    arg1 = valuePop(ctxt);
7154
406k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7155
0
  if (arg1 != NULL)
7156
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7157
0
  else
7158
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7159
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7160
0
    }
7161
7162
406k
    if (arg1 == arg2) {
7163
#ifdef DEBUG_EXPR
7164
        xmlGenericError(xmlGenericErrorContext,
7165
    "Equal: by pointer\n");
7166
#endif
7167
0
  xmlXPathFreeObject(arg1);
7168
0
        return(1);
7169
0
    }
7170
7171
    /*
7172
     *If either argument is a nodeset, it's a 'special case'
7173
     */
7174
406k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7175
406k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7176
  /*
7177
   *Hack it to assure arg1 is the nodeset
7178
   */
7179
157k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7180
43.4k
    argtmp = arg2;
7181
43.4k
    arg2 = arg1;
7182
43.4k
    arg1 = argtmp;
7183
43.4k
  }
7184
157k
  switch (arg2->type) {
7185
0
      case XPATH_UNDEFINED:
7186
#ifdef DEBUG_EXPR
7187
    xmlGenericError(xmlGenericErrorContext,
7188
      "Equal: undefined\n");
7189
#endif
7190
0
    break;
7191
45.4k
      case XPATH_NODESET:
7192
55.0k
      case XPATH_XSLT_TREE:
7193
55.0k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7194
55.0k
    break;
7195
40.4k
      case XPATH_BOOLEAN:
7196
40.4k
    if ((arg1->nodesetval == NULL) ||
7197
40.4k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7198
5.52k
    else
7199
5.52k
        ret = 1;
7200
40.4k
    ret = (ret == arg2->boolval);
7201
40.4k
    break;
7202
39.3k
      case XPATH_NUMBER:
7203
39.3k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7204
39.3k
    break;
7205
22.9k
      case XPATH_STRING:
7206
22.9k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7207
22.9k
    break;
7208
1
      case XPATH_USERS:
7209
#ifdef LIBXML_XPTR_LOCS_ENABLED
7210
      case XPATH_POINT:
7211
      case XPATH_RANGE:
7212
      case XPATH_LOCATIONSET:
7213
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7214
1
    TODO
7215
1
    break;
7216
157k
  }
7217
157k
  xmlXPathReleaseObject(ctxt->context, arg1);
7218
157k
  xmlXPathReleaseObject(ctxt->context, arg2);
7219
157k
  return(ret);
7220
157k
    }
7221
7222
248k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223
406k
}
7224
7225
/**
7226
 * xmlXPathNotEqualValues:
7227
 * @ctxt:  the XPath Parser context
7228
 *
7229
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7230
 *
7231
 * Returns 0 or 1 depending on the results of the test.
7232
 */
7233
int
7234
284k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7235
284k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7236
284k
    int ret = 0;
7237
7238
284k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7239
284k
    arg2 = valuePop(ctxt);
7240
284k
    arg1 = valuePop(ctxt);
7241
284k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7242
0
  if (arg1 != NULL)
7243
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7244
0
  else
7245
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7246
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7247
0
    }
7248
7249
284k
    if (arg1 == arg2) {
7250
#ifdef DEBUG_EXPR
7251
        xmlGenericError(xmlGenericErrorContext,
7252
    "NotEqual: by pointer\n");
7253
#endif
7254
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7255
0
        return(0);
7256
0
    }
7257
7258
    /*
7259
     *If either argument is a nodeset, it's a 'special case'
7260
     */
7261
284k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7262
284k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7263
  /*
7264
   *Hack it to assure arg1 is the nodeset
7265
   */
7266
207k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7267
172k
    argtmp = arg2;
7268
172k
    arg2 = arg1;
7269
172k
    arg1 = argtmp;
7270
172k
  }
7271
207k
  switch (arg2->type) {
7272
0
      case XPATH_UNDEFINED:
7273
#ifdef DEBUG_EXPR
7274
    xmlGenericError(xmlGenericErrorContext,
7275
      "NotEqual: undefined\n");
7276
#endif
7277
0
    break;
7278
28.5k
      case XPATH_NODESET:
7279
28.7k
      case XPATH_XSLT_TREE:
7280
28.7k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7281
28.7k
    break;
7282
118k
      case XPATH_BOOLEAN:
7283
118k
    if ((arg1->nodesetval == NULL) ||
7284
118k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7285
104k
    else
7286
104k
        ret = 1;
7287
118k
    ret = (ret != arg2->boolval);
7288
118k
    break;
7289
56.8k
      case XPATH_NUMBER:
7290
56.8k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7291
56.8k
    break;
7292
3.42k
      case XPATH_STRING:
7293
3.42k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7294
3.42k
    break;
7295
0
      case XPATH_USERS:
7296
#ifdef LIBXML_XPTR_LOCS_ENABLED
7297
      case XPATH_POINT:
7298
      case XPATH_RANGE:
7299
      case XPATH_LOCATIONSET:
7300
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7301
0
    TODO
7302
0
    break;
7303
207k
  }
7304
207k
  xmlXPathReleaseObject(ctxt->context, arg1);
7305
207k
  xmlXPathReleaseObject(ctxt->context, arg2);
7306
207k
  return(ret);
7307
207k
    }
7308
7309
77.3k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7310
284k
}
7311
7312
/**
7313
 * xmlXPathCompareValues:
7314
 * @ctxt:  the XPath Parser context
7315
 * @inf:  less than (1) or greater than (0)
7316
 * @strict:  is the comparison strict
7317
 *
7318
 * Implement the compare operation on XPath objects:
7319
 *     @arg1 < @arg2    (1, 1, ...
7320
 *     @arg1 <= @arg2   (1, 0, ...
7321
 *     @arg1 > @arg2    (0, 1, ...
7322
 *     @arg1 >= @arg2   (0, 0, ...
7323
 *
7324
 * When neither object to be compared is a node-set and the operator is
7325
 * <=, <, >=, >, then the objects are compared by converted both objects
7326
 * to numbers and comparing the numbers according to IEEE 754. The <
7327
 * comparison will be true if and only if the first number is less than the
7328
 * second number. The <= comparison will be true if and only if the first
7329
 * number is less than or equal to the second number. The > comparison
7330
 * will be true if and only if the first number is greater than the second
7331
 * number. The >= comparison will be true if and only if the first number
7332
 * is greater than or equal to the second number.
7333
 *
7334
 * Returns 1 if the comparison succeeded, 0 if it failed
7335
 */
7336
int
7337
861k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7338
861k
    int ret = 0, arg1i = 0, arg2i = 0;
7339
861k
    xmlXPathObjectPtr arg1, arg2;
7340
7341
861k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7342
861k
    arg2 = valuePop(ctxt);
7343
861k
    arg1 = valuePop(ctxt);
7344
861k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7345
331
  if (arg1 != NULL)
7346
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7347
331
  else
7348
331
      xmlXPathReleaseObject(ctxt->context, arg2);
7349
331
  XP_ERROR0(XPATH_INVALID_OPERAND);
7350
0
    }
7351
7352
861k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7353
861k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7354
  /*
7355
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7356
   * are not freed from within this routine; they will be freed from the
7357
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7358
   */
7359
598k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7360
598k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7361
284k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7362
313k
  } else {
7363
313k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7364
121k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7365
121k
                                arg1, arg2);
7366
191k
      } else {
7367
191k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7368
191k
                                arg2, arg1);
7369
191k
      }
7370
313k
  }
7371
598k
  return(ret);
7372
598k
    }
7373
7374
263k
    if (arg1->type != XPATH_NUMBER) {
7375
156k
  valuePush(ctxt, arg1);
7376
156k
  xmlXPathNumberFunction(ctxt, 1);
7377
156k
  arg1 = valuePop(ctxt);
7378
156k
    }
7379
263k
    if (arg2->type != XPATH_NUMBER) {
7380
143k
  valuePush(ctxt, arg2);
7381
143k
  xmlXPathNumberFunction(ctxt, 1);
7382
143k
  arg2 = valuePop(ctxt);
7383
143k
    }
7384
263k
    if (ctxt->error)
7385
291
        goto error;
7386
    /*
7387
     * Add tests for infinity and nan
7388
     * => feedback on 3.4 for Inf and NaN
7389
     */
7390
    /* Hand check NaN and Infinity comparisons */
7391
263k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7392
91.9k
  ret=0;
7393
171k
    } else {
7394
171k
  arg1i=xmlXPathIsInf(arg1->floatval);
7395
171k
  arg2i=xmlXPathIsInf(arg2->floatval);
7396
171k
  if (inf && strict) {
7397
141k
      if ((arg1i == -1 && arg2i != -1) ||
7398
141k
    (arg2i == 1 && arg1i != 1)) {
7399
50
    ret = 1;
7400
141k
      } else if (arg1i == 0 && arg2i == 0) {
7401
140k
    ret = (arg1->floatval < arg2->floatval);
7402
140k
      } else {
7403
900
    ret = 0;
7404
900
      }
7405
141k
  }
7406
29.7k
  else if (inf && !strict) {
7407
403
      if (arg1i == -1 || arg2i == 1) {
7408
45
    ret = 1;
7409
358
      } else if (arg1i == 0 && arg2i == 0) {
7410
319
    ret = (arg1->floatval <= arg2->floatval);
7411
319
      } else {
7412
39
    ret = 0;
7413
39
      }
7414
403
  }
7415
29.3k
  else if (!inf && strict) {
7416
21.0k
      if ((arg1i == 1 && arg2i != 1) ||
7417
21.0k
    (arg2i == -1 && arg1i != -1)) {
7418
411
    ret = 1;
7419
20.6k
      } else if (arg1i == 0 && arg2i == 0) {
7420
17.5k
    ret = (arg1->floatval > arg2->floatval);
7421
17.5k
      } else {
7422
3.11k
    ret = 0;
7423
3.11k
      }
7424
21.0k
  }
7425
8.28k
  else if (!inf && !strict) {
7426
8.28k
      if (arg1i == 1 || arg2i == -1) {
7427
4.10k
    ret = 1;
7428
4.18k
      } else if (arg1i == 0 && arg2i == 0) {
7429
3.82k
    ret = (arg1->floatval >= arg2->floatval);
7430
3.82k
      } else {
7431
364
    ret = 0;
7432
364
      }
7433
8.28k
  }
7434
171k
    }
7435
263k
error:
7436
263k
    xmlXPathReleaseObject(ctxt->context, arg1);
7437
263k
    xmlXPathReleaseObject(ctxt->context, arg2);
7438
263k
    return(ret);
7439
263k
}
7440
7441
/**
7442
 * xmlXPathValueFlipSign:
7443
 * @ctxt:  the XPath Parser context
7444
 *
7445
 * Implement the unary - operation on an XPath object
7446
 * The numeric operators convert their operands to numbers as if
7447
 * by calling the number function.
7448
 */
7449
void
7450
777k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7451
777k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7452
777k
    CAST_TO_NUMBER;
7453
777k
    CHECK_TYPE(XPATH_NUMBER);
7454
777k
    ctxt->value->floatval = -ctxt->value->floatval;
7455
777k
}
7456
7457
/**
7458
 * xmlXPathAddValues:
7459
 * @ctxt:  the XPath Parser context
7460
 *
7461
 * Implement the add operation on XPath objects:
7462
 * The numeric operators convert their operands to numbers as if
7463
 * by calling the number function.
7464
 */
7465
void
7466
137k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7467
137k
    xmlXPathObjectPtr arg;
7468
137k
    double val;
7469
7470
137k
    arg = valuePop(ctxt);
7471
137k
    if (arg == NULL)
7472
137k
  XP_ERROR(XPATH_INVALID_OPERAND);
7473
137k
    val = xmlXPathCastToNumber(arg);
7474
137k
    xmlXPathReleaseObject(ctxt->context, arg);
7475
137k
    CAST_TO_NUMBER;
7476
137k
    CHECK_TYPE(XPATH_NUMBER);
7477
137k
    ctxt->value->floatval += val;
7478
137k
}
7479
7480
/**
7481
 * xmlXPathSubValues:
7482
 * @ctxt:  the XPath Parser context
7483
 *
7484
 * Implement the subtraction operation on XPath objects:
7485
 * The numeric operators convert their operands to numbers as if
7486
 * by calling the number function.
7487
 */
7488
void
7489
546k
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7490
546k
    xmlXPathObjectPtr arg;
7491
546k
    double val;
7492
7493
546k
    arg = valuePop(ctxt);
7494
546k
    if (arg == NULL)
7495
546k
  XP_ERROR(XPATH_INVALID_OPERAND);
7496
546k
    val = xmlXPathCastToNumber(arg);
7497
546k
    xmlXPathReleaseObject(ctxt->context, arg);
7498
546k
    CAST_TO_NUMBER;
7499
546k
    CHECK_TYPE(XPATH_NUMBER);
7500
546k
    ctxt->value->floatval -= val;
7501
546k
}
7502
7503
/**
7504
 * xmlXPathMultValues:
7505
 * @ctxt:  the XPath Parser context
7506
 *
7507
 * Implement the multiply operation on XPath objects:
7508
 * The numeric operators convert their operands to numbers as if
7509
 * by calling the number function.
7510
 */
7511
void
7512
163k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7513
163k
    xmlXPathObjectPtr arg;
7514
163k
    double val;
7515
7516
163k
    arg = valuePop(ctxt);
7517
163k
    if (arg == NULL)
7518
163k
  XP_ERROR(XPATH_INVALID_OPERAND);
7519
163k
    val = xmlXPathCastToNumber(arg);
7520
163k
    xmlXPathReleaseObject(ctxt->context, arg);
7521
163k
    CAST_TO_NUMBER;
7522
163k
    CHECK_TYPE(XPATH_NUMBER);
7523
162k
    ctxt->value->floatval *= val;
7524
162k
}
7525
7526
/**
7527
 * xmlXPathDivValues:
7528
 * @ctxt:  the XPath Parser context
7529
 *
7530
 * Implement the div operation on XPath objects @arg1 / @arg2:
7531
 * The numeric operators convert their operands to numbers as if
7532
 * by calling the number function.
7533
 */
7534
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7535
void
7536
1.39k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7537
1.39k
    xmlXPathObjectPtr arg;
7538
1.39k
    double val;
7539
7540
1.39k
    arg = valuePop(ctxt);
7541
1.39k
    if (arg == NULL)
7542
1.39k
  XP_ERROR(XPATH_INVALID_OPERAND);
7543
1.39k
    val = xmlXPathCastToNumber(arg);
7544
1.39k
    xmlXPathReleaseObject(ctxt->context, arg);
7545
1.39k
    CAST_TO_NUMBER;
7546
1.39k
    CHECK_TYPE(XPATH_NUMBER);
7547
1.39k
    ctxt->value->floatval /= val;
7548
1.39k
}
7549
7550
/**
7551
 * xmlXPathModValues:
7552
 * @ctxt:  the XPath Parser context
7553
 *
7554
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7555
 * The numeric operators convert their operands to numbers as if
7556
 * by calling the number function.
7557
 */
7558
void
7559
156k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7560
156k
    xmlXPathObjectPtr arg;
7561
156k
    double arg1, arg2;
7562
7563
156k
    arg = valuePop(ctxt);
7564
156k
    if (arg == NULL)
7565
156k
  XP_ERROR(XPATH_INVALID_OPERAND);
7566
156k
    arg2 = xmlXPathCastToNumber(arg);
7567
156k
    xmlXPathReleaseObject(ctxt->context, arg);
7568
156k
    CAST_TO_NUMBER;
7569
156k
    CHECK_TYPE(XPATH_NUMBER);
7570
156k
    arg1 = ctxt->value->floatval;
7571
156k
    if (arg2 == 0)
7572
4.42k
  ctxt->value->floatval = xmlXPathNAN;
7573
151k
    else {
7574
151k
  ctxt->value->floatval = fmod(arg1, arg2);
7575
151k
    }
7576
156k
}
7577
7578
/************************************************************************
7579
 *                  *
7580
 *    The traversal functions         *
7581
 *                  *
7582
 ************************************************************************/
7583
7584
/*
7585
 * A traversal function enumerates nodes along an axis.
7586
 * Initially it must be called with NULL, and it indicates
7587
 * termination on the axis by returning NULL.
7588
 */
7589
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7590
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7591
7592
/*
7593
 * xmlXPathTraversalFunctionExt:
7594
 * A traversal function enumerates nodes along an axis.
7595
 * Initially it must be called with NULL, and it indicates
7596
 * termination on the axis by returning NULL.
7597
 * The context node of the traversal is specified via @contextNode.
7598
 */
7599
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7600
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7601
7602
/*
7603
 * xmlXPathNodeSetMergeFunction:
7604
 * Used for merging node sets in xmlXPathCollectAndTest().
7605
 */
7606
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7607
        (xmlNodeSetPtr, xmlNodeSetPtr);
7608
7609
7610
/**
7611
 * xmlXPathNextSelf:
7612
 * @ctxt:  the XPath Parser context
7613
 * @cur:  the current node in the traversal
7614
 *
7615
 * Traversal function for the "self" direction
7616
 * The self axis contains just the context node itself
7617
 *
7618
 * Returns the next element following that axis
7619
 */
7620
xmlNodePtr
7621
910
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7622
910
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7623
910
    if (cur == NULL)
7624
508
        return(ctxt->context->node);
7625
402
    return(NULL);
7626
910
}
7627
7628
/**
7629
 * xmlXPathNextChild:
7630
 * @ctxt:  the XPath Parser context
7631
 * @cur:  the current node in the traversal
7632
 *
7633
 * Traversal function for the "child" direction
7634
 * The child axis contains the children of the context node in document order.
7635
 *
7636
 * Returns the next element following that axis
7637
 */
7638
xmlNodePtr
7639
1.51M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7640
1.51M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7641
1.51M
    if (cur == NULL) {
7642
700k
  if (ctxt->context->node == NULL) return(NULL);
7643
700k
  switch (ctxt->context->node->type) {
7644
406k
            case XML_ELEMENT_NODE:
7645
607k
            case XML_TEXT_NODE:
7646
607k
            case XML_CDATA_SECTION_NODE:
7647
607k
            case XML_ENTITY_REF_NODE:
7648
607k
            case XML_ENTITY_NODE:
7649
614k
            case XML_PI_NODE:
7650
621k
            case XML_COMMENT_NODE:
7651
621k
            case XML_NOTATION_NODE:
7652
621k
            case XML_DTD_NODE:
7653
621k
    return(ctxt->context->node->children);
7654
76.1k
            case XML_DOCUMENT_NODE:
7655
76.1k
            case XML_DOCUMENT_TYPE_NODE:
7656
76.1k
            case XML_DOCUMENT_FRAG_NODE:
7657
76.1k
            case XML_HTML_DOCUMENT_NODE:
7658
76.1k
    return(((xmlDocPtr) ctxt->context->node)->children);
7659
0
      case XML_ELEMENT_DECL:
7660
0
      case XML_ATTRIBUTE_DECL:
7661
0
      case XML_ENTITY_DECL:
7662
497
            case XML_ATTRIBUTE_NODE:
7663
2.93k
      case XML_NAMESPACE_DECL:
7664
2.93k
      case XML_XINCLUDE_START:
7665
2.93k
      case XML_XINCLUDE_END:
7666
2.93k
    return(NULL);
7667
700k
  }
7668
0
  return(NULL);
7669
700k
    }
7670
816k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7671
816k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7672
0
  return(NULL);
7673
816k
    return(cur->next);
7674
816k
}
7675
7676
/**
7677
 * xmlXPathNextChildElement:
7678
 * @ctxt:  the XPath Parser context
7679
 * @cur:  the current node in the traversal
7680
 *
7681
 * Traversal function for the "child" direction and nodes of type element.
7682
 * The child axis contains the children of the context node in document order.
7683
 *
7684
 * Returns the next element following that axis
7685
 */
7686
static xmlNodePtr
7687
5.92M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7688
5.92M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7689
5.92M
    if (cur == NULL) {
7690
2.83M
  cur = ctxt->context->node;
7691
2.83M
  if (cur == NULL) return(NULL);
7692
  /*
7693
  * Get the first element child.
7694
  */
7695
2.83M
  switch (cur->type) {
7696
1.64M
            case XML_ELEMENT_NODE:
7697
1.64M
      case XML_DOCUMENT_FRAG_NODE:
7698
1.64M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7699
1.64M
            case XML_ENTITY_NODE:
7700
1.64M
    cur = cur->children;
7701
1.64M
    if (cur != NULL) {
7702
1.11M
        if (cur->type == XML_ELEMENT_NODE)
7703
273k
      return(cur);
7704
891k
        do {
7705
891k
      cur = cur->next;
7706
891k
        } while ((cur != NULL) &&
7707
891k
      (cur->type != XML_ELEMENT_NODE));
7708
837k
        return(cur);
7709
1.11M
    }
7710
530k
    return(NULL);
7711
293k
            case XML_DOCUMENT_NODE:
7712
293k
            case XML_HTML_DOCUMENT_NODE:
7713
293k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7714
901k
      default:
7715
901k
    return(NULL);
7716
2.83M
  }
7717
0
  return(NULL);
7718
2.83M
    }
7719
    /*
7720
    * Get the next sibling element node.
7721
    */
7722
3.09M
    switch (cur->type) {
7723
3.09M
  case XML_ELEMENT_NODE:
7724
3.09M
  case XML_TEXT_NODE:
7725
3.09M
  case XML_ENTITY_REF_NODE:
7726
3.09M
  case XML_ENTITY_NODE:
7727
3.09M
  case XML_CDATA_SECTION_NODE:
7728
3.09M
  case XML_PI_NODE:
7729
3.09M
  case XML_COMMENT_NODE:
7730
3.09M
  case XML_XINCLUDE_END:
7731
3.09M
      break;
7732
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7733
0
  default:
7734
0
      return(NULL);
7735
3.09M
    }
7736
3.09M
    if (cur->next != NULL) {
7737
2.41M
  if (cur->next->type == XML_ELEMENT_NODE)
7738
1.23M
      return(cur->next);
7739
1.17M
  cur = cur->next;
7740
1.23M
  do {
7741
1.23M
      cur = cur->next;
7742
1.23M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7743
1.17M
  return(cur);
7744
2.41M
    }
7745
675k
    return(NULL);
7746
3.09M
}
7747
7748
#if 0
7749
/**
7750
 * xmlXPathNextDescendantOrSelfElemParent:
7751
 * @ctxt:  the XPath Parser context
7752
 * @cur:  the current node in the traversal
7753
 *
7754
 * Traversal function for the "descendant-or-self" axis.
7755
 * Additionally it returns only nodes which can be parents of
7756
 * element nodes.
7757
 *
7758
 *
7759
 * Returns the next element following that axis
7760
 */
7761
static xmlNodePtr
7762
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7763
               xmlNodePtr contextNode)
7764
{
7765
    if (cur == NULL) {
7766
  if (contextNode == NULL)
7767
      return(NULL);
7768
  switch (contextNode->type) {
7769
      case XML_ELEMENT_NODE:
7770
      case XML_XINCLUDE_START:
7771
      case XML_DOCUMENT_FRAG_NODE:
7772
      case XML_DOCUMENT_NODE:
7773
      case XML_HTML_DOCUMENT_NODE:
7774
    return(contextNode);
7775
      default:
7776
    return(NULL);
7777
  }
7778
  return(NULL);
7779
    } else {
7780
  xmlNodePtr start = cur;
7781
7782
  while (cur != NULL) {
7783
      switch (cur->type) {
7784
    case XML_ELEMENT_NODE:
7785
    /* TODO: OK to have XInclude here? */
7786
    case XML_XINCLUDE_START:
7787
    case XML_DOCUMENT_FRAG_NODE:
7788
        if (cur != start)
7789
      return(cur);
7790
        if (cur->children != NULL) {
7791
      cur = cur->children;
7792
      continue;
7793
        }
7794
        break;
7795
    /* Not sure if we need those here. */
7796
    case XML_DOCUMENT_NODE:
7797
    case XML_HTML_DOCUMENT_NODE:
7798
        if (cur != start)
7799
      return(cur);
7800
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7801
    default:
7802
        break;
7803
      }
7804
7805
next_sibling:
7806
      if ((cur == NULL) || (cur == contextNode))
7807
    return(NULL);
7808
      if (cur->next != NULL) {
7809
    cur = cur->next;
7810
      } else {
7811
    cur = cur->parent;
7812
    goto next_sibling;
7813
      }
7814
  }
7815
    }
7816
    return(NULL);
7817
}
7818
#endif
7819
7820
/**
7821
 * xmlXPathNextDescendant:
7822
 * @ctxt:  the XPath Parser context
7823
 * @cur:  the current node in the traversal
7824
 *
7825
 * Traversal function for the "descendant" direction
7826
 * the descendant axis contains the descendants of the context node in document
7827
 * order; a descendant is a child or a child of a child and so on.
7828
 *
7829
 * Returns the next element following that axis
7830
 */
7831
xmlNodePtr
7832
22.5M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7833
22.5M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7834
22.5M
    if (cur == NULL) {
7835
814k
  if (ctxt->context->node == NULL)
7836
0
      return(NULL);
7837
814k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7838
814k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7839
1.36k
      return(NULL);
7840
7841
813k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7842
775k
      return(ctxt->context->doc->children);
7843
37.5k
        return(ctxt->context->node->children);
7844
813k
    }
7845
7846
21.7M
    if (cur->type == XML_NAMESPACE_DECL)
7847
0
        return(NULL);
7848
21.7M
    if (cur->children != NULL) {
7849
  /*
7850
   * Do not descend on entities declarations
7851
   */
7852
4.64M
  if (cur->children->type != XML_ENTITY_DECL) {
7853
4.64M
      cur = cur->children;
7854
      /*
7855
       * Skip DTDs
7856
       */
7857
4.64M
      if (cur->type != XML_DTD_NODE)
7858
4.64M
    return(cur);
7859
4.64M
  }
7860
4.64M
    }
7861
7862
17.1M
    if (cur == ctxt->context->node) return(NULL);
7863
7864
17.0M
    while (cur->next != NULL) {
7865
13.7M
  cur = cur->next;
7866
13.7M
  if ((cur->type != XML_ENTITY_DECL) &&
7867
13.7M
      (cur->type != XML_DTD_NODE))
7868
13.7M
      return(cur);
7869
13.7M
    }
7870
7871
5.42M
    do {
7872
5.42M
        cur = cur->parent;
7873
5.42M
  if (cur == NULL) break;
7874
5.42M
  if (cur == ctxt->context->node) return(NULL);
7875
4.57M
  if (cur->next != NULL) {
7876
2.50M
      cur = cur->next;
7877
2.50M
      return(cur);
7878
2.50M
  }
7879
4.57M
    } while (cur != NULL);
7880
0
    return(cur);
7881
3.36M
}
7882
7883
/**
7884
 * xmlXPathNextDescendantOrSelf:
7885
 * @ctxt:  the XPath Parser context
7886
 * @cur:  the current node in the traversal
7887
 *
7888
 * Traversal function for the "descendant-or-self" direction
7889
 * the descendant-or-self axis contains the context node and the descendants
7890
 * of the context node in document order; thus the context node is the first
7891
 * node on the axis, and the first child of the context node is the second node
7892
 * on the axis
7893
 *
7894
 * Returns the next element following that axis
7895
 */
7896
xmlNodePtr
7897
4.94M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7898
4.94M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7899
4.94M
    if (cur == NULL)
7900
145k
        return(ctxt->context->node);
7901
7902
4.80M
    if (ctxt->context->node == NULL)
7903
0
        return(NULL);
7904
4.80M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7905
4.80M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7906
72.5k
        return(NULL);
7907
7908
4.72M
    return(xmlXPathNextDescendant(ctxt, cur));
7909
4.80M
}
7910
7911
/**
7912
 * xmlXPathNextParent:
7913
 * @ctxt:  the XPath Parser context
7914
 * @cur:  the current node in the traversal
7915
 *
7916
 * Traversal function for the "parent" direction
7917
 * The parent axis contains the parent of the context node, if there is one.
7918
 *
7919
 * Returns the next element following that axis
7920
 */
7921
xmlNodePtr
7922
1.33M
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7923
1.33M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7924
    /*
7925
     * the parent of an attribute or namespace node is the element
7926
     * to which the attribute or namespace node is attached
7927
     * Namespace handling !!!
7928
     */
7929
1.33M
    if (cur == NULL) {
7930
683k
  if (ctxt->context->node == NULL) return(NULL);
7931
683k
  switch (ctxt->context->node->type) {
7932
447k
            case XML_ELEMENT_NODE:
7933
636k
            case XML_TEXT_NODE:
7934
636k
            case XML_CDATA_SECTION_NODE:
7935
636k
            case XML_ENTITY_REF_NODE:
7936
636k
            case XML_ENTITY_NODE:
7937
644k
            case XML_PI_NODE:
7938
653k
            case XML_COMMENT_NODE:
7939
653k
            case XML_NOTATION_NODE:
7940
653k
            case XML_DTD_NODE:
7941
653k
      case XML_ELEMENT_DECL:
7942
653k
      case XML_ATTRIBUTE_DECL:
7943
653k
      case XML_XINCLUDE_START:
7944
653k
      case XML_XINCLUDE_END:
7945
653k
      case XML_ENTITY_DECL:
7946
653k
    if (ctxt->context->node->parent == NULL)
7947
0
        return((xmlNodePtr) ctxt->context->doc);
7948
653k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7949
653k
        ((ctxt->context->node->parent->name[0] == ' ') ||
7950
623k
         (xmlStrEqual(ctxt->context->node->parent->name,
7951
623k
         BAD_CAST "fake node libxslt"))))
7952
0
        return(NULL);
7953
653k
    return(ctxt->context->node->parent);
7954
484
            case XML_ATTRIBUTE_NODE: {
7955
484
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7956
7957
484
    return(att->parent);
7958
653k
      }
7959
28.8k
            case XML_DOCUMENT_NODE:
7960
28.8k
            case XML_DOCUMENT_TYPE_NODE:
7961
28.8k
            case XML_DOCUMENT_FRAG_NODE:
7962
28.8k
            case XML_HTML_DOCUMENT_NODE:
7963
28.8k
                return(NULL);
7964
820
      case XML_NAMESPACE_DECL: {
7965
820
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7966
7967
820
    if ((ns->next != NULL) &&
7968
820
        (ns->next->type != XML_NAMESPACE_DECL))
7969
820
        return((xmlNodePtr) ns->next);
7970
0
                return(NULL);
7971
820
      }
7972
683k
  }
7973
683k
    }
7974
653k
    return(NULL);
7975
1.33M
}
7976
7977
/**
7978
 * xmlXPathNextAncestor:
7979
 * @ctxt:  the XPath Parser context
7980
 * @cur:  the current node in the traversal
7981
 *
7982
 * Traversal function for the "ancestor" direction
7983
 * the ancestor axis contains the ancestors of the context node; the ancestors
7984
 * of the context node consist of the parent of context node and the parent's
7985
 * parent and so on; the nodes are ordered in reverse document order; thus the
7986
 * parent is the first node on the axis, and the parent's parent is the second
7987
 * node on the axis
7988
 *
7989
 * Returns the next element following that axis
7990
 */
7991
xmlNodePtr
7992
310k
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7993
310k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7994
    /*
7995
     * the parent of an attribute or namespace node is the element
7996
     * to which the attribute or namespace node is attached
7997
     * !!!!!!!!!!!!!
7998
     */
7999
310k
    if (cur == NULL) {
8000
24.1k
  if (ctxt->context->node == NULL) return(NULL);
8001
24.1k
  switch (ctxt->context->node->type) {
8002
10.0k
            case XML_ELEMENT_NODE:
8003
22.7k
            case XML_TEXT_NODE:
8004
22.7k
            case XML_CDATA_SECTION_NODE:
8005
22.7k
            case XML_ENTITY_REF_NODE:
8006
22.7k
            case XML_ENTITY_NODE:
8007
23.3k
            case XML_PI_NODE:
8008
23.6k
            case XML_COMMENT_NODE:
8009
23.6k
      case XML_DTD_NODE:
8010
23.6k
      case XML_ELEMENT_DECL:
8011
23.6k
      case XML_ATTRIBUTE_DECL:
8012
23.6k
      case XML_ENTITY_DECL:
8013
23.6k
            case XML_NOTATION_NODE:
8014
23.6k
      case XML_XINCLUDE_START:
8015
23.6k
      case XML_XINCLUDE_END:
8016
23.6k
    if (ctxt->context->node->parent == NULL)
8017
0
        return((xmlNodePtr) ctxt->context->doc);
8018
23.6k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8019
23.6k
        ((ctxt->context->node->parent->name[0] == ' ') ||
8020
23.1k
         (xmlStrEqual(ctxt->context->node->parent->name,
8021
23.1k
         BAD_CAST "fake node libxslt"))))
8022
0
        return(NULL);
8023
23.6k
    return(ctxt->context->node->parent);
8024
0
            case XML_ATTRIBUTE_NODE: {
8025
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8026
8027
0
    return(tmp->parent);
8028
23.6k
      }
8029
488
            case XML_DOCUMENT_NODE:
8030
488
            case XML_DOCUMENT_TYPE_NODE:
8031
488
            case XML_DOCUMENT_FRAG_NODE:
8032
488
            case XML_HTML_DOCUMENT_NODE:
8033
488
                return(NULL);
8034
0
      case XML_NAMESPACE_DECL: {
8035
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8036
8037
0
    if ((ns->next != NULL) &&
8038
0
        (ns->next->type != XML_NAMESPACE_DECL))
8039
0
        return((xmlNodePtr) ns->next);
8040
    /* Bad, how did that namespace end up here ? */
8041
0
                return(NULL);
8042
0
      }
8043
24.1k
  }
8044
0
  return(NULL);
8045
24.1k
    }
8046
286k
    if (cur == ctxt->context->doc->children)
8047
30.2k
  return((xmlNodePtr) ctxt->context->doc);
8048
255k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8049
34.4k
  return(NULL);
8050
221k
    switch (cur->type) {
8051
214k
  case XML_ELEMENT_NODE:
8052
220k
  case XML_TEXT_NODE:
8053
220k
  case XML_CDATA_SECTION_NODE:
8054
220k
  case XML_ENTITY_REF_NODE:
8055
220k
  case XML_ENTITY_NODE:
8056
220k
  case XML_PI_NODE:
8057
221k
  case XML_COMMENT_NODE:
8058
221k
  case XML_NOTATION_NODE:
8059
221k
  case XML_DTD_NODE:
8060
221k
        case XML_ELEMENT_DECL:
8061
221k
        case XML_ATTRIBUTE_DECL:
8062
221k
        case XML_ENTITY_DECL:
8063
221k
  case XML_XINCLUDE_START:
8064
221k
  case XML_XINCLUDE_END:
8065
221k
      if (cur->parent == NULL)
8066
0
    return(NULL);
8067
221k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8068
221k
    ((cur->parent->name[0] == ' ') ||
8069
212k
     (xmlStrEqual(cur->parent->name,
8070
212k
            BAD_CAST "fake node libxslt"))))
8071
0
    return(NULL);
8072
221k
      return(cur->parent);
8073
0
  case XML_ATTRIBUTE_NODE: {
8074
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8075
8076
0
      return(att->parent);
8077
221k
  }
8078
0
  case XML_NAMESPACE_DECL: {
8079
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8080
8081
0
      if ((ns->next != NULL) &&
8082
0
          (ns->next->type != XML_NAMESPACE_DECL))
8083
0
          return((xmlNodePtr) ns->next);
8084
      /* Bad, how did that namespace end up here ? */
8085
0
            return(NULL);
8086
0
  }
8087
0
  case XML_DOCUMENT_NODE:
8088
0
  case XML_DOCUMENT_TYPE_NODE:
8089
0
  case XML_DOCUMENT_FRAG_NODE:
8090
0
  case XML_HTML_DOCUMENT_NODE:
8091
0
      return(NULL);
8092
221k
    }
8093
0
    return(NULL);
8094
221k
}
8095
8096
/**
8097
 * xmlXPathNextAncestorOrSelf:
8098
 * @ctxt:  the XPath Parser context
8099
 * @cur:  the current node in the traversal
8100
 *
8101
 * Traversal function for the "ancestor-or-self" direction
8102
 * he ancestor-or-self axis contains the context node and ancestors of
8103
 * the context node in reverse document order; thus the context node is
8104
 * the first node on the axis, and the context node's parent the second;
8105
 * parent here is defined the same as with the parent axis.
8106
 *
8107
 * Returns the next element following that axis
8108
 */
8109
xmlNodePtr
8110
59.8k
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8111
59.8k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8112
59.8k
    if (cur == NULL)
8113
10.8k
        return(ctxt->context->node);
8114
49.0k
    return(xmlXPathNextAncestor(ctxt, cur));
8115
59.8k
}
8116
8117
/**
8118
 * xmlXPathNextFollowingSibling:
8119
 * @ctxt:  the XPath Parser context
8120
 * @cur:  the current node in the traversal
8121
 *
8122
 * Traversal function for the "following-sibling" direction
8123
 * The following-sibling axis contains the following siblings of the context
8124
 * node in document order.
8125
 *
8126
 * Returns the next element following that axis
8127
 */
8128
xmlNodePtr
8129
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8130
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8131
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8132
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8133
0
  return(NULL);
8134
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8135
0
        return(NULL);
8136
0
    if (cur == NULL)
8137
0
        return(ctxt->context->node->next);
8138
0
    return(cur->next);
8139
0
}
8140
8141
/**
8142
 * xmlXPathNextPrecedingSibling:
8143
 * @ctxt:  the XPath Parser context
8144
 * @cur:  the current node in the traversal
8145
 *
8146
 * Traversal function for the "preceding-sibling" direction
8147
 * The preceding-sibling axis contains the preceding siblings of the context
8148
 * node in reverse document order; the first preceding sibling is first on the
8149
 * axis; the sibling preceding that node is the second on the axis and so on.
8150
 *
8151
 * Returns the next element following that axis
8152
 */
8153
xmlNodePtr
8154
218M
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8155
218M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8156
218M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8157
218M
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8158
750
  return(NULL);
8159
218M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8160
0
        return(NULL);
8161
218M
    if (cur == NULL)
8162
11.3k
        return(ctxt->context->node->prev);
8163
218M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8164
0
  cur = cur->prev;
8165
0
  if (cur == NULL)
8166
0
      return(ctxt->context->node->prev);
8167
0
    }
8168
218M
    return(cur->prev);
8169
218M
}
8170
8171
/**
8172
 * xmlXPathNextFollowing:
8173
 * @ctxt:  the XPath Parser context
8174
 * @cur:  the current node in the traversal
8175
 *
8176
 * Traversal function for the "following" direction
8177
 * The following axis contains all nodes in the same document as the context
8178
 * node that are after the context node in document order, excluding any
8179
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8180
 * are ordered in document order
8181
 *
8182
 * Returns the next element following that axis
8183
 */
8184
xmlNodePtr
8185
243k
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8186
243k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8187
243k
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8188
243k
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8189
42.8k
        return(cur->children);
8190
8191
200k
    if (cur == NULL) {
8192
4.16k
        cur = ctxt->context->node;
8193
4.16k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8194
0
            cur = cur->parent;
8195
4.16k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8196
3.85k
            xmlNsPtr ns = (xmlNsPtr) cur;
8197
8198
3.85k
            if ((ns->next == NULL) ||
8199
3.85k
                (ns->next->type == XML_NAMESPACE_DECL))
8200
0
                return (NULL);
8201
3.85k
            cur = (xmlNodePtr) ns->next;
8202
3.85k
        }
8203
4.16k
    }
8204
200k
    if (cur == NULL) return(NULL) ; /* ERROR */
8205
200k
    if (cur->next != NULL) return(cur->next) ;
8206
53.7k
    do {
8207
53.7k
        cur = cur->parent;
8208
53.7k
        if (cur == NULL) break;
8209
53.4k
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8210
49.6k
        if (cur->next != NULL) return(cur->next);
8211
49.6k
    } while (cur != NULL);
8212
281
    return(cur);
8213
40.7k
}
8214
8215
/*
8216
 * xmlXPathIsAncestor:
8217
 * @ancestor:  the ancestor node
8218
 * @node:  the current node
8219
 *
8220
 * Check that @ancestor is a @node's ancestor
8221
 *
8222
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8223
 */
8224
static int
8225
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8226
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8227
0
    if (node->type == XML_NAMESPACE_DECL)
8228
0
        return(0);
8229
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8230
0
        return(0);
8231
    /* nodes need to be in the same document */
8232
0
    if (ancestor->doc != node->doc) return(0);
8233
    /* avoid searching if ancestor or node is the root node */
8234
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8235
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8236
0
    while (node->parent != NULL) {
8237
0
        if (node->parent == ancestor)
8238
0
            return(1);
8239
0
  node = node->parent;
8240
0
    }
8241
0
    return(0);
8242
0
}
8243
8244
/**
8245
 * xmlXPathNextPreceding:
8246
 * @ctxt:  the XPath Parser context
8247
 * @cur:  the current node in the traversal
8248
 *
8249
 * Traversal function for the "preceding" direction
8250
 * the preceding axis contains all nodes in the same document as the context
8251
 * node that are before the context node in document order, excluding any
8252
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253
 * ordered in reverse document order
8254
 *
8255
 * Returns the next element following that axis
8256
 */
8257
xmlNodePtr
8258
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8259
0
{
8260
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8261
0
    if (cur == NULL) {
8262
0
        cur = ctxt->context->node;
8263
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8264
0
            cur = cur->parent;
8265
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8266
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8267
8268
0
            if ((ns->next == NULL) ||
8269
0
                (ns->next->type == XML_NAMESPACE_DECL))
8270
0
                return (NULL);
8271
0
            cur = (xmlNodePtr) ns->next;
8272
0
        }
8273
0
    }
8274
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8275
0
  return (NULL);
8276
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8277
0
  cur = cur->prev;
8278
0
    do {
8279
0
        if (cur->prev != NULL) {
8280
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8281
0
            return (cur);
8282
0
        }
8283
8284
0
        cur = cur->parent;
8285
0
        if (cur == NULL)
8286
0
            return (NULL);
8287
0
        if (cur == ctxt->context->doc->children)
8288
0
            return (NULL);
8289
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8290
0
    return (cur);
8291
0
}
8292
8293
/**
8294
 * xmlXPathNextPrecedingInternal:
8295
 * @ctxt:  the XPath Parser context
8296
 * @cur:  the current node in the traversal
8297
 *
8298
 * Traversal function for the "preceding" direction
8299
 * the preceding axis contains all nodes in the same document as the context
8300
 * node that are before the context node in document order, excluding any
8301
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8302
 * ordered in reverse document order
8303
 * This is a faster implementation but internal only since it requires a
8304
 * state kept in the parser context: ctxt->ancestor.
8305
 *
8306
 * Returns the next element following that axis
8307
 */
8308
static xmlNodePtr
8309
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8310
                              xmlNodePtr cur)
8311
3.94M
{
8312
3.94M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8313
3.94M
    if (cur == NULL) {
8314
6.54k
        cur = ctxt->context->node;
8315
6.54k
        if (cur == NULL)
8316
0
            return (NULL);
8317
6.54k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8318
215
            cur = cur->parent;
8319
6.32k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8320
164
            xmlNsPtr ns = (xmlNsPtr) cur;
8321
8322
164
            if ((ns->next == NULL) ||
8323
164
                (ns->next->type == XML_NAMESPACE_DECL))
8324
0
                return (NULL);
8325
164
            cur = (xmlNodePtr) ns->next;
8326
164
        }
8327
6.54k
        ctxt->ancestor = cur->parent;
8328
6.54k
    }
8329
3.94M
    if (cur->type == XML_NAMESPACE_DECL)
8330
0
        return(NULL);
8331
3.94M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8332
22
  cur = cur->prev;
8333
4.17M
    while (cur->prev == NULL) {
8334
2.03M
        cur = cur->parent;
8335
2.03M
        if (cur == NULL)
8336
1.39k
            return (NULL);
8337
2.03M
        if (cur == ctxt->context->doc->children)
8338
5.13k
            return (NULL);
8339
2.02M
        if (cur != ctxt->ancestor)
8340
1.79M
            return (cur);
8341
232k
        ctxt->ancestor = cur->parent;
8342
232k
    }
8343
2.14M
    cur = cur->prev;
8344
3.94M
    while (cur->last != NULL)
8345
1.79M
        cur = cur->last;
8346
2.14M
    return (cur);
8347
3.94M
}
8348
8349
/**
8350
 * xmlXPathNextNamespace:
8351
 * @ctxt:  the XPath Parser context
8352
 * @cur:  the current attribute in the traversal
8353
 *
8354
 * Traversal function for the "namespace" direction
8355
 * the namespace axis contains the namespace nodes of the context node;
8356
 * the order of nodes on this axis is implementation-defined; the axis will
8357
 * be empty unless the context node is an element
8358
 *
8359
 * We keep the XML namespace node at the end of the list.
8360
 *
8361
 * Returns the next element following that axis
8362
 */
8363
xmlNodePtr
8364
914k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8365
914k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8366
914k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8367
866k
    if (cur == NULL) {
8368
174k
        if (ctxt->context->tmpNsList != NULL)
8369
2.44k
      xmlFree(ctxt->context->tmpNsList);
8370
174k
  ctxt->context->tmpNsList =
8371
174k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8372
174k
  ctxt->context->tmpNsNr = 0;
8373
174k
  if (ctxt->context->tmpNsList != NULL) {
8374
703k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8375
533k
    ctxt->context->tmpNsNr++;
8376
533k
      }
8377
169k
  }
8378
174k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8379
174k
    }
8380
692k
    if (ctxt->context->tmpNsNr > 0) {
8381
522k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8382
522k
    } else {
8383
169k
  if (ctxt->context->tmpNsList != NULL)
8384
165k
      xmlFree(ctxt->context->tmpNsList);
8385
169k
  ctxt->context->tmpNsList = NULL;
8386
169k
  return(NULL);
8387
169k
    }
8388
692k
}
8389
8390
/**
8391
 * xmlXPathNextAttribute:
8392
 * @ctxt:  the XPath Parser context
8393
 * @cur:  the current attribute in the traversal
8394
 *
8395
 * Traversal function for the "attribute" direction
8396
 * TODO: support DTD inherited default attributes
8397
 *
8398
 * Returns the next element following that axis
8399
 */
8400
xmlNodePtr
8401
1.60M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8402
1.60M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8403
1.60M
    if (ctxt->context->node == NULL)
8404
0
  return(NULL);
8405
1.60M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8406
114k
  return(NULL);
8407
1.49M
    if (cur == NULL) {
8408
805k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8409
0
      return(NULL);
8410
805k
        return((xmlNodePtr)ctxt->context->node->properties);
8411
805k
    }
8412
687k
    return((xmlNodePtr)cur->next);
8413
1.49M
}
8414
8415
/************************************************************************
8416
 *                  *
8417
 *    NodeTest Functions          *
8418
 *                  *
8419
 ************************************************************************/
8420
8421
#define IS_FUNCTION     200
8422
8423
8424
/************************************************************************
8425
 *                  *
8426
 *    Implicit tree core function library     *
8427
 *                  *
8428
 ************************************************************************/
8429
8430
/**
8431
 * xmlXPathRoot:
8432
 * @ctxt:  the XPath Parser context
8433
 *
8434
 * Initialize the context to the root of the document
8435
 */
8436
void
8437
1.91M
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8438
1.91M
    if ((ctxt == NULL) || (ctxt->context == NULL))
8439
0
  return;
8440
1.91M
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8441
1.91M
  (xmlNodePtr) ctxt->context->doc));
8442
1.91M
}
8443
8444
/************************************************************************
8445
 *                  *
8446
 *    The explicit core function library      *
8447
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8448
 *                  *
8449
 ************************************************************************/
8450
8451
8452
/**
8453
 * xmlXPathLastFunction:
8454
 * @ctxt:  the XPath Parser context
8455
 * @nargs:  the number of arguments
8456
 *
8457
 * Implement the last() XPath function
8458
 *    number last()
8459
 * The last function returns the number of nodes in the context node list.
8460
 */
8461
void
8462
157k
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8463
470k
    CHECK_ARITY(0);
8464
470k
    if (ctxt->context->contextSize >= 0) {
8465
156k
  valuePush(ctxt,
8466
156k
      xmlXPathCacheNewFloat(ctxt->context,
8467
156k
    (double) ctxt->context->contextSize));
8468
#ifdef DEBUG_EXPR
8469
  xmlGenericError(xmlGenericErrorContext,
8470
    "last() : %d\n", ctxt->context->contextSize);
8471
#endif
8472
156k
    } else {
8473
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8474
0
    }
8475
470k
}
8476
8477
/**
8478
 * xmlXPathPositionFunction:
8479
 * @ctxt:  the XPath Parser context
8480
 * @nargs:  the number of arguments
8481
 *
8482
 * Implement the position() XPath function
8483
 *    number position()
8484
 * The position function returns the position of the context node in the
8485
 * context node list. The first position is 1, and so the last position
8486
 * will be equal to last().
8487
 */
8488
void
8489
81.3k
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490
243k
    CHECK_ARITY(0);
8491
243k
    if (ctxt->context->proximityPosition >= 0) {
8492
81.0k
  valuePush(ctxt,
8493
81.0k
        xmlXPathCacheNewFloat(ctxt->context,
8494
81.0k
    (double) ctxt->context->proximityPosition));
8495
#ifdef DEBUG_EXPR
8496
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8497
    ctxt->context->proximityPosition);
8498
#endif
8499
81.0k
    } else {
8500
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8501
0
    }
8502
243k
}
8503
8504
/**
8505
 * xmlXPathCountFunction:
8506
 * @ctxt:  the XPath Parser context
8507
 * @nargs:  the number of arguments
8508
 *
8509
 * Implement the count() XPath function
8510
 *    number count(node-set)
8511
 */
8512
void
8513
12.1k
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514
12.1k
    xmlXPathObjectPtr cur;
8515
8516
26.6k
    CHECK_ARITY(1);
8517
26.6k
    if ((ctxt->value == NULL) ||
8518
7.24k
  ((ctxt->value->type != XPATH_NODESET) &&
8519
7.24k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8520
4.76k
  XP_ERROR(XPATH_INVALID_TYPE);
8521
2.47k
    cur = valuePop(ctxt);
8522
8523
2.47k
    if ((cur == NULL) || (cur->nodesetval == NULL))
8524
416
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8525
2.06k
    else
8526
2.06k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8527
2.06k
      (double) cur->nodesetval->nodeNr));
8528
2.47k
    xmlXPathReleaseObject(ctxt->context, cur);
8529
2.47k
}
8530
8531
/**
8532
 * xmlXPathGetElementsByIds:
8533
 * @doc:  the document
8534
 * @ids:  a whitespace separated list of IDs
8535
 *
8536
 * Selects elements by their unique ID.
8537
 *
8538
 * Returns a node-set of selected elements.
8539
 */
8540
static xmlNodeSetPtr
8541
19.5k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8542
19.5k
    xmlNodeSetPtr ret;
8543
19.5k
    const xmlChar *cur = ids;
8544
19.5k
    xmlChar *ID;
8545
19.5k
    xmlAttrPtr attr;
8546
19.5k
    xmlNodePtr elem = NULL;
8547
8548
19.5k
    if (ids == NULL) return(NULL);
8549
8550
19.3k
    ret = xmlXPathNodeSetCreate(NULL);
8551
19.3k
    if (ret == NULL)
8552
5
        return(ret);
8553
8554
19.3k
    while (IS_BLANK_CH(*cur)) cur++;
8555
42.4k
    while (*cur != 0) {
8556
1.77M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8557
1.75M
      cur++;
8558
8559
23.0k
        ID = xmlStrndup(ids, cur - ids);
8560
23.0k
  if (ID != NULL) {
8561
      /*
8562
       * We used to check the fact that the value passed
8563
       * was an NCName, but this generated much troubles for
8564
       * me and Aleksey Sanin, people blatantly violated that
8565
       * constraint, like Visa3D spec.
8566
       * if (xmlValidateNCName(ID, 1) == 0)
8567
       */
8568
22.8k
      attr = xmlGetID(doc, ID);
8569
22.8k
      if (attr != NULL) {
8570
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8571
0
        elem = attr->parent;
8572
0
    else if (attr->type == XML_ELEMENT_NODE)
8573
0
        elem = (xmlNodePtr) attr;
8574
0
    else
8575
0
        elem = NULL;
8576
                /* TODO: Check memory error. */
8577
0
    if (elem != NULL)
8578
0
        xmlXPathNodeSetAdd(ret, elem);
8579
0
      }
8580
22.8k
      xmlFree(ID);
8581
22.8k
  }
8582
8583
23.0k
  while (IS_BLANK_CH(*cur)) cur++;
8584
23.0k
  ids = cur;
8585
23.0k
    }
8586
19.3k
    return(ret);
8587
19.3k
}
8588
8589
/**
8590
 * xmlXPathIdFunction:
8591
 * @ctxt:  the XPath Parser context
8592
 * @nargs:  the number of arguments
8593
 *
8594
 * Implement the id() XPath function
8595
 *    node-set id(object)
8596
 * The id function selects elements by their unique ID
8597
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8598
 * then the result is the union of the result of applying id to the
8599
 * string value of each of the nodes in the argument node-set. When the
8600
 * argument to id is of any other type, the argument is converted to a
8601
 * string as if by a call to the string function; the string is split
8602
 * into a whitespace-separated list of tokens (whitespace is any sequence
8603
 * of characters matching the production S); the result is a node-set
8604
 * containing the elements in the same document as the context node that
8605
 * have a unique ID equal to any of the tokens in the list.
8606
 */
8607
void
8608
20.6k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8609
20.6k
    xmlChar *tokens;
8610
20.6k
    xmlNodeSetPtr ret;
8611
20.6k
    xmlXPathObjectPtr obj;
8612
8613
61.8k
    CHECK_ARITY(1);
8614
61.8k
    obj = valuePop(ctxt);
8615
61.8k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8616
20.6k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8617
2.08k
  xmlNodeSetPtr ns;
8618
2.08k
  int i;
8619
8620
        /* TODO: Check memory error. */
8621
2.08k
  ret = xmlXPathNodeSetCreate(NULL);
8622
8623
2.08k
  if (obj->nodesetval != NULL) {
8624
2.89k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8625
993
    tokens =
8626
993
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8627
993
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8628
                /* TODO: Check memory error. */
8629
993
    ret = xmlXPathNodeSetMerge(ret, ns);
8630
993
    xmlXPathFreeNodeSet(ns);
8631
993
    if (tokens != NULL)
8632
868
        xmlFree(tokens);
8633
993
      }
8634
1.90k
  }
8635
2.08k
  xmlXPathReleaseObject(ctxt->context, obj);
8636
2.08k
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8637
2.08k
  return;
8638
2.08k
    }
8639
18.5k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8640
18.5k
    if (obj == NULL) return;
8641
18.5k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8642
18.5k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8643
18.5k
    xmlXPathReleaseObject(ctxt->context, obj);
8644
18.5k
    return;
8645
18.5k
}
8646
8647
/**
8648
 * xmlXPathLocalNameFunction:
8649
 * @ctxt:  the XPath Parser context
8650
 * @nargs:  the number of arguments
8651
 *
8652
 * Implement the local-name() XPath function
8653
 *    string local-name(node-set?)
8654
 * The local-name function returns a string containing the local part
8655
 * of the name of the node in the argument node-set that is first in
8656
 * document order. If the node-set is empty or the first node has no
8657
 * name, an empty string is returned. If the argument is omitted it
8658
 * defaults to the context node.
8659
 */
8660
void
8661
9.19k
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8662
9.19k
    xmlXPathObjectPtr cur;
8663
8664
9.19k
    if (ctxt == NULL) return;
8665
8666
9.19k
    if (nargs == 0) {
8667
141
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8668
141
      ctxt->context->node));
8669
141
  nargs = 1;
8670
141
    }
8671
8672
27.5k
    CHECK_ARITY(1);
8673
27.5k
    if ((ctxt->value == NULL) ||
8674
9.19k
  ((ctxt->value->type != XPATH_NODESET) &&
8675
9.19k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8676
9.19k
  XP_ERROR(XPATH_INVALID_TYPE);
8677
9.19k
    cur = valuePop(ctxt);
8678
8679
9.19k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8680
96
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8681
9.09k
    } else {
8682
9.09k
  int i = 0; /* Should be first in document order !!!!! */
8683
9.09k
  switch (cur->nodesetval->nodeTab[i]->type) {
8684
35
  case XML_ELEMENT_NODE:
8685
35
  case XML_ATTRIBUTE_NODE:
8686
680
  case XML_PI_NODE:
8687
680
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8688
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8689
680
      else
8690
680
    valuePush(ctxt,
8691
680
          xmlXPathCacheNewString(ctxt->context,
8692
680
      cur->nodesetval->nodeTab[i]->name));
8693
680
      break;
8694
1.18k
  case XML_NAMESPACE_DECL:
8695
1.18k
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8696
1.18k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8697
1.18k
      break;
8698
7.22k
  default:
8699
7.22k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8700
9.09k
  }
8701
9.09k
    }
8702
9.19k
    xmlXPathReleaseObject(ctxt->context, cur);
8703
9.19k
}
8704
8705
/**
8706
 * xmlXPathNamespaceURIFunction:
8707
 * @ctxt:  the XPath Parser context
8708
 * @nargs:  the number of arguments
8709
 *
8710
 * Implement the namespace-uri() XPath function
8711
 *    string namespace-uri(node-set?)
8712
 * The namespace-uri function returns a string containing the
8713
 * namespace URI of the expanded name of the node in the argument
8714
 * node-set that is first in document order. If the node-set is empty,
8715
 * the first node has no name, or the expanded name has no namespace
8716
 * URI, an empty string is returned. If the argument is omitted it
8717
 * defaults to the context node.
8718
 */
8719
void
8720
1
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8721
1
    xmlXPathObjectPtr cur;
8722
8723
1
    if (ctxt == NULL) return;
8724
8725
1
    if (nargs == 0) {
8726
1
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8727
1
      ctxt->context->node));
8728
1
  nargs = 1;
8729
1
    }
8730
3
    CHECK_ARITY(1);
8731
3
    if ((ctxt->value == NULL) ||
8732
1
  ((ctxt->value->type != XPATH_NODESET) &&
8733
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
8734
1
  XP_ERROR(XPATH_INVALID_TYPE);
8735
1
    cur = valuePop(ctxt);
8736
8737
1
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8738
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8739
1
    } else {
8740
1
  int i = 0; /* Should be first in document order !!!!! */
8741
1
  switch (cur->nodesetval->nodeTab[i]->type) {
8742
0
  case XML_ELEMENT_NODE:
8743
0
  case XML_ATTRIBUTE_NODE:
8744
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8745
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8746
0
      else
8747
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8748
0
        cur->nodesetval->nodeTab[i]->ns->href));
8749
0
      break;
8750
1
  default:
8751
1
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8752
1
  }
8753
1
    }
8754
1
    xmlXPathReleaseObject(ctxt->context, cur);
8755
1
}
8756
8757
/**
8758
 * xmlXPathNameFunction:
8759
 * @ctxt:  the XPath Parser context
8760
 * @nargs:  the number of arguments
8761
 *
8762
 * Implement the name() XPath function
8763
 *    string name(node-set?)
8764
 * The name function returns a string containing a QName representing
8765
 * the name of the node in the argument node-set that is first in document
8766
 * order. The QName must represent the name with respect to the namespace
8767
 * declarations in effect on the node whose name is being represented.
8768
 * Typically, this will be the form in which the name occurred in the XML
8769
 * source. This need not be the case if there are namespace declarations
8770
 * in effect on the node that associate multiple prefixes with the same
8771
 * namespace. However, an implementation may include information about
8772
 * the original prefix in its representation of nodes; in this case, an
8773
 * implementation can ensure that the returned string is always the same
8774
 * as the QName used in the XML source. If the argument it omitted it
8775
 * defaults to the context node.
8776
 * Libxml keep the original prefix so the "real qualified name" used is
8777
 * returned.
8778
 */
8779
static void
8780
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8781
26.7k
{
8782
26.7k
    xmlXPathObjectPtr cur;
8783
8784
26.7k
    if (nargs == 0) {
8785
19.1k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8786
19.1k
      ctxt->context->node));
8787
19.1k
        nargs = 1;
8788
19.1k
    }
8789
8790
79.7k
    CHECK_ARITY(1);
8791
79.7k
    if ((ctxt->value == NULL) ||
8792
26.5k
        ((ctxt->value->type != XPATH_NODESET) &&
8793
26.5k
         (ctxt->value->type != XPATH_XSLT_TREE)))
8794
21.4k
        XP_ERROR(XPATH_INVALID_TYPE);
8795
21.4k
    cur = valuePop(ctxt);
8796
8797
21.4k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8798
1.99k
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799
19.4k
    } else {
8800
19.4k
        int i = 0;              /* Should be first in document order !!!!! */
8801
8802
19.4k
        switch (cur->nodesetval->nodeTab[i]->type) {
8803
10.4k
            case XML_ELEMENT_NODE:
8804
10.4k
            case XML_ATTRIBUTE_NODE:
8805
10.4k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8806
0
        valuePush(ctxt,
8807
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8808
10.4k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8809
10.4k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8810
5.35k
        valuePush(ctxt,
8811
5.35k
            xmlXPathCacheNewString(ctxt->context,
8812
5.35k
          cur->nodesetval->nodeTab[i]->name));
8813
5.35k
    } else {
8814
5.08k
        xmlChar *fullname;
8815
8816
5.08k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8817
5.08k
             cur->nodesetval->nodeTab[i]->ns->prefix,
8818
5.08k
             NULL, 0);
8819
5.08k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8820
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8821
5.08k
        if (fullname == NULL)
8822
2
                        xmlXPathPErrMemory(ctxt, NULL);
8823
5.08k
        valuePush(ctxt, xmlXPathCacheWrapString(
8824
5.08k
      ctxt->context, fullname));
8825
5.08k
                }
8826
10.4k
                break;
8827
9.05k
            default:
8828
9.05k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8829
9.05k
        cur->nodesetval->nodeTab[i]));
8830
9.05k
                xmlXPathLocalNameFunction(ctxt, 1);
8831
19.4k
        }
8832
19.4k
    }
8833
21.4k
    xmlXPathReleaseObject(ctxt->context, cur);
8834
21.4k
}
8835
8836
8837
/**
8838
 * xmlXPathStringFunction:
8839
 * @ctxt:  the XPath Parser context
8840
 * @nargs:  the number of arguments
8841
 *
8842
 * Implement the string() XPath function
8843
 *    string string(object?)
8844
 * The string function converts an object to a string as follows:
8845
 *    - A node-set is converted to a string by returning the value of
8846
 *      the node in the node-set that is first in document order.
8847
 *      If the node-set is empty, an empty string is returned.
8848
 *    - A number is converted to a string as follows
8849
 *      + NaN is converted to the string NaN
8850
 *      + positive zero is converted to the string 0
8851
 *      + negative zero is converted to the string 0
8852
 *      + positive infinity is converted to the string Infinity
8853
 *      + negative infinity is converted to the string -Infinity
8854
 *      + if the number is an integer, the number is represented in
8855
 *        decimal form as a Number with no decimal point and no leading
8856
 *        zeros, preceded by a minus sign (-) if the number is negative
8857
 *      + otherwise, the number is represented in decimal form as a
8858
 *        Number including a decimal point with at least one digit
8859
 *        before the decimal point and at least one digit after the
8860
 *        decimal point, preceded by a minus sign (-) if the number
8861
 *        is negative; there must be no leading zeros before the decimal
8862
 *        point apart possibly from the one required digit immediately
8863
 *        before the decimal point; beyond the one required digit
8864
 *        after the decimal point there must be as many, but only as
8865
 *        many, more digits as are needed to uniquely distinguish the
8866
 *        number from all other IEEE 754 numeric values.
8867
 *    - The boolean false value is converted to the string false.
8868
 *      The boolean true value is converted to the string true.
8869
 *
8870
 * If the argument is omitted, it defaults to a node-set with the
8871
 * context node as its only member.
8872
 */
8873
void
8874
948k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8875
948k
    xmlXPathObjectPtr cur;
8876
8877
948k
    if (ctxt == NULL) return;
8878
948k
    if (nargs == 0) {
8879
8
    valuePush(ctxt,
8880
8
  xmlXPathCacheWrapString(ctxt->context,
8881
8
      xmlXPathCastNodeToString(ctxt->context->node)));
8882
8
  return;
8883
8
    }
8884
8885
3.79M
    CHECK_ARITY(1);
8886
3.79M
    cur = valuePop(ctxt);
8887
3.79M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8888
948k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8889
948k
}
8890
8891
/**
8892
 * xmlXPathStringLengthFunction:
8893
 * @ctxt:  the XPath Parser context
8894
 * @nargs:  the number of arguments
8895
 *
8896
 * Implement the string-length() XPath function
8897
 *    number string-length(string?)
8898
 * The string-length returns the number of characters in the string
8899
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8900
 * the context node converted to a string, in other words the value
8901
 * of the context node.
8902
 */
8903
void
8904
207
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905
207
    xmlXPathObjectPtr cur;
8906
8907
207
    if (nargs == 0) {
8908
22
        if ((ctxt == NULL) || (ctxt->context == NULL))
8909
0
      return;
8910
22
  if (ctxt->context->node == NULL) {
8911
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8912
22
  } else {
8913
22
      xmlChar *content;
8914
8915
22
      content = xmlXPathCastNodeToString(ctxt->context->node);
8916
22
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8917
22
    xmlUTF8Strlen(content)));
8918
22
      xmlFree(content);
8919
22
  }
8920
22
  return;
8921
22
    }
8922
740
    CHECK_ARITY(1);
8923
740
    CAST_TO_STRING;
8924
740
    CHECK_TYPE(XPATH_STRING);
8925
182
    cur = valuePop(ctxt);
8926
182
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8927
182
  xmlUTF8Strlen(cur->stringval)));
8928
182
    xmlXPathReleaseObject(ctxt->context, cur);
8929
182
}
8930
8931
/**
8932
 * xmlXPathConcatFunction:
8933
 * @ctxt:  the XPath Parser context
8934
 * @nargs:  the number of arguments
8935
 *
8936
 * Implement the concat() XPath function
8937
 *    string concat(string, string, string*)
8938
 * The concat function returns the concatenation of its arguments.
8939
 */
8940
void
8941
733
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8942
733
    xmlXPathObjectPtr cur, newobj;
8943
733
    xmlChar *tmp;
8944
8945
733
    if (ctxt == NULL) return;
8946
733
    if (nargs < 2) {
8947
79
  CHECK_ARITY(2);
8948
79
    }
8949
8950
654
    CAST_TO_STRING;
8951
654
    cur = valuePop(ctxt);
8952
654
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8953
4
  xmlXPathReleaseObject(ctxt->context, cur);
8954
4
  return;
8955
4
    }
8956
650
    nargs--;
8957
8958
2.66k
    while (nargs > 0) {
8959
2.01k
  CAST_TO_STRING;
8960
2.01k
  newobj = valuePop(ctxt);
8961
2.01k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8962
8
      xmlXPathReleaseObject(ctxt->context, newobj);
8963
8
      xmlXPathReleaseObject(ctxt->context, cur);
8964
8
      XP_ERROR(XPATH_INVALID_TYPE);
8965
0
  }
8966
2.01k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8967
2.01k
  newobj->stringval = cur->stringval;
8968
2.01k
  cur->stringval = tmp;
8969
2.01k
  xmlXPathReleaseObject(ctxt->context, newobj);
8970
2.01k
  nargs--;
8971
2.01k
    }
8972
642
    valuePush(ctxt, cur);
8973
642
}
8974
8975
/**
8976
 * xmlXPathContainsFunction:
8977
 * @ctxt:  the XPath Parser context
8978
 * @nargs:  the number of arguments
8979
 *
8980
 * Implement the contains() XPath function
8981
 *    boolean contains(string, string)
8982
 * The contains function returns true if the first argument string
8983
 * contains the second argument string, and otherwise returns false.
8984
 */
8985
void
8986
8.45k
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8987
8.45k
    xmlXPathObjectPtr hay, needle;
8988
8989
25.2k
    CHECK_ARITY(2);
8990
25.2k
    CAST_TO_STRING;
8991
25.2k
    CHECK_TYPE(XPATH_STRING);
8992
8.41k
    needle = valuePop(ctxt);
8993
8.41k
    CAST_TO_STRING;
8994
8.41k
    hay = valuePop(ctxt);
8995
8996
8.41k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8997
3
  xmlXPathReleaseObject(ctxt->context, hay);
8998
3
  xmlXPathReleaseObject(ctxt->context, needle);
8999
3
  XP_ERROR(XPATH_INVALID_TYPE);
9000
0
    }
9001
8.41k
    if (xmlStrstr(hay->stringval, needle->stringval))
9002
4.32k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9003
4.08k
    else
9004
4.08k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9005
8.41k
    xmlXPathReleaseObject(ctxt->context, hay);
9006
8.41k
    xmlXPathReleaseObject(ctxt->context, needle);
9007
8.41k
}
9008
9009
/**
9010
 * xmlXPathStartsWithFunction:
9011
 * @ctxt:  the XPath Parser context
9012
 * @nargs:  the number of arguments
9013
 *
9014
 * Implement the starts-with() XPath function
9015
 *    boolean starts-with(string, string)
9016
 * The starts-with function returns true if the first argument string
9017
 * starts with the second argument string, and otherwise returns false.
9018
 */
9019
void
9020
789
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9021
789
    xmlXPathObjectPtr hay, needle;
9022
789
    int n;
9023
9024
2.14k
    CHECK_ARITY(2);
9025
2.14k
    CAST_TO_STRING;
9026
2.14k
    CHECK_TYPE(XPATH_STRING);
9027
608
    needle = valuePop(ctxt);
9028
608
    CAST_TO_STRING;
9029
608
    hay = valuePop(ctxt);
9030
9031
608
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9032
1
  xmlXPathReleaseObject(ctxt->context, hay);
9033
1
  xmlXPathReleaseObject(ctxt->context, needle);
9034
1
  XP_ERROR(XPATH_INVALID_TYPE);
9035
0
    }
9036
607
    n = xmlStrlen(needle->stringval);
9037
607
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9038
452
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9039
155
    else
9040
155
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9041
607
    xmlXPathReleaseObject(ctxt->context, hay);
9042
607
    xmlXPathReleaseObject(ctxt->context, needle);
9043
607
}
9044
9045
/**
9046
 * xmlXPathSubstringFunction:
9047
 * @ctxt:  the XPath Parser context
9048
 * @nargs:  the number of arguments
9049
 *
9050
 * Implement the substring() XPath function
9051
 *    string substring(string, number, number?)
9052
 * The substring function returns the substring of the first argument
9053
 * starting at the position specified in the second argument with
9054
 * length specified in the third argument. For example,
9055
 * substring("12345",2,3) returns "234". If the third argument is not
9056
 * specified, it returns the substring starting at the position specified
9057
 * in the second argument and continuing to the end of the string. For
9058
 * example, substring("12345",2) returns "2345".  More precisely, each
9059
 * character in the string (see [3.6 Strings]) is considered to have a
9060
 * numeric position: the position of the first character is 1, the position
9061
 * of the second character is 2 and so on. The returned substring contains
9062
 * those characters for which the position of the character is greater than
9063
 * or equal to the second argument and, if the third argument is specified,
9064
 * less than the sum of the second and third arguments; the comparisons
9065
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9066
 *  - substring("12345", 1.5, 2.6) returns "234"
9067
 *  - substring("12345", 0, 3) returns "12"
9068
 *  - substring("12345", 0 div 0, 3) returns ""
9069
 *  - substring("12345", 1, 0 div 0) returns ""
9070
 *  - substring("12345", -42, 1 div 0) returns "12345"
9071
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9072
 */
9073
void
9074
6.27k
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9075
6.27k
    xmlXPathObjectPtr str, start, len;
9076
6.27k
    double le=0, in;
9077
6.27k
    int i = 1, j = INT_MAX;
9078
9079
6.27k
    if (nargs < 2) {
9080
67
  CHECK_ARITY(2);
9081
67
    }
9082
6.21k
    if (nargs > 3) {
9083
20
  CHECK_ARITY(3);
9084
20
    }
9085
    /*
9086
     * take care of possible last (position) argument
9087
    */
9088
6.19k
    if (nargs == 3) {
9089
1.39k
  CAST_TO_NUMBER;
9090
1.39k
  CHECK_TYPE(XPATH_NUMBER);
9091
1.39k
  len = valuePop(ctxt);
9092
1.39k
  le = len->floatval;
9093
1.39k
  xmlXPathReleaseObject(ctxt->context, len);
9094
1.39k
    }
9095
9096
6.19k
    CAST_TO_NUMBER;
9097
6.19k
    CHECK_TYPE(XPATH_NUMBER);
9098
6.19k
    start = valuePop(ctxt);
9099
6.19k
    in = start->floatval;
9100
6.19k
    xmlXPathReleaseObject(ctxt->context, start);
9101
6.19k
    CAST_TO_STRING;
9102
6.19k
    CHECK_TYPE(XPATH_STRING);
9103
6.18k
    str = valuePop(ctxt);
9104
9105
6.18k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9106
398
        i = INT_MAX;
9107
5.79k
    } else if (in >= 1.0) {
9108
4.72k
        i = (int)in;
9109
4.72k
        if (in - floor(in) >= 0.5)
9110
21
            i += 1;
9111
4.72k
    }
9112
9113
6.18k
    if (nargs == 3) {
9114
1.39k
        double rin, rle, end;
9115
9116
1.39k
        rin = floor(in);
9117
1.39k
        if (in - rin >= 0.5)
9118
28
            rin += 1.0;
9119
9120
1.39k
        rle = floor(le);
9121
1.39k
        if (le - rle >= 0.5)
9122
0
            rle += 1.0;
9123
9124
1.39k
        end = rin + rle;
9125
1.39k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9126
312
            j = 1;
9127
1.07k
        } else if (end < INT_MAX) {
9128
929
            j = (int)end;
9129
929
        }
9130
1.39k
    }
9131
9132
6.18k
    if (i < j) {
9133
5.52k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9134
5.52k
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9135
5.52k
  xmlFree(ret);
9136
5.52k
    } else {
9137
662
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9138
662
    }
9139
9140
6.18k
    xmlXPathReleaseObject(ctxt->context, str);
9141
6.18k
}
9142
9143
/**
9144
 * xmlXPathSubstringBeforeFunction:
9145
 * @ctxt:  the XPath Parser context
9146
 * @nargs:  the number of arguments
9147
 *
9148
 * Implement the substring-before() XPath function
9149
 *    string substring-before(string, string)
9150
 * The substring-before function returns the substring of the first
9151
 * argument string that precedes the first occurrence of the second
9152
 * argument string in the first argument string, or the empty string
9153
 * if the first argument string does not contain the second argument
9154
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9155
 */
9156
void
9157
2.11k
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9158
2.11k
  xmlXPathObjectPtr str;
9159
2.11k
  xmlXPathObjectPtr find;
9160
2.11k
  xmlBufPtr target;
9161
2.11k
  const xmlChar *point;
9162
2.11k
  int offset;
9163
9164
6.21k
  CHECK_ARITY(2);
9165
6.21k
  CAST_TO_STRING;
9166
6.21k
  find = valuePop(ctxt);
9167
6.21k
  CAST_TO_STRING;
9168
6.21k
  str = valuePop(ctxt);
9169
9170
6.21k
  target = xmlBufCreate();
9171
6.21k
  if (target) {
9172
2.04k
    point = xmlStrstr(str->stringval, find->stringval);
9173
2.04k
    if (point) {
9174
841
      offset = point - str->stringval;
9175
841
      xmlBufAdd(target, str->stringval, offset);
9176
841
    }
9177
2.04k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9178
2.04k
  xmlBufContent(target)));
9179
2.04k
    xmlBufFree(target);
9180
2.04k
  }
9181
6.21k
  xmlXPathReleaseObject(ctxt->context, str);
9182
6.21k
  xmlXPathReleaseObject(ctxt->context, find);
9183
6.21k
}
9184
9185
/**
9186
 * xmlXPathSubstringAfterFunction:
9187
 * @ctxt:  the XPath Parser context
9188
 * @nargs:  the number of arguments
9189
 *
9190
 * Implement the substring-after() XPath function
9191
 *    string substring-after(string, string)
9192
 * The substring-after function returns the substring of the first
9193
 * argument string that follows the first occurrence of the second
9194
 * argument string in the first argument string, or the empty stringi
9195
 * if the first argument string does not contain the second argument
9196
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9197
 * and substring-after("1999/04/01","19") returns 99/04/01.
9198
 */
9199
void
9200
2.63k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9201
2.63k
  xmlXPathObjectPtr str;
9202
2.63k
  xmlXPathObjectPtr find;
9203
2.63k
  xmlBufPtr target;
9204
2.63k
  const xmlChar *point;
9205
2.63k
  int offset;
9206
9207
7.82k
  CHECK_ARITY(2);
9208
7.82k
  CAST_TO_STRING;
9209
7.82k
  find = valuePop(ctxt);
9210
7.82k
  CAST_TO_STRING;
9211
7.82k
  str = valuePop(ctxt);
9212
9213
7.82k
  target = xmlBufCreate();
9214
7.82k
  if (target) {
9215
2.59k
    point = xmlStrstr(str->stringval, find->stringval);
9216
2.59k
    if (point) {
9217
836
      offset = point - str->stringval + xmlStrlen(find->stringval);
9218
836
      xmlBufAdd(target, &str->stringval[offset],
9219
836
       xmlStrlen(str->stringval) - offset);
9220
836
    }
9221
2.59k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9222
2.59k
  xmlBufContent(target)));
9223
2.59k
    xmlBufFree(target);
9224
2.59k
  }
9225
7.82k
  xmlXPathReleaseObject(ctxt->context, str);
9226
7.82k
  xmlXPathReleaseObject(ctxt->context, find);
9227
7.82k
}
9228
9229
/**
9230
 * xmlXPathNormalizeFunction:
9231
 * @ctxt:  the XPath Parser context
9232
 * @nargs:  the number of arguments
9233
 *
9234
 * Implement the normalize-space() XPath function
9235
 *    string normalize-space(string?)
9236
 * The normalize-space function returns the argument string with white
9237
 * space normalized by stripping leading and trailing whitespace
9238
 * and replacing sequences of whitespace characters by a single
9239
 * space. Whitespace characters are the same allowed by the S production
9240
 * in XML. If the argument is omitted, it defaults to the context
9241
 * node converted to a string, in other words the value of the context node.
9242
 */
9243
void
9244
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245
0
    xmlChar *source, *target;
9246
0
    int blank;
9247
9248
0
    if (ctxt == NULL) return;
9249
0
    if (nargs == 0) {
9250
        /* Use current context node */
9251
0
        valuePush(ctxt,
9252
0
            xmlXPathCacheWrapString(ctxt->context,
9253
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9254
0
        nargs = 1;
9255
0
    }
9256
9257
0
    CHECK_ARITY(1);
9258
0
    CAST_TO_STRING;
9259
0
    CHECK_TYPE(XPATH_STRING);
9260
0
    source = ctxt->value->stringval;
9261
0
    if (source == NULL)
9262
0
        return;
9263
0
    target = source;
9264
9265
    /* Skip leading whitespaces */
9266
0
    while (IS_BLANK_CH(*source))
9267
0
        source++;
9268
9269
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9270
0
    blank = 0;
9271
0
    while (*source) {
9272
0
        if (IS_BLANK_CH(*source)) {
9273
0
      blank = 1;
9274
0
        } else {
9275
0
            if (blank) {
9276
0
                *target++ = 0x20;
9277
0
                blank = 0;
9278
0
            }
9279
0
            *target++ = *source;
9280
0
        }
9281
0
        source++;
9282
0
    }
9283
0
    *target = 0;
9284
0
}
9285
9286
/**
9287
 * xmlXPathTranslateFunction:
9288
 * @ctxt:  the XPath Parser context
9289
 * @nargs:  the number of arguments
9290
 *
9291
 * Implement the translate() XPath function
9292
 *    string translate(string, string, string)
9293
 * The translate function returns the first argument string with
9294
 * occurrences of characters in the second argument string replaced
9295
 * by the character at the corresponding position in the third argument
9296
 * string. For example, translate("bar","abc","ABC") returns the string
9297
 * BAr. If there is a character in the second argument string with no
9298
 * character at a corresponding position in the third argument string
9299
 * (because the second argument string is longer than the third argument
9300
 * string), then occurrences of that character in the first argument
9301
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9302
 * returns "AAA". If a character occurs more than once in second
9303
 * argument string, then the first occurrence determines the replacement
9304
 * character. If the third argument string is longer than the second
9305
 * argument string, then excess characters are ignored.
9306
 */
9307
void
9308
728
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9309
728
    xmlXPathObjectPtr str;
9310
728
    xmlXPathObjectPtr from;
9311
728
    xmlXPathObjectPtr to;
9312
728
    xmlBufPtr target;
9313
728
    int offset, max;
9314
728
    int ch;
9315
728
    const xmlChar *point;
9316
728
    xmlChar *cptr;
9317
9318
1.70k
    CHECK_ARITY(3);
9319
9320
1.70k
    CAST_TO_STRING;
9321
1.70k
    to = valuePop(ctxt);
9322
1.70k
    CAST_TO_STRING;
9323
1.70k
    from = valuePop(ctxt);
9324
1.70k
    CAST_TO_STRING;
9325
1.70k
    str = valuePop(ctxt);
9326
9327
1.70k
    target = xmlBufCreate();
9328
1.70k
    if (target) {
9329
485
  max = xmlUTF8Strlen(to->stringval);
9330
1.61M
  for (cptr = str->stringval; (ch=*cptr); ) {
9331
1.61M
      offset = xmlUTF8Strloc(from->stringval, cptr);
9332
1.61M
      if (offset >= 0) {
9333
4.74k
    if (offset < max) {
9334
3.22k
        point = xmlUTF8Strpos(to->stringval, offset);
9335
3.22k
        if (point)
9336
3.22k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9337
3.22k
    }
9338
4.74k
      } else
9339
1.61M
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9340
9341
      /* Step to next character in input */
9342
1.61M
      cptr++;
9343
1.61M
      if ( ch & 0x80 ) {
9344
    /* if not simple ascii, verify proper format */
9345
620k
    if ( (ch & 0xc0) != 0xc0 ) {
9346
14
        xmlGenericError(xmlGenericErrorContext,
9347
14
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9348
                    /* not asserting an XPath error is probably better */
9349
14
        break;
9350
14
    }
9351
    /* then skip over remaining bytes for this char */
9352
1.86M
    while ( (ch <<= 1) & 0x80 )
9353
1.24M
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9354
0
      xmlGenericError(xmlGenericErrorContext,
9355
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9356
                        /* not asserting an XPath error is probably better */
9357
0
      break;
9358
0
        }
9359
620k
    if (ch & 0x80) /* must have had error encountered */
9360
0
        break;
9361
620k
      }
9362
1.61M
  }
9363
485
    }
9364
1.70k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9365
1.70k
  xmlBufContent(target)));
9366
1.70k
    xmlBufFree(target);
9367
1.70k
    xmlXPathReleaseObject(ctxt->context, str);
9368
1.70k
    xmlXPathReleaseObject(ctxt->context, from);
9369
1.70k
    xmlXPathReleaseObject(ctxt->context, to);
9370
1.70k
}
9371
9372
/**
9373
 * xmlXPathBooleanFunction:
9374
 * @ctxt:  the XPath Parser context
9375
 * @nargs:  the number of arguments
9376
 *
9377
 * Implement the boolean() XPath function
9378
 *    boolean boolean(object)
9379
 * The boolean function converts its argument to a boolean as follows:
9380
 *    - a number is true if and only if it is neither positive or
9381
 *      negative zero nor NaN
9382
 *    - a node-set is true if and only if it is non-empty
9383
 *    - a string is true if and only if its length is non-zero
9384
 */
9385
void
9386
308k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9387
308k
    xmlXPathObjectPtr cur;
9388
9389
926k
    CHECK_ARITY(1);
9390
926k
    cur = valuePop(ctxt);
9391
926k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9392
308k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9393
308k
    valuePush(ctxt, cur);
9394
308k
}
9395
9396
/**
9397
 * xmlXPathNotFunction:
9398
 * @ctxt:  the XPath Parser context
9399
 * @nargs:  the number of arguments
9400
 *
9401
 * Implement the not() XPath function
9402
 *    boolean not(boolean)
9403
 * The not function returns true if its argument is false,
9404
 * and false otherwise.
9405
 */
9406
void
9407
802
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9408
2.40k
    CHECK_ARITY(1);
9409
2.40k
    CAST_TO_BOOLEAN;
9410
2.40k
    CHECK_TYPE(XPATH_BOOLEAN);
9411
801
    ctxt->value->boolval = ! ctxt->value->boolval;
9412
801
}
9413
9414
/**
9415
 * xmlXPathTrueFunction:
9416
 * @ctxt:  the XPath Parser context
9417
 * @nargs:  the number of arguments
9418
 *
9419
 * Implement the true() XPath function
9420
 *    boolean true()
9421
 */
9422
void
9423
401
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9424
1.20k
    CHECK_ARITY(0);
9425
1.20k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9426
1.20k
}
9427
9428
/**
9429
 * xmlXPathFalseFunction:
9430
 * @ctxt:  the XPath Parser context
9431
 * @nargs:  the number of arguments
9432
 *
9433
 * Implement the false() XPath function
9434
 *    boolean false()
9435
 */
9436
void
9437
87
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438
241
    CHECK_ARITY(0);
9439
241
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9440
241
}
9441
9442
/**
9443
 * xmlXPathLangFunction:
9444
 * @ctxt:  the XPath Parser context
9445
 * @nargs:  the number of arguments
9446
 *
9447
 * Implement the lang() XPath function
9448
 *    boolean lang(string)
9449
 * The lang function returns true or false depending on whether the
9450
 * language of the context node as specified by xml:lang attributes
9451
 * is the same as or is a sublanguage of the language specified by
9452
 * the argument string. The language of the context node is determined
9453
 * by the value of the xml:lang attribute on the context node, or, if
9454
 * the context node has no xml:lang attribute, by the value of the
9455
 * xml:lang attribute on the nearest ancestor of the context node that
9456
 * has an xml:lang attribute. If there is no such attribute, then lang
9457
 * returns false. If there is such an attribute, then lang returns
9458
 * true if the attribute value is equal to the argument ignoring case,
9459
 * or if there is some suffix starting with - such that the attribute
9460
 * value is equal to the argument ignoring that suffix of the attribute
9461
 * value and ignoring case.
9462
 */
9463
void
9464
1.21k
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9465
1.21k
    xmlXPathObjectPtr val = NULL;
9466
1.21k
    const xmlChar *theLang = NULL;
9467
1.21k
    const xmlChar *lang;
9468
1.21k
    int ret = 0;
9469
1.21k
    int i;
9470
9471
3.23k
    CHECK_ARITY(1);
9472
3.23k
    CAST_TO_STRING;
9473
3.23k
    CHECK_TYPE(XPATH_STRING);
9474
851
    val = valuePop(ctxt);
9475
851
    lang = val->stringval;
9476
851
    theLang = xmlNodeGetLang(ctxt->context->node);
9477
851
    if ((theLang != NULL) && (lang != NULL)) {
9478
0
        for (i = 0;lang[i] != 0;i++)
9479
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9480
0
          goto not_equal;
9481
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9482
0
      ret = 1;
9483
0
    }
9484
851
not_equal:
9485
851
    if (theLang != NULL)
9486
0
  xmlFree((void *)theLang);
9487
9488
851
    xmlXPathReleaseObject(ctxt->context, val);
9489
851
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9490
851
}
9491
9492
/**
9493
 * xmlXPathNumberFunction:
9494
 * @ctxt:  the XPath Parser context
9495
 * @nargs:  the number of arguments
9496
 *
9497
 * Implement the number() XPath function
9498
 *    number number(object?)
9499
 */
9500
void
9501
3.55M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9502
3.55M
    xmlXPathObjectPtr cur;
9503
3.55M
    double res;
9504
9505
3.55M
    if (ctxt == NULL) return;
9506
3.55M
    if (nargs == 0) {
9507
273
  if (ctxt->context->node == NULL) {
9508
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9509
273
  } else {
9510
273
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9511
9512
273
      res = xmlXPathStringEvalNumber(content);
9513
273
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9514
273
      xmlFree(content);
9515
273
  }
9516
273
  return;
9517
273
    }
9518
9519
14.2M
    CHECK_ARITY(1);
9520
14.2M
    cur = valuePop(ctxt);
9521
14.2M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9522
14.2M
}
9523
9524
/**
9525
 * xmlXPathSumFunction:
9526
 * @ctxt:  the XPath Parser context
9527
 * @nargs:  the number of arguments
9528
 *
9529
 * Implement the sum() XPath function
9530
 *    number sum(node-set)
9531
 * The sum function returns the sum of the values of the nodes in
9532
 * the argument node-set.
9533
 */
9534
void
9535
665
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9536
665
    xmlXPathObjectPtr cur;
9537
665
    int i;
9538
665
    double res = 0.0;
9539
9540
1.99k
    CHECK_ARITY(1);
9541
1.99k
    if ((ctxt->value == NULL) ||
9542
665
  ((ctxt->value->type != XPATH_NODESET) &&
9543
665
   (ctxt->value->type != XPATH_XSLT_TREE)))
9544
665
  XP_ERROR(XPATH_INVALID_TYPE);
9545
665
    cur = valuePop(ctxt);
9546
9547
665
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9548
448
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9549
301
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9550
301
  }
9551
147
    }
9552
665
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9553
665
    xmlXPathReleaseObject(ctxt->context, cur);
9554
665
}
9555
9556
/**
9557
 * xmlXPathFloorFunction:
9558
 * @ctxt:  the XPath Parser context
9559
 * @nargs:  the number of arguments
9560
 *
9561
 * Implement the floor() XPath function
9562
 *    number floor(number)
9563
 * The floor function returns the largest (closest to positive infinity)
9564
 * number that is not greater than the argument and that is an integer.
9565
 */
9566
void
9567
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9568
0
    CHECK_ARITY(1);
9569
0
    CAST_TO_NUMBER;
9570
0
    CHECK_TYPE(XPATH_NUMBER);
9571
9572
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9573
0
}
9574
9575
/**
9576
 * xmlXPathCeilingFunction:
9577
 * @ctxt:  the XPath Parser context
9578
 * @nargs:  the number of arguments
9579
 *
9580
 * Implement the ceiling() XPath function
9581
 *    number ceiling(number)
9582
 * The ceiling function returns the smallest (closest to negative infinity)
9583
 * number that is not less than the argument and that is an integer.
9584
 */
9585
void
9586
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9587
0
    CHECK_ARITY(1);
9588
0
    CAST_TO_NUMBER;
9589
0
    CHECK_TYPE(XPATH_NUMBER);
9590
9591
#ifdef _AIX
9592
    /* Work around buggy ceil() function on AIX */
9593
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9594
#else
9595
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9596
0
#endif
9597
0
}
9598
9599
/**
9600
 * xmlXPathRoundFunction:
9601
 * @ctxt:  the XPath Parser context
9602
 * @nargs:  the number of arguments
9603
 *
9604
 * Implement the round() XPath function
9605
 *    number round(number)
9606
 * The round function returns the number that is closest to the
9607
 * argument and that is an integer. If there are two such numbers,
9608
 * then the one that is closest to positive infinity is returned.
9609
 */
9610
void
9611
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612
0
    double f;
9613
9614
0
    CHECK_ARITY(1);
9615
0
    CAST_TO_NUMBER;
9616
0
    CHECK_TYPE(XPATH_NUMBER);
9617
9618
0
    f = ctxt->value->floatval;
9619
9620
0
    if ((f >= -0.5) && (f < 0.5)) {
9621
        /* Handles negative zero. */
9622
0
        ctxt->value->floatval *= 0.0;
9623
0
    }
9624
0
    else {
9625
0
        double rounded = floor(f);
9626
0
        if (f - rounded >= 0.5)
9627
0
            rounded += 1.0;
9628
0
        ctxt->value->floatval = rounded;
9629
0
    }
9630
0
}
9631
9632
/************************************************************************
9633
 *                  *
9634
 *      The Parser          *
9635
 *                  *
9636
 ************************************************************************/
9637
9638
/*
9639
 * a few forward declarations since we use a recursive call based
9640
 * implementation.
9641
 */
9642
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9643
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9644
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9645
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9646
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9647
                                    int qualified);
9648
9649
/**
9650
 * xmlXPathCurrentChar:
9651
 * @ctxt:  the XPath parser context
9652
 * @cur:  pointer to the beginning of the char
9653
 * @len:  pointer to the length of the char read
9654
 *
9655
 * The current char value, if using UTF-8 this may actually span multiple
9656
 * bytes in the input buffer.
9657
 *
9658
 * Returns the current char value and its length
9659
 */
9660
9661
static int
9662
58.9M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9663
58.9M
    unsigned char c;
9664
58.9M
    unsigned int val;
9665
58.9M
    const xmlChar *cur;
9666
9667
58.9M
    if (ctxt == NULL)
9668
0
  return(0);
9669
58.9M
    cur = ctxt->cur;
9670
9671
    /*
9672
     * We are supposed to handle UTF8, check it's valid
9673
     * From rfc2044: encoding of the Unicode values on UTF-8:
9674
     *
9675
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9676
     * 0000 0000-0000 007F   0xxxxxxx
9677
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9678
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9679
     *
9680
     * Check for the 0x110000 limit too
9681
     */
9682
58.9M
    c = *cur;
9683
58.9M
    if (c & 0x80) {
9684
2.75M
  if ((cur[1] & 0xc0) != 0x80)
9685
2.64k
      goto encoding_error;
9686
2.74M
  if ((c & 0xe0) == 0xe0) {
9687
9688
367k
      if ((cur[2] & 0xc0) != 0x80)
9689
0
    goto encoding_error;
9690
367k
      if ((c & 0xf0) == 0xf0) {
9691
9.68k
    if (((c & 0xf8) != 0xf0) ||
9692
9.68k
        ((cur[3] & 0xc0) != 0x80))
9693
0
        goto encoding_error;
9694
    /* 4-byte code */
9695
9.68k
    *len = 4;
9696
9.68k
    val = (cur[0] & 0x7) << 18;
9697
9.68k
    val |= (cur[1] & 0x3f) << 12;
9698
9.68k
    val |= (cur[2] & 0x3f) << 6;
9699
9.68k
    val |= cur[3] & 0x3f;
9700
357k
      } else {
9701
        /* 3-byte code */
9702
357k
    *len = 3;
9703
357k
    val = (cur[0] & 0xf) << 12;
9704
357k
    val |= (cur[1] & 0x3f) << 6;
9705
357k
    val |= cur[2] & 0x3f;
9706
357k
      }
9707
2.38M
  } else {
9708
    /* 2-byte code */
9709
2.38M
      *len = 2;
9710
2.38M
      val = (cur[0] & 0x1f) << 6;
9711
2.38M
      val |= cur[1] & 0x3f;
9712
2.38M
  }
9713
2.74M
  if (!IS_CHAR(val)) {
9714
1
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9715
0
  }
9716
2.74M
  return(val);
9717
56.1M
    } else {
9718
  /* 1-byte code */
9719
56.1M
  *len = 1;
9720
56.1M
  return(*cur);
9721
56.1M
    }
9722
2.64k
encoding_error:
9723
    /*
9724
     * If we detect an UTF8 error that probably means that the
9725
     * input encoding didn't get properly advertised in the
9726
     * declaration header. Report the error and switch the encoding
9727
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9728
     * encoding !)
9729
     */
9730
2.64k
    *len = 0;
9731
2.64k
    XP_ERROR0(XPATH_ENCODING_ERROR);
9732
0
}
9733
9734
/**
9735
 * xmlXPathParseNCName:
9736
 * @ctxt:  the XPath Parser context
9737
 *
9738
 * parse an XML namespace non qualified name.
9739
 *
9740
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9741
 *
9742
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9743
 *                       CombiningChar | Extender
9744
 *
9745
 * Returns the namespace name or NULL
9746
 */
9747
9748
xmlChar *
9749
9.26M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9750
9.26M
    const xmlChar *in;
9751
9.26M
    xmlChar *ret;
9752
9.26M
    int count = 0;
9753
9754
9.26M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9755
    /*
9756
     * Accelerator for simple ASCII names
9757
     */
9758
9.26M
    in = ctxt->cur;
9759
9.26M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9760
9.26M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9761
9.26M
  (*in == '_')) {
9762
9.02M
  in++;
9763
35.4M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9764
35.4M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9765
35.4M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9766
35.4M
         (*in == '_') || (*in == '.') ||
9767
35.4M
         (*in == '-'))
9768
26.4M
      in++;
9769
9.02M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9770
9.02M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9771
9.02M
            (*in == '@') || (*in == '*')) {
9772
2.47M
      count = in - ctxt->cur;
9773
2.47M
      if (count == 0)
9774
0
    return(NULL);
9775
2.47M
      ret = xmlStrndup(ctxt->cur, count);
9776
2.47M
      ctxt->cur = in;
9777
2.47M
      return(ret);
9778
2.47M
  }
9779
9.02M
    }
9780
6.79M
    return(xmlXPathParseNameComplex(ctxt, 0));
9781
9.26M
}
9782
9783
9784
/**
9785
 * xmlXPathParseQName:
9786
 * @ctxt:  the XPath Parser context
9787
 * @prefix:  a xmlChar **
9788
 *
9789
 * parse an XML qualified name
9790
 *
9791
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9792
 *
9793
 * [NS 6] Prefix ::= NCName
9794
 *
9795
 * [NS 7] LocalPart ::= NCName
9796
 *
9797
 * Returns the function returns the local part, and prefix is updated
9798
 *   to get the Prefix if any.
9799
 */
9800
9801
static xmlChar *
9802
1.16M
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9803
1.16M
    xmlChar *ret = NULL;
9804
9805
1.16M
    *prefix = NULL;
9806
1.16M
    ret = xmlXPathParseNCName(ctxt);
9807
1.16M
    if (ret && CUR == ':') {
9808
900k
        *prefix = ret;
9809
900k
  NEXT;
9810
900k
  ret = xmlXPathParseNCName(ctxt);
9811
900k
    }
9812
1.16M
    return(ret);
9813
1.16M
}
9814
9815
/**
9816
 * xmlXPathParseName:
9817
 * @ctxt:  the XPath Parser context
9818
 *
9819
 * parse an XML name
9820
 *
9821
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9822
 *                  CombiningChar | Extender
9823
 *
9824
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9825
 *
9826
 * Returns the namespace name or NULL
9827
 */
9828
9829
xmlChar *
9830
21.8k
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9831
21.8k
    const xmlChar *in;
9832
21.8k
    xmlChar *ret;
9833
21.8k
    size_t count = 0;
9834
9835
21.8k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9836
    /*
9837
     * Accelerator for simple ASCII names
9838
     */
9839
21.8k
    in = ctxt->cur;
9840
21.8k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9841
21.8k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9842
21.8k
  (*in == '_') || (*in == ':')) {
9843
19.2k
  in++;
9844
6.49M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9845
6.49M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9846
6.49M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9847
6.49M
         (*in == '_') || (*in == '-') ||
9848
6.49M
         (*in == ':') || (*in == '.'))
9849
6.47M
      in++;
9850
19.2k
  if ((*in > 0) && (*in < 0x80)) {
9851
16.8k
      count = in - ctxt->cur;
9852
16.8k
            if (count > XML_MAX_NAME_LENGTH) {
9853
65
                ctxt->cur = in;
9854
65
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9855
0
            }
9856
16.7k
      ret = xmlStrndup(ctxt->cur, count);
9857
16.7k
      ctxt->cur = in;
9858
16.7k
      return(ret);
9859
16.8k
  }
9860
19.2k
    }
9861
5.05k
    return(xmlXPathParseNameComplex(ctxt, 1));
9862
21.8k
}
9863
9864
static xmlChar *
9865
6.79M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9866
6.79M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9867
6.79M
    int len = 0, l;
9868
6.79M
    int c;
9869
9870
    /*
9871
     * Handler for more complex cases
9872
     */
9873
6.79M
    c = CUR_CHAR(l);
9874
6.79M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9875
6.79M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9876
6.79M
        (c == '*') || /* accelerators */
9877
6.79M
  (!IS_LETTER(c) && (c != '_') &&
9878
6.68M
         ((!qualified) || (c != ':')))) {
9879
180k
  return(NULL);
9880
180k
    }
9881
9882
21.5M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9883
21.5M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9884
21.4M
            (c == '.') || (c == '-') ||
9885
21.4M
      (c == '_') || ((qualified) && (c == ':')) ||
9886
21.4M
      (IS_COMBINING(c)) ||
9887
21.4M
      (IS_EXTENDER(c)))) {
9888
14.9M
  COPY_BUF(l,buf,len,c);
9889
14.9M
  NEXTL(l);
9890
14.9M
  c = CUR_CHAR(l);
9891
14.9M
  if (len >= XML_MAX_NAMELEN) {
9892
      /*
9893
       * Okay someone managed to make a huge name, so he's ready to pay
9894
       * for the processing speed.
9895
       */
9896
6.40k
      xmlChar *buffer;
9897
6.40k
      int max = len * 2;
9898
9899
6.40k
            if (len > XML_MAX_NAME_LENGTH) {
9900
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9901
0
            }
9902
6.40k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9903
6.40k
      if (buffer == NULL) {
9904
3
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9905
0
      }
9906
6.40k
      memcpy(buffer, buf, len);
9907
4.83M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9908
4.83M
       (c == '.') || (c == '-') ||
9909
4.83M
       (c == '_') || ((qualified) && (c == ':')) ||
9910
4.83M
       (IS_COMBINING(c)) ||
9911
4.83M
       (IS_EXTENDER(c))) {
9912
4.82M
    if (len + 10 > max) {
9913
2.28k
                    xmlChar *tmp;
9914
2.28k
                    if (max > XML_MAX_NAME_LENGTH) {
9915
128
                        xmlFree(buffer);
9916
128
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9917
0
                    }
9918
2.15k
        max *= 2;
9919
2.15k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9920
2.15k
        if (tmp == NULL) {
9921
1
                        xmlFree(buffer);
9922
1
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9923
0
        }
9924
2.15k
                    buffer = tmp;
9925
2.15k
    }
9926
4.82M
    COPY_BUF(l,buffer,len,c);
9927
4.82M
    NEXTL(l);
9928
4.82M
    c = CUR_CHAR(l);
9929
4.82M
      }
9930
6.27k
      buffer[len] = 0;
9931
6.27k
      return(buffer);
9932
6.40k
  }
9933
14.9M
    }
9934
6.60M
    if (len == 0)
9935
0
  return(NULL);
9936
6.60M
    return(xmlStrndup(buf, len));
9937
6.60M
}
9938
9939
185k
#define MAX_FRAC 20
9940
9941
/**
9942
 * xmlXPathStringEvalNumber:
9943
 * @str:  A string to scan
9944
 *
9945
 *  [30a]  Float  ::= Number ('e' Digits?)?
9946
 *
9947
 *  [30]   Number ::=   Digits ('.' Digits?)?
9948
 *                    | '.' Digits
9949
 *  [31]   Digits ::=   [0-9]+
9950
 *
9951
 * Compile a Number in the string
9952
 * In complement of the Number expression, this function also handles
9953
 * negative values : '-' Number.
9954
 *
9955
 * Returns the double value.
9956
 */
9957
double
9958
3.73M
xmlXPathStringEvalNumber(const xmlChar *str) {
9959
3.73M
    const xmlChar *cur = str;
9960
3.73M
    double ret;
9961
3.73M
    int ok = 0;
9962
3.73M
    int isneg = 0;
9963
3.73M
    int exponent = 0;
9964
3.73M
    int is_exponent_negative = 0;
9965
3.73M
#ifdef __GNUC__
9966
3.73M
    unsigned long tmp = 0;
9967
3.73M
    double temp;
9968
3.73M
#endif
9969
3.73M
    if (cur == NULL) return(0);
9970
3.73M
    while (IS_BLANK_CH(*cur)) cur++;
9971
3.73M
    if (*cur == '-') {
9972
27.7k
  isneg = 1;
9973
27.7k
  cur++;
9974
27.7k
    }
9975
3.73M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9976
3.43M
        return(xmlXPathNAN);
9977
3.43M
    }
9978
9979
297k
#ifdef __GNUC__
9980
    /*
9981
     * tmp/temp is a workaround against a gcc compiler bug
9982
     * http://veillard.com/gcc.bug
9983
     */
9984
297k
    ret = 0;
9985
430k
    while ((*cur >= '0') && (*cur <= '9')) {
9986
132k
  ret = ret * 10;
9987
132k
  tmp = (*cur - '0');
9988
132k
  ok = 1;
9989
132k
  cur++;
9990
132k
  temp = (double) tmp;
9991
132k
  ret = ret + temp;
9992
132k
    }
9993
#else
9994
    ret = 0;
9995
    while ((*cur >= '0') && (*cur <= '9')) {
9996
  ret = ret * 10 + (*cur - '0');
9997
  ok = 1;
9998
  cur++;
9999
    }
10000
#endif
10001
10002
297k
    if (*cur == '.') {
10003
253k
  int v, frac = 0, max;
10004
253k
  double fraction = 0;
10005
10006
253k
        cur++;
10007
253k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10008
234k
      return(xmlXPathNAN);
10009
234k
  }
10010
25.7k
        while (*cur == '0') {
10011
6.73k
      frac = frac + 1;
10012
6.73k
      cur++;
10013
6.73k
        }
10014
19.0k
        max = frac + MAX_FRAC;
10015
46.7k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10016
27.7k
      v = (*cur - '0');
10017
27.7k
      fraction = fraction * 10 + v;
10018
27.7k
      frac = frac + 1;
10019
27.7k
      cur++;
10020
27.7k
  }
10021
19.0k
  fraction /= pow(10.0, frac);
10022
19.0k
  ret = ret + fraction;
10023
19.3k
  while ((*cur >= '0') && (*cur <= '9'))
10024
296
      cur++;
10025
19.0k
    }
10026
63.1k
    if ((*cur == 'e') || (*cur == 'E')) {
10027
14.1k
      cur++;
10028
14.1k
      if (*cur == '-') {
10029
279
  is_exponent_negative = 1;
10030
279
  cur++;
10031
13.8k
      } else if (*cur == '+') {
10032
554
        cur++;
10033
554
      }
10034
102k
      while ((*cur >= '0') && (*cur <= '9')) {
10035
88.2k
        if (exponent < 1000000)
10036
70.2k
    exponent = exponent * 10 + (*cur - '0');
10037
88.2k
  cur++;
10038
88.2k
      }
10039
14.1k
    }
10040
63.1k
    while (IS_BLANK_CH(*cur)) cur++;
10041
63.1k
    if (*cur != 0) return(xmlXPathNAN);
10042
32.0k
    if (isneg) ret = -ret;
10043
32.0k
    if (is_exponent_negative) exponent = -exponent;
10044
32.0k
    ret *= pow(10.0, (double)exponent);
10045
32.0k
    return(ret);
10046
63.1k
}
10047
10048
/**
10049
 * xmlXPathCompNumber:
10050
 * @ctxt:  the XPath Parser context
10051
 *
10052
 *  [30]   Number ::=   Digits ('.' Digits?)?
10053
 *                    | '.' Digits
10054
 *  [31]   Digits ::=   [0-9]+
10055
 *
10056
 * Compile a Number, then push it on the stack
10057
 *
10058
 */
10059
static void
10060
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10061
973k
{
10062
973k
    double ret = 0.0;
10063
973k
    int ok = 0;
10064
973k
    int exponent = 0;
10065
973k
    int is_exponent_negative = 0;
10066
973k
    xmlXPathObjectPtr num;
10067
973k
#ifdef __GNUC__
10068
973k
    unsigned long tmp = 0;
10069
973k
    double temp;
10070
973k
#endif
10071
10072
973k
    CHECK_ERROR;
10073
973k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10074
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10075
0
    }
10076
973k
#ifdef __GNUC__
10077
    /*
10078
     * tmp/temp is a workaround against a gcc compiler bug
10079
     * http://veillard.com/gcc.bug
10080
     */
10081
973k
    ret = 0;
10082
2.85M
    while ((CUR >= '0') && (CUR <= '9')) {
10083
1.88M
  ret = ret * 10;
10084
1.88M
  tmp = (CUR - '0');
10085
1.88M
        ok = 1;
10086
1.88M
        NEXT;
10087
1.88M
  temp = (double) tmp;
10088
1.88M
  ret = ret + temp;
10089
1.88M
    }
10090
#else
10091
    ret = 0;
10092
    while ((CUR >= '0') && (CUR <= '9')) {
10093
  ret = ret * 10 + (CUR - '0');
10094
  ok = 1;
10095
  NEXT;
10096
    }
10097
#endif
10098
973k
    if (CUR == '.') {
10099
166k
  int v, frac = 0, max;
10100
166k
  double fraction = 0;
10101
10102
166k
        NEXT;
10103
166k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10104
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10105
0
        }
10106
241k
        while (CUR == '0') {
10107
74.4k
            frac = frac + 1;
10108
74.4k
            NEXT;
10109
74.4k
        }
10110
166k
        max = frac + MAX_FRAC;
10111
465k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10112
298k
      v = (CUR - '0');
10113
298k
      fraction = fraction * 10 + v;
10114
298k
      frac = frac + 1;
10115
298k
            NEXT;
10116
298k
        }
10117
166k
        fraction /= pow(10.0, frac);
10118
166k
        ret = ret + fraction;
10119
167k
        while ((CUR >= '0') && (CUR <= '9'))
10120
377
            NEXT;
10121
166k
    }
10122
973k
    if ((CUR == 'e') || (CUR == 'E')) {
10123
63.5k
        NEXT;
10124
63.5k
        if (CUR == '-') {
10125
574
            is_exponent_negative = 1;
10126
574
            NEXT;
10127
62.9k
        } else if (CUR == '+') {
10128
727
      NEXT;
10129
727
  }
10130
328k
        while ((CUR >= '0') && (CUR <= '9')) {
10131
265k
            if (exponent < 1000000)
10132
237k
                exponent = exponent * 10 + (CUR - '0');
10133
265k
            NEXT;
10134
265k
        }
10135
63.5k
        if (is_exponent_negative)
10136
574
            exponent = -exponent;
10137
63.5k
        ret *= pow(10.0, (double) exponent);
10138
63.5k
    }
10139
973k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10140
973k
    if (num == NULL) {
10141
21
  ctxt->error = XPATH_MEMORY_ERROR;
10142
973k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10143
973k
                              NULL) == -1) {
10144
7
        xmlXPathReleaseObject(ctxt->context, num);
10145
7
    }
10146
973k
}
10147
10148
/**
10149
 * xmlXPathParseLiteral:
10150
 * @ctxt:  the XPath Parser context
10151
 *
10152
 * Parse a Literal
10153
 *
10154
 *  [29]   Literal ::=   '"' [^"]* '"'
10155
 *                    | "'" [^']* "'"
10156
 *
10157
 * Returns the value found or NULL in case of error
10158
 */
10159
static xmlChar *
10160
2.26k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10161
2.26k
    const xmlChar *q;
10162
2.26k
    xmlChar *ret = NULL;
10163
10164
2.26k
    if (CUR == '"') {
10165
1.41k
        NEXT;
10166
1.41k
  q = CUR_PTR;
10167
54.9k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10168
53.5k
      NEXT;
10169
1.41k
  if (!IS_CHAR_CH(CUR)) {
10170
423
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10171
994
  } else {
10172
994
      ret = xmlStrndup(q, CUR_PTR - q);
10173
994
      NEXT;
10174
994
        }
10175
1.41k
    } else if (CUR == '\'') {
10176
492
        NEXT;
10177
492
  q = CUR_PTR;
10178
29.0k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10179
28.5k
      NEXT;
10180
492
  if (!IS_CHAR_CH(CUR)) {
10181
302
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10182
190
  } else {
10183
190
      ret = xmlStrndup(q, CUR_PTR - q);
10184
190
      NEXT;
10185
190
        }
10186
492
    } else {
10187
359
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10188
0
    }
10189
1.18k
    return(ret);
10190
2.26k
}
10191
10192
/**
10193
 * xmlXPathCompLiteral:
10194
 * @ctxt:  the XPath Parser context
10195
 *
10196
 * Parse a Literal and push it on the stack.
10197
 *
10198
 *  [29]   Literal ::=   '"' [^"]* '"'
10199
 *                    | "'" [^']* "'"
10200
 *
10201
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10202
 */
10203
static void
10204
250k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10205
250k
    const xmlChar *q;
10206
250k
    xmlChar *ret = NULL;
10207
250k
    xmlXPathObjectPtr lit;
10208
10209
250k
    if (CUR == '"') {
10210
143k
        NEXT;
10211
143k
  q = CUR_PTR;
10212
473k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10213
329k
      NEXT;
10214
143k
  if (!IS_CHAR_CH(CUR)) {
10215
6.17k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10216
137k
  } else {
10217
137k
      ret = xmlStrndup(q, CUR_PTR - q);
10218
137k
      NEXT;
10219
137k
        }
10220
143k
    } else if (CUR == '\'') {
10221
107k
        NEXT;
10222
107k
  q = CUR_PTR;
10223
4.81M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10224
4.70M
      NEXT;
10225
107k
  if (!IS_CHAR_CH(CUR)) {
10226
6.47k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10227
101k
  } else {
10228
101k
      ret = xmlStrndup(q, CUR_PTR - q);
10229
101k
      NEXT;
10230
101k
        }
10231
107k
    } else {
10232
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10233
0
    }
10234
238k
    if (ret == NULL) {
10235
12
        xmlXPathPErrMemory(ctxt, NULL);
10236
12
        return;
10237
12
    }
10238
238k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10239
238k
    if (lit == NULL) {
10240
13
  ctxt->error = XPATH_MEMORY_ERROR;
10241
238k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10242
238k
                              NULL) == -1) {
10243
2
        xmlXPathReleaseObject(ctxt->context, lit);
10244
2
    }
10245
238k
    xmlFree(ret);
10246
238k
}
10247
10248
/**
10249
 * xmlXPathCompVariableReference:
10250
 * @ctxt:  the XPath Parser context
10251
 *
10252
 * Parse a VariableReference, evaluate it and push it on the stack.
10253
 *
10254
 * The variable bindings consist of a mapping from variable names
10255
 * to variable values. The value of a variable is an object, which can be
10256
 * of any of the types that are possible for the value of an expression,
10257
 * and may also be of additional types not specified here.
10258
 *
10259
 * Early evaluation is possible since:
10260
 * The variable bindings [...] used to evaluate a subexpression are
10261
 * always the same as those used to evaluate the containing expression.
10262
 *
10263
 *  [36]   VariableReference ::=   '$' QName
10264
 */
10265
static void
10266
88.2k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10267
88.2k
    xmlChar *name;
10268
88.2k
    xmlChar *prefix;
10269
10270
88.2k
    SKIP_BLANKS;
10271
88.2k
    if (CUR != '$') {
10272
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10273
0
    }
10274
88.2k
    NEXT;
10275
88.2k
    name = xmlXPathParseQName(ctxt, &prefix);
10276
88.2k
    if (name == NULL) {
10277
2.93k
        xmlFree(prefix);
10278
2.93k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10279
0
    }
10280
85.3k
    ctxt->comp->last = -1;
10281
85.3k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10282
1
        xmlFree(prefix);
10283
1
        xmlFree(name);
10284
1
    }
10285
85.3k
    SKIP_BLANKS;
10286
85.3k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10287
223
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10288
0
    }
10289
85.3k
}
10290
10291
/**
10292
 * xmlXPathIsNodeType:
10293
 * @name:  a name string
10294
 *
10295
 * Is the name given a NodeType one.
10296
 *
10297
 *  [38]   NodeType ::=   'comment'
10298
 *                    | 'text'
10299
 *                    | 'processing-instruction'
10300
 *                    | 'node'
10301
 *
10302
 * Returns 1 if true 0 otherwise
10303
 */
10304
int
10305
1.14M
xmlXPathIsNodeType(const xmlChar *name) {
10306
1.14M
    if (name == NULL)
10307
0
  return(0);
10308
10309
1.14M
    if (xmlStrEqual(name, BAD_CAST "node"))
10310
12.4k
  return(1);
10311
1.13M
    if (xmlStrEqual(name, BAD_CAST "text"))
10312
37.4k
  return(1);
10313
1.09M
    if (xmlStrEqual(name, BAD_CAST "comment"))
10314
345
  return(1);
10315
1.09M
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10316
774
  return(1);
10317
1.09M
    return(0);
10318
1.09M
}
10319
10320
/**
10321
 * xmlXPathCompFunctionCall:
10322
 * @ctxt:  the XPath Parser context
10323
 *
10324
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10325
 *  [17]   Argument ::=   Expr
10326
 *
10327
 * Compile a function call, the evaluation of all arguments are
10328
 * pushed on the stack
10329
 */
10330
static void
10331
1.07M
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10332
1.07M
    xmlChar *name;
10333
1.07M
    xmlChar *prefix;
10334
1.07M
    int nbargs = 0;
10335
1.07M
    int sort = 1;
10336
10337
1.07M
    name = xmlXPathParseQName(ctxt, &prefix);
10338
1.07M
    if (name == NULL) {
10339
817
  xmlFree(prefix);
10340
817
  XP_ERROR(XPATH_EXPR_ERROR);
10341
0
    }
10342
1.07M
    SKIP_BLANKS;
10343
#ifdef DEBUG_EXPR
10344
    if (prefix == NULL)
10345
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10346
      name);
10347
    else
10348
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10349
      prefix, name);
10350
#endif
10351
10352
1.07M
    if (CUR != '(') {
10353
989
  xmlFree(name);
10354
989
  xmlFree(prefix);
10355
989
  XP_ERROR(XPATH_EXPR_ERROR);
10356
0
    }
10357
1.07M
    NEXT;
10358
1.07M
    SKIP_BLANKS;
10359
10360
    /*
10361
    * Optimization for count(): we don't need the node-set to be sorted.
10362
    */
10363
1.07M
    if ((prefix == NULL) && (name[0] == 'c') &&
10364
1.07M
  xmlStrEqual(name, BAD_CAST "count"))
10365
2.35k
    {
10366
2.35k
  sort = 0;
10367
2.35k
    }
10368
1.07M
    ctxt->comp->last = -1;
10369
1.07M
    if (CUR != ')') {
10370
1.75M
  while (CUR != 0) {
10371
1.74M
      int op1 = ctxt->comp->last;
10372
1.74M
      ctxt->comp->last = -1;
10373
1.74M
      xmlXPathCompileExpr(ctxt, sort);
10374
1.74M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10375
152k
    xmlFree(name);
10376
152k
    xmlFree(prefix);
10377
152k
    return;
10378
152k
      }
10379
1.59M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10380
1.59M
      nbargs++;
10381
1.59M
      if (CUR == ')') break;
10382
805k
      if (CUR != ',') {
10383
5.17k
    xmlFree(name);
10384
5.17k
    xmlFree(prefix);
10385
5.17k
    XP_ERROR(XPATH_EXPR_ERROR);
10386
0
      }
10387
800k
      NEXT;
10388
800k
      SKIP_BLANKS;
10389
800k
  }
10390
957k
    }
10391
912k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10392
13
        xmlFree(prefix);
10393
13
        xmlFree(name);
10394
13
    }
10395
912k
    NEXT;
10396
912k
    SKIP_BLANKS;
10397
912k
}
10398
10399
/**
10400
 * xmlXPathCompPrimaryExpr:
10401
 * @ctxt:  the XPath Parser context
10402
 *
10403
 *  [15]   PrimaryExpr ::=   VariableReference
10404
 *                | '(' Expr ')'
10405
 *                | Literal
10406
 *                | Number
10407
 *                | FunctionCall
10408
 *
10409
 * Compile a primary expression.
10410
 */
10411
static void
10412
2.56M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10413
2.56M
    SKIP_BLANKS;
10414
2.56M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10415
2.47M
    else if (CUR == '(') {
10416
178k
  NEXT;
10417
178k
  SKIP_BLANKS;
10418
178k
  xmlXPathCompileExpr(ctxt, 1);
10419
178k
  CHECK_ERROR;
10420
101k
  if (CUR != ')') {
10421
19.2k
      XP_ERROR(XPATH_EXPR_ERROR);
10422
0
  }
10423
82.3k
  NEXT;
10424
82.3k
  SKIP_BLANKS;
10425
2.29M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10426
973k
  xmlXPathCompNumber(ctxt);
10427
1.32M
    } else if ((CUR == '\'') || (CUR == '"')) {
10428
250k
  xmlXPathCompLiteral(ctxt);
10429
1.07M
    } else {
10430
1.07M
  xmlXPathCompFunctionCall(ctxt);
10431
1.07M
    }
10432
2.46M
    SKIP_BLANKS;
10433
2.46M
}
10434
10435
/**
10436
 * xmlXPathCompFilterExpr:
10437
 * @ctxt:  the XPath Parser context
10438
 *
10439
 *  [20]   FilterExpr ::=   PrimaryExpr
10440
 *               | FilterExpr Predicate
10441
 *
10442
 * Compile a filter expression.
10443
 * Square brackets are used to filter expressions in the same way that
10444
 * they are used in location paths. It is an error if the expression to
10445
 * be filtered does not evaluate to a node-set. The context node list
10446
 * used for evaluating the expression in square brackets is the node-set
10447
 * to be filtered listed in document order.
10448
 */
10449
10450
static void
10451
2.56M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10452
2.56M
    xmlXPathCompPrimaryExpr(ctxt);
10453
2.56M
    CHECK_ERROR;
10454
2.29M
    SKIP_BLANKS;
10455
10456
2.63M
    while (CUR == '[') {
10457
339k
  xmlXPathCompPredicate(ctxt, 1);
10458
339k
  SKIP_BLANKS;
10459
339k
    }
10460
10461
10462
2.29M
}
10463
10464
/**
10465
 * xmlXPathScanName:
10466
 * @ctxt:  the XPath Parser context
10467
 *
10468
 * Trickery: parse an XML name but without consuming the input flow
10469
 * Needed to avoid insanity in the parser state.
10470
 *
10471
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10472
 *                  CombiningChar | Extender
10473
 *
10474
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10475
 *
10476
 * [6] Names ::= Name (S Name)*
10477
 *
10478
 * Returns the Name parsed or NULL
10479
 */
10480
10481
static xmlChar *
10482
6.67M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10483
6.67M
    int l;
10484
6.67M
    int c;
10485
6.67M
    const xmlChar *cur;
10486
6.67M
    xmlChar *ret;
10487
10488
6.67M
    cur = ctxt->cur;
10489
10490
6.67M
    c = CUR_CHAR(l);
10491
6.67M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10492
6.67M
  (!IS_LETTER(c) && (c != '_') &&
10493
6.67M
         (c != ':'))) {
10494
183k
  return(NULL);
10495
183k
    }
10496
10497
32.2M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10498
32.2M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10499
31.7M
            (c == '.') || (c == '-') ||
10500
31.7M
      (c == '_') || (c == ':') ||
10501
31.7M
      (IS_COMBINING(c)) ||
10502
31.7M
      (IS_EXTENDER(c)))) {
10503
25.7M
  NEXTL(l);
10504
25.7M
  c = CUR_CHAR(l);
10505
25.7M
    }
10506
6.49M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10507
6.49M
    ctxt->cur = cur;
10508
6.49M
    return(ret);
10509
6.67M
}
10510
10511
/**
10512
 * xmlXPathCompPathExpr:
10513
 * @ctxt:  the XPath Parser context
10514
 *
10515
 *  [19]   PathExpr ::=   LocationPath
10516
 *               | FilterExpr
10517
 *               | FilterExpr '/' RelativeLocationPath
10518
 *               | FilterExpr '//' RelativeLocationPath
10519
 *
10520
 * Compile a path expression.
10521
 * The / operator and // operators combine an arbitrary expression
10522
 * and a relative location path. It is an error if the expression
10523
 * does not evaluate to a node-set.
10524
 * The / operator does composition in the same way as when / is
10525
 * used in a location path. As in location paths, // is short for
10526
 * /descendant-or-self::node()/.
10527
 */
10528
10529
static void
10530
46.7M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10531
46.7M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10532
46.7M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10533
10534
46.7M
    SKIP_BLANKS;
10535
46.7M
    if ((CUR == '$') || (CUR == '(') ||
10536
46.7M
  (IS_ASCII_DIGIT(CUR)) ||
10537
46.7M
        (CUR == '\'') || (CUR == '"') ||
10538
46.7M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10539
1.49M
  lc = 0;
10540
45.2M
    } else if (CUR == '*') {
10541
  /* relative or absolute location path */
10542
36.0M
  lc = 1;
10543
36.0M
    } else if (CUR == '/') {
10544
  /* relative or absolute location path */
10545
1.35M
  lc = 1;
10546
7.89M
    } else if (CUR == '@') {
10547
  /* relative abbreviated attribute location path */
10548
66.8k
  lc = 1;
10549
7.82M
    } else if (CUR == '.') {
10550
  /* relative abbreviated attribute location path */
10551
1.15M
  lc = 1;
10552
6.67M
    } else {
10553
  /*
10554
   * Problem is finding if we have a name here whether it's:
10555
   *   - a nodetype
10556
   *   - a function call in which case it's followed by '('
10557
   *   - an axis in which case it's followed by ':'
10558
   *   - a element name
10559
   * We do an a priori analysis here rather than having to
10560
   * maintain parsed token content through the recursive function
10561
   * calls. This looks uglier but makes the code easier to
10562
   * read/write/debug.
10563
   */
10564
6.67M
  SKIP_BLANKS;
10565
6.67M
  name = xmlXPathScanName(ctxt);
10566
6.67M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10567
#ifdef DEBUG_STEP
10568
      xmlGenericError(xmlGenericErrorContext,
10569
        "PathExpr: Axis\n");
10570
#endif
10571
8.48k
      lc = 1;
10572
8.48k
      xmlFree(name);
10573
6.66M
  } else if (name != NULL) {
10574
6.48M
      int len =xmlStrlen(name);
10575
10576
10577
7.08M
      while (NXT(len) != 0) {
10578
7.05M
    if (NXT(len) == '/') {
10579
        /* element name */
10580
#ifdef DEBUG_STEP
10581
        xmlGenericError(xmlGenericErrorContext,
10582
          "PathExpr: AbbrRelLocation\n");
10583
#endif
10584
197k
        lc = 1;
10585
197k
        break;
10586
6.85M
    } else if (IS_BLANK_CH(NXT(len))) {
10587
        /* ignore blanks */
10588
597k
        ;
10589
6.26M
    } else if (NXT(len) == ':') {
10590
#ifdef DEBUG_STEP
10591
        xmlGenericError(xmlGenericErrorContext,
10592
          "PathExpr: AbbrRelLocation\n");
10593
#endif
10594
1.16k
        lc = 1;
10595
1.16k
        break;
10596
6.25M
    } else if ((NXT(len) == '(')) {
10597
        /* Node Type or Function */
10598
1.12M
        if (xmlXPathIsNodeType(name)) {
10599
#ifdef DEBUG_STEP
10600
            xmlGenericError(xmlGenericErrorContext,
10601
        "PathExpr: Type search\n");
10602
#endif
10603
48.4k
      lc = 1;
10604
#ifdef LIBXML_XPTR_LOCS_ENABLED
10605
                    } else if (ctxt->xptr &&
10606
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10607
                        lc = 1;
10608
#endif
10609
1.07M
        } else {
10610
#ifdef DEBUG_STEP
10611
            xmlGenericError(xmlGenericErrorContext,
10612
        "PathExpr: function call\n");
10613
#endif
10614
1.07M
      lc = 0;
10615
1.07M
        }
10616
1.12M
                    break;
10617
5.13M
    } else if ((NXT(len) == '[')) {
10618
        /* element name */
10619
#ifdef DEBUG_STEP
10620
        xmlGenericError(xmlGenericErrorContext,
10621
          "PathExpr: AbbrRelLocation\n");
10622
#endif
10623
30.4k
        lc = 1;
10624
30.4k
        break;
10625
5.10M
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10626
5.10M
         (NXT(len) == '=')) {
10627
480k
        lc = 1;
10628
480k
        break;
10629
4.62M
    } else {
10630
4.62M
        lc = 1;
10631
4.62M
        break;
10632
4.62M
    }
10633
597k
    len++;
10634
597k
      }
10635
6.48M
      if (NXT(len) == 0) {
10636
#ifdef DEBUG_STEP
10637
    xmlGenericError(xmlGenericErrorContext,
10638
      "PathExpr: AbbrRelLocation\n");
10639
#endif
10640
    /* element name */
10641
27.9k
    lc = 1;
10642
27.9k
      }
10643
6.48M
      xmlFree(name);
10644
6.48M
  } else {
10645
      /* make sure all cases are covered explicitly */
10646
183k
      XP_ERROR(XPATH_EXPR_ERROR);
10647
0
  }
10648
6.67M
    }
10649
10650
46.5M
    if (lc) {
10651
44.0M
  if (CUR == '/') {
10652
1.35M
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10653
42.6M
  } else {
10654
42.6M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10655
42.6M
  }
10656
44.0M
  xmlXPathCompLocationPath(ctxt);
10657
44.0M
    } else {
10658
2.56M
  xmlXPathCompFilterExpr(ctxt);
10659
2.56M
  CHECK_ERROR;
10660
2.23M
  if ((CUR == '/') && (NXT(1) == '/')) {
10661
11.1k
      SKIP(2);
10662
11.1k
      SKIP_BLANKS;
10663
10664
11.1k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10665
11.1k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10666
10667
11.1k
      xmlXPathCompRelativeLocationPath(ctxt);
10668
2.22M
  } else if (CUR == '/') {
10669
302k
      xmlXPathCompRelativeLocationPath(ctxt);
10670
302k
  }
10671
2.23M
    }
10672
46.2M
    SKIP_BLANKS;
10673
46.2M
}
10674
10675
/**
10676
 * xmlXPathCompUnionExpr:
10677
 * @ctxt:  the XPath Parser context
10678
 *
10679
 *  [18]   UnionExpr ::=   PathExpr
10680
 *               | UnionExpr '|' PathExpr
10681
 *
10682
 * Compile an union expression.
10683
 */
10684
10685
static void
10686
42.0M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10687
42.0M
    xmlXPathCompPathExpr(ctxt);
10688
42.0M
    CHECK_ERROR;
10689
41.4M
    SKIP_BLANKS;
10690
46.1M
    while (CUR == '|') {
10691
4.70M
  int op1 = ctxt->comp->last;
10692
4.70M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10693
10694
4.70M
  NEXT;
10695
4.70M
  SKIP_BLANKS;
10696
4.70M
  xmlXPathCompPathExpr(ctxt);
10697
10698
4.70M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10699
10700
4.70M
  SKIP_BLANKS;
10701
4.70M
    }
10702
41.4M
}
10703
10704
/**
10705
 * xmlXPathCompUnaryExpr:
10706
 * @ctxt:  the XPath Parser context
10707
 *
10708
 *  [27]   UnaryExpr ::=   UnionExpr
10709
 *                   | '-' UnaryExpr
10710
 *
10711
 * Compile an unary expression.
10712
 */
10713
10714
static void
10715
42.0M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10716
42.0M
    int minus = 0;
10717
42.0M
    int found = 0;
10718
10719
42.0M
    SKIP_BLANKS;
10720
46.7M
    while (CUR == '-') {
10721
4.70M
        minus = 1 - minus;
10722
4.70M
  found = 1;
10723
4.70M
  NEXT;
10724
4.70M
  SKIP_BLANKS;
10725
4.70M
    }
10726
10727
42.0M
    xmlXPathCompUnionExpr(ctxt);
10728
42.0M
    CHECK_ERROR;
10729
41.4M
    if (found) {
10730
949k
  if (minus)
10731
560k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10732
388k
  else
10733
388k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10734
949k
    }
10735
41.4M
}
10736
10737
/**
10738
 * xmlXPathCompMultiplicativeExpr:
10739
 * @ctxt:  the XPath Parser context
10740
 *
10741
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10742
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10743
 *                   | MultiplicativeExpr 'div' UnaryExpr
10744
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10745
 *  [34]   MultiplyOperator ::=   '*'
10746
 *
10747
 * Compile an Additive expression.
10748
 */
10749
10750
static void
10751
6.15M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10752
6.15M
    xmlXPathCompUnaryExpr(ctxt);
10753
6.15M
    CHECK_ERROR;
10754
5.56M
    SKIP_BLANKS;
10755
41.4M
    while ((CUR == '*') ||
10756
41.4M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10757
41.4M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10758
35.8M
  int op = -1;
10759
35.8M
  int op1 = ctxt->comp->last;
10760
10761
35.8M
        if (CUR == '*') {
10762
35.6M
      op = 0;
10763
35.6M
      NEXT;
10764
35.6M
  } else if (CUR == 'd') {
10765
1.51k
      op = 1;
10766
1.51k
      SKIP(3);
10767
196k
  } else if (CUR == 'm') {
10768
196k
      op = 2;
10769
196k
      SKIP(3);
10770
196k
  }
10771
35.8M
  SKIP_BLANKS;
10772
35.8M
        xmlXPathCompUnaryExpr(ctxt);
10773
35.8M
  CHECK_ERROR;
10774
35.8M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10775
35.8M
  SKIP_BLANKS;
10776
35.8M
    }
10777
5.56M
}
10778
10779
/**
10780
 * xmlXPathCompAdditiveExpr:
10781
 * @ctxt:  the XPath Parser context
10782
 *
10783
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10784
 *                   | AdditiveExpr '+' MultiplicativeExpr
10785
 *                   | AdditiveExpr '-' MultiplicativeExpr
10786
 *
10787
 * Compile an Additive expression.
10788
 */
10789
10790
static void
10791
4.94M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10792
10793
4.94M
    xmlXPathCompMultiplicativeExpr(ctxt);
10794
4.94M
    CHECK_ERROR;
10795
4.45M
    SKIP_BLANKS;
10796
5.55M
    while ((CUR == '+') || (CUR == '-')) {
10797
1.21M
  int plus;
10798
1.21M
  int op1 = ctxt->comp->last;
10799
10800
1.21M
        if (CUR == '+') plus = 1;
10801
970k
  else plus = 0;
10802
1.21M
  NEXT;
10803
1.21M
  SKIP_BLANKS;
10804
1.21M
        xmlXPathCompMultiplicativeExpr(ctxt);
10805
1.21M
  CHECK_ERROR;
10806
1.09M
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10807
1.09M
  SKIP_BLANKS;
10808
1.09M
    }
10809
4.45M
}
10810
10811
/**
10812
 * xmlXPathCompRelationalExpr:
10813
 * @ctxt:  the XPath Parser context
10814
 *
10815
 *  [24]   RelationalExpr ::=   AdditiveExpr
10816
 *                 | RelationalExpr '<' AdditiveExpr
10817
 *                 | RelationalExpr '>' AdditiveExpr
10818
 *                 | RelationalExpr '<=' AdditiveExpr
10819
 *                 | RelationalExpr '>=' AdditiveExpr
10820
 *
10821
 *  A <= B > C is allowed ? Answer from James, yes with
10822
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10823
 *  which is basically what got implemented.
10824
 *
10825
 * Compile a Relational expression, then push the result
10826
 * on the stack
10827
 */
10828
10829
static void
10830
4.37M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10831
4.37M
    xmlXPathCompAdditiveExpr(ctxt);
10832
4.37M
    CHECK_ERROR;
10833
3.83M
    SKIP_BLANKS;
10834
4.34M
    while ((CUR == '<') || (CUR == '>')) {
10835
566k
  int inf, strict;
10836
566k
  int op1 = ctxt->comp->last;
10837
10838
566k
        if (CUR == '<') inf = 1;
10839
560k
  else inf = 0;
10840
566k
  if (NXT(1) == '=') strict = 0;
10841
550k
  else strict = 1;
10842
566k
  NEXT;
10843
566k
  if (!strict) NEXT;
10844
566k
  SKIP_BLANKS;
10845
566k
        xmlXPathCompAdditiveExpr(ctxt);
10846
566k
  CHECK_ERROR;
10847
502k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10848
502k
  SKIP_BLANKS;
10849
502k
    }
10850
3.83M
}
10851
10852
/**
10853
 * xmlXPathCompEqualityExpr:
10854
 * @ctxt:  the XPath Parser context
10855
 *
10856
 *  [23]   EqualityExpr ::=   RelationalExpr
10857
 *                 | EqualityExpr '=' RelationalExpr
10858
 *                 | EqualityExpr '!=' RelationalExpr
10859
 *
10860
 *  A != B != C is allowed ? Answer from James, yes with
10861
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10862
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10863
 *  which is basically what got implemented.
10864
 *
10865
 * Compile an Equality expression.
10866
 *
10867
 */
10868
static void
10869
3.34M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10870
3.34M
    xmlXPathCompRelationalExpr(ctxt);
10871
3.34M
    CHECK_ERROR;
10872
2.89M
    SKIP_BLANKS;
10873
3.77M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10874
1.02M
  int eq;
10875
1.02M
  int op1 = ctxt->comp->last;
10876
10877
1.02M
        if (CUR == '=') eq = 1;
10878
404k
  else eq = 0;
10879
1.02M
  NEXT;
10880
1.02M
  if (!eq) NEXT;
10881
1.02M
  SKIP_BLANKS;
10882
1.02M
        xmlXPathCompRelationalExpr(ctxt);
10883
1.02M
  CHECK_ERROR;
10884
878k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10885
878k
  SKIP_BLANKS;
10886
878k
    }
10887
2.89M
}
10888
10889
/**
10890
 * xmlXPathCompAndExpr:
10891
 * @ctxt:  the XPath Parser context
10892
 *
10893
 *  [22]   AndExpr ::=   EqualityExpr
10894
 *                 | AndExpr 'and' EqualityExpr
10895
 *
10896
 * Compile an AND expression.
10897
 *
10898
 */
10899
static void
10900
3.26M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10901
3.26M
    xmlXPathCompEqualityExpr(ctxt);
10902
3.26M
    CHECK_ERROR;
10903
2.68M
    SKIP_BLANKS;
10904
2.74M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10905
84.4k
  int op1 = ctxt->comp->last;
10906
84.4k
        SKIP(3);
10907
84.4k
  SKIP_BLANKS;
10908
84.4k
        xmlXPathCompEqualityExpr(ctxt);
10909
84.4k
  CHECK_ERROR;
10910
60.1k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10911
60.1k
  SKIP_BLANKS;
10912
60.1k
    }
10913
2.68M
}
10914
10915
/**
10916
 * xmlXPathCompileExpr:
10917
 * @ctxt:  the XPath Parser context
10918
 *
10919
 *  [14]   Expr ::=   OrExpr
10920
 *  [21]   OrExpr ::=   AndExpr
10921
 *                 | OrExpr 'or' AndExpr
10922
 *
10923
 * Parse and compile an expression
10924
 */
10925
static void
10926
3.43M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10927
3.43M
    xmlXPathContextPtr xpctxt = ctxt->context;
10928
10929
3.43M
    if (xpctxt != NULL) {
10930
3.43M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10931
3.24M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10932
        /*
10933
         * Parsing a single '(' pushes about 10 functions on the call stack
10934
         * before recursing!
10935
         */
10936
3.24M
        xpctxt->depth += 10;
10937
3.24M
    }
10938
10939
3.24M
    xmlXPathCompAndExpr(ctxt);
10940
3.24M
    CHECK_ERROR;
10941
2.64M
    SKIP_BLANKS;
10942
2.66M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10943
23.5k
  int op1 = ctxt->comp->last;
10944
23.5k
        SKIP(2);
10945
23.5k
  SKIP_BLANKS;
10946
23.5k
        xmlXPathCompAndExpr(ctxt);
10947
23.5k
  CHECK_ERROR;
10948
17.8k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10949
17.8k
  SKIP_BLANKS;
10950
17.8k
    }
10951
2.64M
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10952
  /* more ops could be optimized too */
10953
  /*
10954
  * This is the main place to eliminate sorting for
10955
  * operations which don't require a sorted node-set.
10956
  * E.g. count().
10957
  */
10958
2.32M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10959
2.32M
    }
10960
10961
2.64M
    if (xpctxt != NULL)
10962
2.64M
        xpctxt->depth -= 10;
10963
2.64M
}
10964
10965
/**
10966
 * xmlXPathCompPredicate:
10967
 * @ctxt:  the XPath Parser context
10968
 * @filter:  act as a filter
10969
 *
10970
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10971
 *  [9]   PredicateExpr ::=   Expr
10972
 *
10973
 * Compile a predicate expression
10974
 */
10975
static void
10976
554k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10977
554k
    int op1 = ctxt->comp->last;
10978
10979
554k
    SKIP_BLANKS;
10980
554k
    if (CUR != '[') {
10981
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10982
0
    }
10983
554k
    NEXT;
10984
554k
    SKIP_BLANKS;
10985
10986
554k
    ctxt->comp->last = -1;
10987
    /*
10988
    * This call to xmlXPathCompileExpr() will deactivate sorting
10989
    * of the predicate result.
10990
    * TODO: Sorting is still activated for filters, since I'm not
10991
    *  sure if needed. Normally sorting should not be needed, since
10992
    *  a filter can only diminish the number of items in a sequence,
10993
    *  but won't change its order; so if the initial sequence is sorted,
10994
    *  subsequent sorting is not needed.
10995
    */
10996
554k
    if (! filter)
10997
214k
  xmlXPathCompileExpr(ctxt, 0);
10998
339k
    else
10999
339k
  xmlXPathCompileExpr(ctxt, 1);
11000
554k
    CHECK_ERROR;
11001
11002
397k
    if (CUR != ']') {
11003
3.99k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11004
0
    }
11005
11006
393k
    if (filter)
11007
288k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11008
105k
    else
11009
105k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11010
11011
393k
    NEXT;
11012
393k
    SKIP_BLANKS;
11013
393k
}
11014
11015
/**
11016
 * xmlXPathCompNodeTest:
11017
 * @ctxt:  the XPath Parser context
11018
 * @test:  pointer to a xmlXPathTestVal
11019
 * @type:  pointer to a xmlXPathTypeVal
11020
 * @prefix:  placeholder for a possible name prefix
11021
 *
11022
 * [7] NodeTest ::=   NameTest
11023
 *        | NodeType '(' ')'
11024
 *        | 'processing-instruction' '(' Literal ')'
11025
 *
11026
 * [37] NameTest ::=  '*'
11027
 *        | NCName ':' '*'
11028
 *        | QName
11029
 * [38] NodeType ::= 'comment'
11030
 *       | 'text'
11031
 *       | 'processing-instruction'
11032
 *       | 'node'
11033
 *
11034
 * Returns the name found and updates @test, @type and @prefix appropriately
11035
 */
11036
static xmlChar *
11037
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11038
               xmlXPathTypeVal *type, xmlChar **prefix,
11039
43.3M
         xmlChar *name) {
11040
43.3M
    int blanks;
11041
11042
43.3M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11043
0
  STRANGE;
11044
0
  return(NULL);
11045
0
    }
11046
43.3M
    *type = (xmlXPathTypeVal) 0;
11047
43.3M
    *test = (xmlXPathTestVal) 0;
11048
43.3M
    *prefix = NULL;
11049
43.3M
    SKIP_BLANKS;
11050
11051
43.3M
    if ((name == NULL) && (CUR == '*')) {
11052
  /*
11053
   * All elements
11054
   */
11055
36.4M
  NEXT;
11056
36.4M
  *test = NODE_TEST_ALL;
11057
36.4M
  return(NULL);
11058
36.4M
    }
11059
11060
6.86M
    if (name == NULL)
11061
123k
  name = xmlXPathParseNCName(ctxt);
11062
6.86M
    if (name == NULL) {
11063
37.0k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11064
0
    }
11065
11066
6.83M
    blanks = IS_BLANK_CH(CUR);
11067
6.83M
    SKIP_BLANKS;
11068
6.83M
    if (CUR == '(') {
11069
323k
  NEXT;
11070
  /*
11071
   * NodeType or PI search
11072
   */
11073
323k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11074
25.0k
      *type = NODE_TYPE_COMMENT;
11075
298k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11076
170k
      *type = NODE_TYPE_NODE;
11077
127k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11078
13.5k
      *type = NODE_TYPE_PI;
11079
114k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11080
103k
      *type = NODE_TYPE_TEXT;
11081
10.5k
  else {
11082
10.5k
      if (name != NULL)
11083
10.5k
    xmlFree(name);
11084
10.5k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11085
0
  }
11086
11087
312k
  *test = NODE_TEST_TYPE;
11088
11089
312k
  SKIP_BLANKS;
11090
312k
  if (*type == NODE_TYPE_PI) {
11091
      /*
11092
       * Specific case: search a PI by name.
11093
       */
11094
13.5k
      if (name != NULL)
11095
13.5k
    xmlFree(name);
11096
13.5k
      name = NULL;
11097
13.5k
      if (CUR != ')') {
11098
2.26k
    name = xmlXPathParseLiteral(ctxt);
11099
2.26k
                if (name == NULL) {
11100
1.08k
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11101
0
                }
11102
1.18k
    *test = NODE_TEST_PI;
11103
1.18k
    SKIP_BLANKS;
11104
1.18k
      }
11105
13.5k
  }
11106
311k
  if (CUR != ')') {
11107
3.07k
      if (name != NULL)
11108
3.07k
    xmlFree(name);
11109
3.07k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11110
0
  }
11111
308k
  NEXT;
11112
308k
  return(name);
11113
311k
    }
11114
6.50M
    *test = NODE_TEST_NAME;
11115
6.50M
    if ((!blanks) && (CUR == ':')) {
11116
151k
  NEXT;
11117
11118
  /*
11119
   * Since currently the parser context don't have a
11120
   * namespace list associated:
11121
   * The namespace name for this prefix can be computed
11122
   * only at evaluation time. The compilation is done
11123
   * outside of any context.
11124
   */
11125
#if 0
11126
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11127
  if (name != NULL)
11128
      xmlFree(name);
11129
  if (*prefix == NULL) {
11130
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11131
  }
11132
#else
11133
151k
  *prefix = name;
11134
151k
#endif
11135
11136
151k
  if (CUR == '*') {
11137
      /*
11138
       * All elements
11139
       */
11140
19.0k
      NEXT;
11141
19.0k
      *test = NODE_TEST_ALL;
11142
19.0k
      return(NULL);
11143
19.0k
  }
11144
11145
132k
  name = xmlXPathParseNCName(ctxt);
11146
132k
  if (name == NULL) {
11147
19.5k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11148
0
  }
11149
132k
    }
11150
6.46M
    return(name);
11151
6.50M
}
11152
11153
/**
11154
 * xmlXPathIsAxisName:
11155
 * @name:  a preparsed name token
11156
 *
11157
 * [6] AxisName ::=   'ancestor'
11158
 *                  | 'ancestor-or-self'
11159
 *                  | 'attribute'
11160
 *                  | 'child'
11161
 *                  | 'descendant'
11162
 *                  | 'descendant-or-self'
11163
 *                  | 'following'
11164
 *                  | 'following-sibling'
11165
 *                  | 'namespace'
11166
 *                  | 'parent'
11167
 *                  | 'preceding'
11168
 *                  | 'preceding-sibling'
11169
 *                  | 'self'
11170
 *
11171
 * Returns the axis or 0
11172
 */
11173
static xmlXPathAxisVal
11174
6.83M
xmlXPathIsAxisName(const xmlChar *name) {
11175
6.83M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11176
6.83M
    switch (name[0]) {
11177
359k
  case 'a':
11178
359k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11179
457
    ret = AXIS_ANCESTOR;
11180
359k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11181
816
    ret = AXIS_ANCESTOR_OR_SELF;
11182
359k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11183
8.90k
    ret = AXIS_ATTRIBUTE;
11184
359k
      break;
11185
165k
  case 'c':
11186
165k
      if (xmlStrEqual(name, BAD_CAST "child"))
11187
2.62k
    ret = AXIS_CHILD;
11188
165k
      break;
11189
102k
  case 'd':
11190
102k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11191
237
    ret = AXIS_DESCENDANT;
11192
102k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11193
231
    ret = AXIS_DESCENDANT_OR_SELF;
11194
102k
      break;
11195
12.6k
  case 'f':
11196
12.6k
      if (xmlStrEqual(name, BAD_CAST "following"))
11197
1.16k
    ret = AXIS_FOLLOWING;
11198
12.6k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11199
212
    ret = AXIS_FOLLOWING_SIBLING;
11200
12.6k
      break;
11201
604k
  case 'n':
11202
604k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11203
110k
    ret = AXIS_NAMESPACE;
11204
604k
      break;
11205
94.2k
  case 'p':
11206
94.2k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11207
1.13k
    ret = AXIS_PARENT;
11208
94.2k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11209
774
    ret = AXIS_PRECEDING;
11210
94.2k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11211
587
    ret = AXIS_PRECEDING_SIBLING;
11212
94.2k
      break;
11213
53.0k
  case 's':
11214
53.0k
      if (xmlStrEqual(name, BAD_CAST "self"))
11215
3.21k
    ret = AXIS_SELF;
11216
53.0k
      break;
11217
6.83M
    }
11218
6.83M
    return(ret);
11219
6.83M
}
11220
11221
/**
11222
 * xmlXPathCompStep:
11223
 * @ctxt:  the XPath Parser context
11224
 *
11225
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11226
 *                  | AbbreviatedStep
11227
 *
11228
 * [12] AbbreviatedStep ::=   '.' | '..'
11229
 *
11230
 * [5] AxisSpecifier ::= AxisName '::'
11231
 *                  | AbbreviatedAxisSpecifier
11232
 *
11233
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11234
 *
11235
 * Modified for XPtr range support as:
11236
 *
11237
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11238
 *                     | AbbreviatedStep
11239
 *                     | 'range-to' '(' Expr ')' Predicate*
11240
 *
11241
 * Compile one step in a Location Path
11242
 * A location step of . is short for self::node(). This is
11243
 * particularly useful in conjunction with //. For example, the
11244
 * location path .//para is short for
11245
 * self::node()/descendant-or-self::node()/child::para
11246
 * and so will select all para descendant elements of the context
11247
 * node.
11248
 * Similarly, a location step of .. is short for parent::node().
11249
 * For example, ../title is short for parent::node()/child::title
11250
 * and so will select the title children of the parent of the context
11251
 * node.
11252
 */
11253
static void
11254
44.7M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11255
#ifdef LIBXML_XPTR_LOCS_ENABLED
11256
    int rangeto = 0;
11257
    int op2 = -1;
11258
#endif
11259
11260
44.7M
    SKIP_BLANKS;
11261
44.7M
    if ((CUR == '.') && (NXT(1) == '.')) {
11262
100k
  SKIP(2);
11263
100k
  SKIP_BLANKS;
11264
100k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11265
100k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11266
44.6M
    } else if (CUR == '.') {
11267
1.37M
  NEXT;
11268
1.37M
  SKIP_BLANKS;
11269
43.3M
    } else {
11270
43.3M
  xmlChar *name = NULL;
11271
43.3M
  xmlChar *prefix = NULL;
11272
43.3M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11273
43.3M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11274
43.3M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11275
43.3M
  int op1;
11276
11277
  /*
11278
   * The modification needed for XPointer change to the production
11279
   */
11280
#ifdef LIBXML_XPTR_LOCS_ENABLED
11281
  if (ctxt->xptr) {
11282
      name = xmlXPathParseNCName(ctxt);
11283
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11284
                op2 = ctxt->comp->last;
11285
    xmlFree(name);
11286
    SKIP_BLANKS;
11287
    if (CUR != '(') {
11288
        XP_ERROR(XPATH_EXPR_ERROR);
11289
    }
11290
    NEXT;
11291
    SKIP_BLANKS;
11292
11293
    xmlXPathCompileExpr(ctxt, 1);
11294
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11295
    CHECK_ERROR;
11296
11297
    SKIP_BLANKS;
11298
    if (CUR != ')') {
11299
        XP_ERROR(XPATH_EXPR_ERROR);
11300
    }
11301
    NEXT;
11302
    rangeto = 1;
11303
    goto eval_predicates;
11304
      }
11305
  }
11306
#endif
11307
43.3M
  if (CUR == '*') {
11308
36.3M
      axis = AXIS_CHILD;
11309
36.3M
  } else {
11310
6.95M
      if (name == NULL)
11311
6.95M
    name = xmlXPathParseNCName(ctxt);
11312
6.95M
      if (name != NULL) {
11313
6.83M
    axis = xmlXPathIsAxisName(name);
11314
6.83M
    if (axis != 0) {
11315
130k
        SKIP_BLANKS;
11316
130k
        if ((CUR == ':') && (NXT(1) == ':')) {
11317
78.2k
      SKIP(2);
11318
78.2k
      xmlFree(name);
11319
78.2k
      name = NULL;
11320
78.2k
        } else {
11321
      /* an element name can conflict with an axis one :-\ */
11322
52.5k
      axis = AXIS_CHILD;
11323
52.5k
        }
11324
6.70M
    } else {
11325
6.70M
        axis = AXIS_CHILD;
11326
6.70M
    }
11327
6.83M
      } else if (CUR == '@') {
11328
77.1k
    NEXT;
11329
77.1k
    axis = AXIS_ATTRIBUTE;
11330
77.1k
      } else {
11331
40.8k
    axis = AXIS_CHILD;
11332
40.8k
      }
11333
6.95M
  }
11334
11335
43.3M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11336
19.9k
            xmlFree(name);
11337
19.9k
            return;
11338
19.9k
        }
11339
11340
43.3M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11341
43.3M
  if (test == 0)
11342
47.6k
      return;
11343
11344
43.2M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11345
43.2M
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11346
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11347
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11348
0
      }
11349
0
  }
11350
#ifdef DEBUG_STEP
11351
  xmlGenericError(xmlGenericErrorContext,
11352
    "Basis : computing new set\n");
11353
#endif
11354
11355
#ifdef DEBUG_STEP
11356
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11357
  if (ctxt->value == NULL)
11358
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11359
  else if (ctxt->value->nodesetval == NULL)
11360
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11361
  else
11362
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11363
#endif
11364
11365
#ifdef LIBXML_XPTR_LOCS_ENABLED
11366
eval_predicates:
11367
#endif
11368
43.2M
  op1 = ctxt->comp->last;
11369
43.2M
  ctxt->comp->last = -1;
11370
11371
43.2M
  SKIP_BLANKS;
11372
43.4M
  while (CUR == '[') {
11373
214k
      xmlXPathCompPredicate(ctxt, 0);
11374
214k
  }
11375
11376
#ifdef LIBXML_XPTR_LOCS_ENABLED
11377
  if (rangeto) {
11378
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11379
  } else
11380
#endif
11381
43.2M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11382
43.2M
                           test, type, (void *)prefix, (void *)name) == -1) {
11383
74
            xmlFree(prefix);
11384
74
            xmlFree(name);
11385
74
        }
11386
43.2M
    }
11387
#ifdef DEBUG_STEP
11388
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11389
    if (ctxt->value == NULL)
11390
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11391
    else if (ctxt->value->nodesetval == NULL)
11392
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11393
    else
11394
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11395
    ctxt->value->nodesetval);
11396
#endif
11397
44.7M
}
11398
11399
/**
11400
 * xmlXPathCompRelativeLocationPath:
11401
 * @ctxt:  the XPath Parser context
11402
 *
11403
 *  [3]   RelativeLocationPath ::=   Step
11404
 *                     | RelativeLocationPath '/' Step
11405
 *                     | AbbreviatedRelativeLocationPath
11406
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11407
 *
11408
 * Compile a relative location path.
11409
 */
11410
static void
11411
xmlXPathCompRelativeLocationPath
11412
43.5M
(xmlXPathParserContextPtr ctxt) {
11413
43.5M
    SKIP_BLANKS;
11414
43.5M
    if ((CUR == '/') && (NXT(1) == '/')) {
11415
3.01k
  SKIP(2);
11416
3.01k
  SKIP_BLANKS;
11417
3.01k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11418
3.01k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11419
43.5M
    } else if (CUR == '/') {
11420
305k
      NEXT;
11421
305k
  SKIP_BLANKS;
11422
305k
    }
11423
43.5M
    xmlXPathCompStep(ctxt);
11424
43.5M
    CHECK_ERROR;
11425
43.4M
    SKIP_BLANKS;
11426
44.7M
    while (CUR == '/') {
11427
1.29M
  if ((CUR == '/') && (NXT(1) == '/')) {
11428
64.7k
      SKIP(2);
11429
64.7k
      SKIP_BLANKS;
11430
64.7k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11431
64.7k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11432
64.7k
      xmlXPathCompStep(ctxt);
11433
1.22M
  } else if (CUR == '/') {
11434
1.22M
      NEXT;
11435
1.22M
      SKIP_BLANKS;
11436
1.22M
      xmlXPathCompStep(ctxt);
11437
1.22M
  }
11438
1.29M
  SKIP_BLANKS;
11439
1.29M
    }
11440
43.4M
}
11441
11442
/**
11443
 * xmlXPathCompLocationPath:
11444
 * @ctxt:  the XPath Parser context
11445
 *
11446
 *  [1]   LocationPath ::=   RelativeLocationPath
11447
 *                     | AbsoluteLocationPath
11448
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11449
 *                     | AbbreviatedAbsoluteLocationPath
11450
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11451
 *                           '//' RelativeLocationPath
11452
 *
11453
 * Compile a location path
11454
 *
11455
 * // is short for /descendant-or-self::node()/. For example,
11456
 * //para is short for /descendant-or-self::node()/child::para and
11457
 * so will select any para element in the document (even a para element
11458
 * that is a document element will be selected by //para since the
11459
 * document element node is a child of the root node); div//para is
11460
 * short for div/descendant-or-self::node()/child::para and so will
11461
 * select all para descendants of div children.
11462
 */
11463
static void
11464
44.0M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11465
44.0M
    SKIP_BLANKS;
11466
44.0M
    if (CUR != '/') {
11467
42.6M
        xmlXPathCompRelativeLocationPath(ctxt);
11468
42.6M
    } else {
11469
2.69M
  while (CUR == '/') {
11470
1.36M
      if ((CUR == '/') && (NXT(1) == '/')) {
11471
278k
    SKIP(2);
11472
278k
    SKIP_BLANKS;
11473
278k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11474
278k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11475
278k
    xmlXPathCompRelativeLocationPath(ctxt);
11476
1.08M
      } else if (CUR == '/') {
11477
1.08M
    NEXT;
11478
1.08M
    SKIP_BLANKS;
11479
1.08M
    if ((CUR != 0 ) &&
11480
1.08M
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11481
1.07M
         (CUR == '@') || (CUR == '*')))
11482
263k
        xmlXPathCompRelativeLocationPath(ctxt);
11483
1.08M
      }
11484
1.36M
      CHECK_ERROR;
11485
1.36M
  }
11486
1.35M
    }
11487
44.0M
}
11488
11489
/************************************************************************
11490
 *                  *
11491
 *    XPath precompiled expression evaluation     *
11492
 *                  *
11493
 ************************************************************************/
11494
11495
static int
11496
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11497
11498
#ifdef DEBUG_STEP
11499
static void
11500
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11501
        int nbNodes)
11502
{
11503
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11504
    switch (op->value) {
11505
        case AXIS_ANCESTOR:
11506
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11507
            break;
11508
        case AXIS_ANCESTOR_OR_SELF:
11509
            xmlGenericError(xmlGenericErrorContext,
11510
                            "axis 'ancestors-or-self' ");
11511
            break;
11512
        case AXIS_ATTRIBUTE:
11513
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11514
            break;
11515
        case AXIS_CHILD:
11516
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11517
            break;
11518
        case AXIS_DESCENDANT:
11519
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11520
            break;
11521
        case AXIS_DESCENDANT_OR_SELF:
11522
            xmlGenericError(xmlGenericErrorContext,
11523
                            "axis 'descendant-or-self' ");
11524
            break;
11525
        case AXIS_FOLLOWING:
11526
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11527
            break;
11528
        case AXIS_FOLLOWING_SIBLING:
11529
            xmlGenericError(xmlGenericErrorContext,
11530
                            "axis 'following-siblings' ");
11531
            break;
11532
        case AXIS_NAMESPACE:
11533
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11534
            break;
11535
        case AXIS_PARENT:
11536
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11537
            break;
11538
        case AXIS_PRECEDING:
11539
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11540
            break;
11541
        case AXIS_PRECEDING_SIBLING:
11542
            xmlGenericError(xmlGenericErrorContext,
11543
                            "axis 'preceding-sibling' ");
11544
            break;
11545
        case AXIS_SELF:
11546
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11547
            break;
11548
    }
11549
    xmlGenericError(xmlGenericErrorContext,
11550
  " context contains %d nodes\n", nbNodes);
11551
    switch (op->value2) {
11552
        case NODE_TEST_NONE:
11553
            xmlGenericError(xmlGenericErrorContext,
11554
                            "           searching for none !!!\n");
11555
            break;
11556
        case NODE_TEST_TYPE:
11557
            xmlGenericError(xmlGenericErrorContext,
11558
                            "           searching for type %d\n", op->value3);
11559
            break;
11560
        case NODE_TEST_PI:
11561
            xmlGenericError(xmlGenericErrorContext,
11562
                            "           searching for PI !!!\n");
11563
            break;
11564
        case NODE_TEST_ALL:
11565
            xmlGenericError(xmlGenericErrorContext,
11566
                            "           searching for *\n");
11567
            break;
11568
        case NODE_TEST_NS:
11569
            xmlGenericError(xmlGenericErrorContext,
11570
                            "           searching for namespace %s\n",
11571
                            op->value5);
11572
            break;
11573
        case NODE_TEST_NAME:
11574
            xmlGenericError(xmlGenericErrorContext,
11575
                            "           searching for name %s\n", op->value5);
11576
            if (op->value4)
11577
                xmlGenericError(xmlGenericErrorContext,
11578
                                "           with namespace %s\n", op->value4);
11579
            break;
11580
    }
11581
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11582
}
11583
#endif /* DEBUG_STEP */
11584
11585
/**
11586
 * xmlXPathNodeSetFilter:
11587
 * @ctxt:  the XPath Parser context
11588
 * @set: the node set to filter
11589
 * @filterOpIndex: the index of the predicate/filter op
11590
 * @minPos: minimum position in the filtered set (1-based)
11591
 * @maxPos: maximum position in the filtered set (1-based)
11592
 * @hasNsNodes: true if the node set may contain namespace nodes
11593
 *
11594
 * Filter a node set, keeping only nodes for which the predicate expression
11595
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11596
 * filtered result.
11597
 */
11598
static void
11599
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11600
          xmlNodeSetPtr set,
11601
          int filterOpIndex,
11602
                      int minPos, int maxPos,
11603
          int hasNsNodes)
11604
331k
{
11605
331k
    xmlXPathContextPtr xpctxt;
11606
331k
    xmlNodePtr oldnode;
11607
331k
    xmlDocPtr olddoc;
11608
331k
    xmlXPathStepOpPtr filterOp;
11609
331k
    int oldcs, oldpp;
11610
331k
    int i, j, pos;
11611
11612
331k
    if ((set == NULL) || (set->nodeNr == 0))
11613
111k
        return;
11614
11615
    /*
11616
    * Check if the node set contains a sufficient number of nodes for
11617
    * the requested range.
11618
    */
11619
219k
    if (set->nodeNr < minPos) {
11620
6.78k
        xmlXPathNodeSetClear(set, hasNsNodes);
11621
6.78k
        return;
11622
6.78k
    }
11623
11624
213k
    xpctxt = ctxt->context;
11625
213k
    oldnode = xpctxt->node;
11626
213k
    olddoc = xpctxt->doc;
11627
213k
    oldcs = xpctxt->contextSize;
11628
213k
    oldpp = xpctxt->proximityPosition;
11629
213k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11630
11631
213k
    xpctxt->contextSize = set->nodeNr;
11632
11633
1.22M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11634
1.14M
        xmlNodePtr node = set->nodeTab[i];
11635
1.14M
        int res;
11636
11637
1.14M
        xpctxt->node = node;
11638
1.14M
        xpctxt->proximityPosition = i + 1;
11639
11640
        /*
11641
        * Also set the xpath document in case things like
11642
        * key() are evaluated in the predicate.
11643
        *
11644
        * TODO: Get real doc for namespace nodes.
11645
        */
11646
1.14M
        if ((node->type != XML_NAMESPACE_DECL) &&
11647
1.14M
            (node->doc != NULL))
11648
1.12M
            xpctxt->doc = node->doc;
11649
11650
1.14M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11651
11652
1.14M
        if (ctxt->error != XPATH_EXPRESSION_OK)
11653
11.9k
            break;
11654
1.13M
        if (res < 0) {
11655
            /* Shouldn't happen */
11656
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11657
0
            break;
11658
0
        }
11659
11660
1.13M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11661
344k
            if (i != j) {
11662
15.9k
                set->nodeTab[j] = node;
11663
15.9k
                set->nodeTab[i] = NULL;
11664
15.9k
            }
11665
11666
344k
            j += 1;
11667
788k
        } else {
11668
            /* Remove the entry from the initial node set. */
11669
788k
            set->nodeTab[i] = NULL;
11670
788k
            if (node->type == XML_NAMESPACE_DECL)
11671
7.82k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11672
788k
        }
11673
11674
1.13M
        if (res != 0) {
11675
350k
            if (pos == maxPos) {
11676
120k
                i += 1;
11677
120k
                break;
11678
120k
            }
11679
11680
230k
            pos += 1;
11681
230k
        }
11682
1.13M
    }
11683
11684
    /* Free remaining nodes. */
11685
213k
    if (hasNsNodes) {
11686
842k
        for (; i < set->nodeNr; i++) {
11687
785k
            xmlNodePtr node = set->nodeTab[i];
11688
785k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11689
3.95k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11690
785k
        }
11691
57.4k
    }
11692
11693
213k
    set->nodeNr = j;
11694
11695
    /* If too many elements were removed, shrink table to preserve memory. */
11696
213k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11697
213k
        (set->nodeNr < set->nodeMax / 2)) {
11698
10.4k
        xmlNodePtr *tmp;
11699
10.4k
        int nodeMax = set->nodeNr;
11700
11701
10.4k
        if (nodeMax < XML_NODESET_DEFAULT)
11702
10.2k
            nodeMax = XML_NODESET_DEFAULT;
11703
10.4k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11704
10.4k
                nodeMax * sizeof(xmlNodePtr));
11705
10.4k
        if (tmp == NULL) {
11706
147
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11707
10.3k
        } else {
11708
10.3k
            set->nodeTab = tmp;
11709
10.3k
            set->nodeMax = nodeMax;
11710
10.3k
        }
11711
10.4k
    }
11712
11713
213k
    xpctxt->node = oldnode;
11714
213k
    xpctxt->doc = olddoc;
11715
213k
    xpctxt->contextSize = oldcs;
11716
213k
    xpctxt->proximityPosition = oldpp;
11717
213k
}
11718
11719
#ifdef LIBXML_XPTR_LOCS_ENABLED
11720
/**
11721
 * xmlXPathLocationSetFilter:
11722
 * @ctxt:  the XPath Parser context
11723
 * @locset: the location set to filter
11724
 * @filterOpIndex: the index of the predicate/filter op
11725
 * @minPos: minimum position in the filtered set (1-based)
11726
 * @maxPos: maximum position in the filtered set (1-based)
11727
 *
11728
 * Filter a location set, keeping only nodes for which the predicate
11729
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11730
 * in the filtered result.
11731
 */
11732
static void
11733
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11734
              xmlLocationSetPtr locset,
11735
              int filterOpIndex,
11736
                          int minPos, int maxPos)
11737
{
11738
    xmlXPathContextPtr xpctxt;
11739
    xmlNodePtr oldnode;
11740
    xmlDocPtr olddoc;
11741
    xmlXPathStepOpPtr filterOp;
11742
    int oldcs, oldpp;
11743
    int i, j, pos;
11744
11745
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11746
        return;
11747
11748
    xpctxt = ctxt->context;
11749
    oldnode = xpctxt->node;
11750
    olddoc = xpctxt->doc;
11751
    oldcs = xpctxt->contextSize;
11752
    oldpp = xpctxt->proximityPosition;
11753
    filterOp = &ctxt->comp->steps[filterOpIndex];
11754
11755
    xpctxt->contextSize = locset->locNr;
11756
11757
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11758
        xmlNodePtr contextNode = locset->locTab[i]->user;
11759
        int res;
11760
11761
        xpctxt->node = contextNode;
11762
        xpctxt->proximityPosition = i + 1;
11763
11764
        /*
11765
        * Also set the xpath document in case things like
11766
        * key() are evaluated in the predicate.
11767
        *
11768
        * TODO: Get real doc for namespace nodes.
11769
        */
11770
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11771
            (contextNode->doc != NULL))
11772
            xpctxt->doc = contextNode->doc;
11773
11774
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11775
11776
        if (ctxt->error != XPATH_EXPRESSION_OK)
11777
            break;
11778
        if (res < 0) {
11779
            /* Shouldn't happen */
11780
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11781
            break;
11782
        }
11783
11784
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11785
            if (i != j) {
11786
                locset->locTab[j] = locset->locTab[i];
11787
                locset->locTab[i] = NULL;
11788
            }
11789
11790
            j += 1;
11791
        } else {
11792
            /* Remove the entry from the initial location set. */
11793
            xmlXPathFreeObject(locset->locTab[i]);
11794
            locset->locTab[i] = NULL;
11795
        }
11796
11797
        if (res != 0) {
11798
            if (pos == maxPos) {
11799
                i += 1;
11800
                break;
11801
            }
11802
11803
            pos += 1;
11804
        }
11805
    }
11806
11807
    /* Free remaining nodes. */
11808
    for (; i < locset->locNr; i++)
11809
        xmlXPathFreeObject(locset->locTab[i]);
11810
11811
    locset->locNr = j;
11812
11813
    /* If too many elements were removed, shrink table to preserve memory. */
11814
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11815
        (locset->locNr < locset->locMax / 2)) {
11816
        xmlXPathObjectPtr *tmp;
11817
        int locMax = locset->locNr;
11818
11819
        if (locMax < XML_NODESET_DEFAULT)
11820
            locMax = XML_NODESET_DEFAULT;
11821
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11822
                locMax * sizeof(xmlXPathObjectPtr));
11823
        if (tmp == NULL) {
11824
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11825
        } else {
11826
            locset->locTab = tmp;
11827
            locset->locMax = locMax;
11828
        }
11829
    }
11830
11831
    xpctxt->node = oldnode;
11832
    xpctxt->doc = olddoc;
11833
    xpctxt->contextSize = oldcs;
11834
    xpctxt->proximityPosition = oldpp;
11835
}
11836
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11837
11838
/**
11839
 * xmlXPathCompOpEvalPredicate:
11840
 * @ctxt:  the XPath Parser context
11841
 * @op: the predicate op
11842
 * @set: the node set to filter
11843
 * @minPos: minimum position in the filtered set (1-based)
11844
 * @maxPos: maximum position in the filtered set (1-based)
11845
 * @hasNsNodes: true if the node set may contain namespace nodes
11846
 *
11847
 * Filter a node set, keeping only nodes for which the sequence of predicate
11848
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11849
 * in the filtered result.
11850
 */
11851
static void
11852
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11853
          xmlXPathStepOpPtr op,
11854
          xmlNodeSetPtr set,
11855
                            int minPos, int maxPos,
11856
          int hasNsNodes)
11857
176k
{
11858
176k
    if (op->ch1 != -1) {
11859
42.7k
  xmlXPathCompExprPtr comp = ctxt->comp;
11860
  /*
11861
  * Process inner predicates first.
11862
  */
11863
42.7k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11864
0
            xmlGenericError(xmlGenericErrorContext,
11865
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11866
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11867
0
  }
11868
42.7k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11869
42.7k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11870
42.7k
        ctxt->context->depth += 1;
11871
42.7k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11872
42.7k
                                    1, set->nodeNr, hasNsNodes);
11873
42.7k
        ctxt->context->depth -= 1;
11874
42.7k
  CHECK_ERROR;
11875
42.7k
    }
11876
11877
173k
    if (op->ch2 != -1)
11878
173k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11879
173k
}
11880
11881
static int
11882
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11883
          xmlXPathStepOpPtr op,
11884
          int *maxPos)
11885
101k
{
11886
11887
101k
    xmlXPathStepOpPtr exprOp;
11888
11889
    /*
11890
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11891
    */
11892
11893
    /*
11894
    * If not -1, then ch1 will point to:
11895
    * 1) For predicates (XPATH_OP_PREDICATE):
11896
    *    - an inner predicate operator
11897
    * 2) For filters (XPATH_OP_FILTER):
11898
    *    - an inner filter operator OR
11899
    *    - an expression selecting the node set.
11900
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11901
    */
11902
101k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11903
0
  return(0);
11904
11905
101k
    if (op->ch2 != -1) {
11906
101k
  exprOp = &ctxt->comp->steps[op->ch2];
11907
101k
    } else
11908
0
  return(0);
11909
11910
101k
    if ((exprOp != NULL) &&
11911
101k
  (exprOp->op == XPATH_OP_VALUE) &&
11912
101k
  (exprOp->value4 != NULL) &&
11913
101k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11914
30.2k
    {
11915
30.2k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11916
11917
  /*
11918
  * We have a "[n]" predicate here.
11919
  * TODO: Unfortunately this simplistic test here is not
11920
  * able to detect a position() predicate in compound
11921
  * expressions like "[@attr = 'a" and position() = 1],
11922
  * and even not the usage of position() in
11923
  * "[position() = 1]"; thus - obviously - a position-range,
11924
  * like it "[position() < 5]", is also not detected.
11925
  * Maybe we could rewrite the AST to ease the optimization.
11926
  */
11927
11928
30.2k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11929
29.8k
      *maxPos = (int) floatval;
11930
29.8k
            if (floatval == (double) *maxPos)
11931
28.2k
                return(1);
11932
29.8k
        }
11933
30.2k
    }
11934
73.1k
    return(0);
11935
101k
}
11936
11937
static int
11938
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11939
                           xmlXPathStepOpPtr op,
11940
         xmlNodePtr * first, xmlNodePtr * last,
11941
         int toBool)
11942
4.97M
{
11943
11944
4.97M
#define XP_TEST_HIT \
11945
26.0M
    if (hasAxisRange != 0) { \
11946
82.6k
  if (++pos == maxPos) { \
11947
45.6k
      if (addNode(seq, cur) < 0) \
11948
45.6k
          ctxt->error = XPATH_MEMORY_ERROR; \
11949
45.6k
      goto axis_range_end; } \
11950
25.9M
    } else { \
11951
25.9M
  if (addNode(seq, cur) < 0) \
11952
25.9M
      ctxt->error = XPATH_MEMORY_ERROR; \
11953
25.9M
  if (breakOnFirstHit) goto first_hit; }
11954
11955
4.97M
#define XP_TEST_HIT_NS \
11956
4.97M
    if (hasAxisRange != 0) { \
11957
6.35k
  if (++pos == maxPos) { \
11958
3.48k
      hasNsNodes = 1; \
11959
3.48k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11960
3.48k
          ctxt->error = XPATH_MEMORY_ERROR; \
11961
3.48k
  goto axis_range_end; } \
11962
665k
    } else { \
11963
665k
  hasNsNodes = 1; \
11964
665k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11965
665k
      ctxt->error = XPATH_MEMORY_ERROR; \
11966
665k
  if (breakOnFirstHit) goto first_hit; }
11967
11968
4.97M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11969
4.97M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11970
4.97M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11971
4.97M
    const xmlChar *prefix = op->value4;
11972
4.97M
    const xmlChar *name = op->value5;
11973
4.97M
    const xmlChar *URI = NULL;
11974
11975
#ifdef DEBUG_STEP
11976
    int nbMatches = 0, prevMatches = 0;
11977
#endif
11978
4.97M
    int total = 0, hasNsNodes = 0;
11979
    /* The popped object holding the context nodes */
11980
4.97M
    xmlXPathObjectPtr obj;
11981
    /* The set of context nodes for the node tests */
11982
4.97M
    xmlNodeSetPtr contextSeq;
11983
4.97M
    int contextIdx;
11984
4.97M
    xmlNodePtr contextNode;
11985
    /* The final resulting node set wrt to all context nodes */
11986
4.97M
    xmlNodeSetPtr outSeq;
11987
    /*
11988
    * The temporary resulting node set wrt 1 context node.
11989
    * Used to feed predicate evaluation.
11990
    */
11991
4.97M
    xmlNodeSetPtr seq;
11992
4.97M
    xmlNodePtr cur;
11993
    /* First predicate operator */
11994
4.97M
    xmlXPathStepOpPtr predOp;
11995
4.97M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11996
4.97M
    int hasPredicateRange, hasAxisRange, pos;
11997
4.97M
    int breakOnFirstHit;
11998
11999
4.97M
    xmlXPathTraversalFunction next = NULL;
12000
4.97M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12001
4.97M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12002
4.97M
    xmlNodePtr oldContextNode;
12003
4.97M
    xmlXPathContextPtr xpctxt = ctxt->context;
12004
12005
12006
4.97M
    CHECK_TYPE0(XPATH_NODESET);
12007
4.97M
    obj = valuePop(ctxt);
12008
    /*
12009
    * Setup namespaces.
12010
    */
12011
4.97M
    if (prefix != NULL) {
12012
299k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12013
299k
        if (URI == NULL) {
12014
82.4k
      xmlXPathReleaseObject(xpctxt, obj);
12015
82.4k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12016
0
  }
12017
299k
    }
12018
    /*
12019
    * Setup axis.
12020
    *
12021
    * MAYBE FUTURE TODO: merging optimizations:
12022
    * - If the nodes to be traversed wrt to the initial nodes and
12023
    *   the current axis cannot overlap, then we could avoid searching
12024
    *   for duplicates during the merge.
12025
    *   But the question is how/when to evaluate if they cannot overlap.
12026
    *   Example: if we know that for two initial nodes, the one is
12027
    *   not in the ancestor-or-self axis of the other, then we could safely
12028
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12029
    *   the descendant-or-self axis.
12030
    */
12031
4.89M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12032
4.89M
    switch (axis) {
12033
1.33k
        case AXIS_ANCESTOR:
12034
1.33k
            first = NULL;
12035
1.33k
            next = xmlXPathNextAncestor;
12036
1.33k
            break;
12037
578
        case AXIS_ANCESTOR_OR_SELF:
12038
578
            first = NULL;
12039
578
            next = xmlXPathNextAncestorOrSelf;
12040
578
            break;
12041
702k
        case AXIS_ATTRIBUTE:
12042
702k
            first = NULL;
12043
702k
      last = NULL;
12044
702k
            next = xmlXPathNextAttribute;
12045
702k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12046
702k
            break;
12047
3.03M
        case AXIS_CHILD:
12048
3.03M
      last = NULL;
12049
3.03M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12050
3.03M
    (type == NODE_TYPE_NODE))
12051
2.86M
      {
12052
    /*
12053
    * Optimization if an element node type is 'element'.
12054
    */
12055
2.86M
    next = xmlXPathNextChildElement;
12056
2.86M
      } else
12057
169k
    next = xmlXPathNextChild;
12058
3.03M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12059
3.03M
            break;
12060
851k
        case AXIS_DESCENDANT:
12061
851k
      last = NULL;
12062
851k
            next = xmlXPathNextDescendant;
12063
851k
            break;
12064
73.8k
        case AXIS_DESCENDANT_OR_SELF:
12065
73.8k
      last = NULL;
12066
73.8k
            next = xmlXPathNextDescendantOrSelf;
12067
73.8k
            break;
12068
1.16k
        case AXIS_FOLLOWING:
12069
1.16k
      last = NULL;
12070
1.16k
            next = xmlXPathNextFollowing;
12071
1.16k
            break;
12072
0
        case AXIS_FOLLOWING_SIBLING:
12073
0
      last = NULL;
12074
0
            next = xmlXPathNextFollowingSibling;
12075
0
            break;
12076
63.1k
        case AXIS_NAMESPACE:
12077
63.1k
            first = NULL;
12078
63.1k
      last = NULL;
12079
63.1k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12080
63.1k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081
63.1k
            break;
12082
155k
        case AXIS_PARENT:
12083
155k
            first = NULL;
12084
155k
            next = xmlXPathNextParent;
12085
155k
            break;
12086
3.96k
        case AXIS_PRECEDING:
12087
3.96k
            first = NULL;
12088
3.96k
            next = xmlXPathNextPrecedingInternal;
12089
3.96k
            break;
12090
25
        case AXIS_PRECEDING_SIBLING:
12091
25
            first = NULL;
12092
25
            next = xmlXPathNextPrecedingSibling;
12093
25
            break;
12094
511
        case AXIS_SELF:
12095
511
            first = NULL;
12096
511
      last = NULL;
12097
511
            next = xmlXPathNextSelf;
12098
511
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12099
511
            break;
12100
4.89M
    }
12101
12102
#ifdef DEBUG_STEP
12103
    xmlXPathDebugDumpStepAxis(op,
12104
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12105
#endif
12106
12107
4.89M
    if (next == NULL) {
12108
0
  xmlXPathReleaseObject(xpctxt, obj);
12109
0
        return(0);
12110
0
    }
12111
4.89M
    contextSeq = obj->nodesetval;
12112
4.89M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12113
633k
  xmlXPathReleaseObject(xpctxt, obj);
12114
633k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12115
633k
        return(0);
12116
633k
    }
12117
    /*
12118
    * Predicate optimization ---------------------------------------------
12119
    * If this step has a last predicate, which contains a position(),
12120
    * then we'll optimize (although not exactly "position()", but only
12121
    * the  short-hand form, i.e., "[n]".
12122
    *
12123
    * Example - expression "/foo[parent::bar][1]":
12124
    *
12125
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12126
    *   ROOT                               -- op->ch1
12127
    *   PREDICATE                          -- op->ch2 (predOp)
12128
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12129
    *       SORT
12130
    *         COLLECT  'parent' 'name' 'node' bar
12131
    *           NODE
12132
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12133
    *
12134
    */
12135
4.25M
    maxPos = 0;
12136
4.25M
    predOp = NULL;
12137
4.25M
    hasPredicateRange = 0;
12138
4.25M
    hasAxisRange = 0;
12139
4.25M
    if (op->ch2 != -1) {
12140
  /*
12141
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12142
  */
12143
101k
  predOp = &ctxt->comp->steps[op->ch2];
12144
101k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12145
28.2k
      if (predOp->ch1 != -1) {
12146
    /*
12147
    * Use the next inner predicate operator.
12148
    */
12149
5.31k
    predOp = &ctxt->comp->steps[predOp->ch1];
12150
5.31k
    hasPredicateRange = 1;
12151
22.9k
      } else {
12152
    /*
12153
    * There's no other predicate than the [n] predicate.
12154
    */
12155
22.9k
    predOp = NULL;
12156
22.9k
    hasAxisRange = 1;
12157
22.9k
      }
12158
28.2k
  }
12159
101k
    }
12160
4.25M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12161
    /*
12162
    * Axis traversal -----------------------------------------------------
12163
    */
12164
    /*
12165
     * 2.3 Node Tests
12166
     *  - For the attribute axis, the principal node type is attribute.
12167
     *  - For the namespace axis, the principal node type is namespace.
12168
     *  - For other axes, the principal node type is element.
12169
     *
12170
     * A node test * is true for any node of the
12171
     * principal node type. For example, child::* will
12172
     * select all element children of the context node
12173
     */
12174
4.25M
    oldContextNode = xpctxt->node;
12175
4.25M
    addNode = xmlXPathNodeSetAddUnique;
12176
4.25M
    outSeq = NULL;
12177
4.25M
    seq = NULL;
12178
4.25M
    contextNode = NULL;
12179
4.25M
    contextIdx = 0;
12180
12181
12182
10.6M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12183
10.6M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12184
6.38M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12185
12186
6.38M
  if (seq == NULL) {
12187
4.30M
      seq = xmlXPathNodeSetCreate(NULL);
12188
4.30M
      if (seq == NULL) {
12189
                /* TODO: Propagate memory error. */
12190
5.45k
    total = 0;
12191
5.45k
    goto error;
12192
5.45k
      }
12193
4.30M
  }
12194
  /*
12195
  * Traverse the axis and test the nodes.
12196
  */
12197
6.38M
  pos = 0;
12198
6.38M
  cur = NULL;
12199
6.38M
  hasNsNodes = 0;
12200
38.5M
        do {
12201
38.5M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12202
450
                goto error;
12203
12204
38.5M
            cur = next(ctxt, cur);
12205
38.5M
            if (cur == NULL)
12206
6.29M
                break;
12207
12208
      /*
12209
      * QUESTION TODO: What does the "first" and "last" stuff do?
12210
      */
12211
32.3M
            if ((first != NULL) && (*first != NULL)) {
12212
20.2k
    if (*first == cur)
12213
3.61k
        break;
12214
16.5k
    if (((total % 256) == 0) &&
12215
16.5k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12216
16.5k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12217
#else
12218
        (xmlXPathCmpNodes(*first, cur) >= 0))
12219
#endif
12220
8.49k
    {
12221
8.49k
        break;
12222
8.49k
    }
12223
16.5k
      }
12224
32.2M
      if ((last != NULL) && (*last != NULL)) {
12225
8.08k
    if (*last == cur)
12226
311
        break;
12227
7.77k
    if (((total % 256) == 0) &&
12228
7.77k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12229
7.77k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12230
#else
12231
        (xmlXPathCmpNodes(cur, *last) >= 0))
12232
#endif
12233
1.34k
    {
12234
1.34k
        break;
12235
1.34k
    }
12236
7.77k
      }
12237
12238
32.2M
            total++;
12239
12240
#ifdef DEBUG_STEP
12241
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12242
#endif
12243
12244
32.2M
      switch (test) {
12245
0
                case NODE_TEST_NONE:
12246
0
        total = 0;
12247
0
                    STRANGE
12248
0
        goto error;
12249
24.5M
                case NODE_TEST_TYPE:
12250
24.5M
        if (type == NODE_TYPE_NODE) {
12251
23.2M
      switch (cur->type) {
12252
268k
          case XML_DOCUMENT_NODE:
12253
268k
          case XML_HTML_DOCUMENT_NODE:
12254
13.8M
          case XML_ELEMENT_NODE:
12255
13.9M
          case XML_ATTRIBUTE_NODE:
12256
14.0M
          case XML_PI_NODE:
12257
14.2M
          case XML_COMMENT_NODE:
12258
14.2M
          case XML_CDATA_SECTION_NODE:
12259
23.1M
          case XML_TEXT_NODE:
12260
23.1M
        XP_TEST_HIT
12261
23.1M
        break;
12262
23.1M
          case XML_NAMESPACE_DECL: {
12263
95.1k
        if (axis == AXIS_NAMESPACE) {
12264
49.3k
            XP_TEST_HIT_NS
12265
49.3k
        } else {
12266
45.7k
                              hasNsNodes = 1;
12267
45.7k
            XP_TEST_HIT
12268
45.7k
        }
12269
94.5k
        break;
12270
95.1k
                            }
12271
94.5k
          default:
12272
13.1k
        break;
12273
23.2M
      }
12274
23.2M
        } else if (cur->type == (xmlElementType) type) {
12275
379k
      if (cur->type == XML_NAMESPACE_DECL)
12276
0
          XP_TEST_HIT_NS
12277
379k
      else
12278
379k
          XP_TEST_HIT
12279
870k
        } else if ((type == NODE_TYPE_TEXT) &&
12280
870k
       (cur->type == XML_CDATA_SECTION_NODE))
12281
0
        {
12282
0
      XP_TEST_HIT
12283
0
        }
12284
24.4M
        break;
12285
24.4M
                case NODE_TEST_PI:
12286
4.87k
                    if ((cur->type == XML_PI_NODE) &&
12287
4.87k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12288
536
        {
12289
536
      XP_TEST_HIT
12290
536
                    }
12291
4.87k
                    break;
12292
3.37M
                case NODE_TEST_ALL:
12293
3.37M
                    if (axis == AXIS_ATTRIBUTE) {
12294
99.0k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12295
99.0k
      {
12296
99.0k
                            if (prefix == NULL)
12297
95.3k
          {
12298
95.3k
        XP_TEST_HIT
12299
95.3k
                            } else if ((cur->ns != NULL) &&
12300
3.75k
        (xmlStrEqual(URI, cur->ns->href)))
12301
38
          {
12302
38
        XP_TEST_HIT
12303
38
                            }
12304
99.0k
                        }
12305
3.27M
                    } else if (axis == AXIS_NAMESPACE) {
12306
620k
                        if (cur->type == XML_NAMESPACE_DECL)
12307
620k
      {
12308
620k
          XP_TEST_HIT_NS
12309
620k
                        }
12310
2.65M
                    } else {
12311
2.65M
                        if (cur->type == XML_ELEMENT_NODE) {
12312
1.84M
                            if (prefix == NULL)
12313
1.84M
          {
12314
1.84M
        XP_TEST_HIT
12315
12316
1.84M
                            } else if ((cur->ns != NULL) &&
12317
3.36k
        (xmlStrEqual(URI, cur->ns->href)))
12318
239
          {
12319
239
        XP_TEST_HIT
12320
239
                            }
12321
1.84M
                        }
12322
2.65M
                    }
12323
3.36M
                    break;
12324
3.36M
                case NODE_TEST_NS:{
12325
0
                        TODO;
12326
0
                        break;
12327
3.37M
                    }
12328
4.40M
                case NODE_TEST_NAME:
12329
4.40M
                    if (axis == AXIS_ATTRIBUTE) {
12330
502k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12331
0
          break;
12332
3.90M
        } else if (axis == AXIS_NAMESPACE) {
12333
27.4k
                        if (cur->type != XML_NAMESPACE_DECL)
12334
0
          break;
12335
3.87M
        } else {
12336
3.87M
            if (cur->type != XML_ELEMENT_NODE)
12337
766k
          break;
12338
3.87M
        }
12339
3.63M
                    switch (cur->type) {
12340
3.10M
                        case XML_ELEMENT_NODE:
12341
3.10M
                            if (xmlStrEqual(name, cur->name)) {
12342
176k
                                if (prefix == NULL) {
12343
108k
                                    if (cur->ns == NULL)
12344
105k
            {
12345
105k
          XP_TEST_HIT
12346
105k
                                    }
12347
108k
                                } else {
12348
68.6k
                                    if ((cur->ns != NULL) &&
12349
68.6k
                                        (xmlStrEqual(URI, cur->ns->href)))
12350
62.2k
            {
12351
62.2k
          XP_TEST_HIT
12352
62.2k
                                    }
12353
68.6k
                                }
12354
176k
                            }
12355
3.10M
                            break;
12356
3.10M
                        case XML_ATTRIBUTE_NODE:{
12357
502k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12358
12359
502k
                                if (xmlStrEqual(name, attr->name)) {
12360
353k
                                    if (prefix == NULL) {
12361
353k
                                        if ((attr->ns == NULL) ||
12362
353k
                                            (attr->ns->prefix == NULL))
12363
353k
          {
12364
353k
              XP_TEST_HIT
12365
353k
                                        }
12366
353k
                                    } else {
12367
29
                                        if ((attr->ns != NULL) &&
12368
29
                                            (xmlStrEqual(URI,
12369
0
                attr->ns->href)))
12370
0
          {
12371
0
              XP_TEST_HIT
12372
0
                                        }
12373
29
                                    }
12374
353k
                                }
12375
499k
                                break;
12376
502k
                            }
12377
499k
                        case XML_NAMESPACE_DECL:
12378
27.4k
                            if (cur->type == XML_NAMESPACE_DECL) {
12379
27.4k
                                xmlNsPtr ns = (xmlNsPtr) cur;
12380
12381
27.4k
                                if ((ns->prefix != NULL) && (name != NULL)
12382
27.4k
                                    && (xmlStrEqual(ns->prefix, name)))
12383
2.68k
        {
12384
2.68k
            XP_TEST_HIT_NS
12385
2.68k
                                }
12386
27.4k
                            }
12387
26.7k
                            break;
12388
26.7k
                        default:
12389
0
                            break;
12390
3.63M
                    }
12391
3.63M
                    break;
12392
32.2M
      } /* switch(test) */
12393
32.2M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12394
12395
6.30M
  goto apply_predicates;
12396
12397
6.30M
axis_range_end: /* ----------------------------------------------------- */
12398
  /*
12399
  * We have a "/foo[n]", and position() = n was reached.
12400
  * Note that we can have as well "/foo/::parent::foo[1]", so
12401
  * a duplicate-aware merge is still needed.
12402
  * Merge with the result.
12403
  */
12404
49.1k
  if (outSeq == NULL) {
12405
12.6k
      outSeq = seq;
12406
12.6k
      seq = NULL;
12407
12.6k
  } else
12408
            /* TODO: Check memory error. */
12409
36.4k
      outSeq = mergeAndClear(outSeq, seq);
12410
  /*
12411
  * Break if only a true/false result was requested.
12412
  */
12413
49.1k
  if (toBool)
12414
4.14k
      break;
12415
45.0k
  continue;
12416
12417
45.0k
first_hit: /* ---------------------------------------------------------- */
12418
  /*
12419
  * Break if only a true/false result was requested and
12420
  * no predicates existed and a node test succeeded.
12421
  */
12422
23.1k
  if (outSeq == NULL) {
12423
23.1k
      outSeq = seq;
12424
23.1k
      seq = NULL;
12425
23.1k
  } else
12426
            /* TODO: Check memory error. */
12427
0
      outSeq = mergeAndClear(outSeq, seq);
12428
23.1k
  break;
12429
12430
#ifdef DEBUG_STEP
12431
  if (seq != NULL)
12432
      nbMatches += seq->nodeNr;
12433
#endif
12434
12435
6.30M
apply_predicates: /* --------------------------------------------------- */
12436
6.30M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12437
388
      goto error;
12438
12439
        /*
12440
  * Apply predicates.
12441
  */
12442
6.30M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12443
      /*
12444
      * E.g. when we have a "/foo[some expression][n]".
12445
      */
12446
      /*
12447
      * QUESTION TODO: The old predicate evaluation took into
12448
      *  account location-sets.
12449
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12450
      *  Do we expect such a set here?
12451
      *  All what I learned now from the evaluation semantics
12452
      *  does not indicate that a location-set will be processed
12453
      *  here, so this looks OK.
12454
      */
12455
      /*
12456
      * Iterate over all predicates, starting with the outermost
12457
      * predicate.
12458
      * TODO: Problem: we cannot execute the inner predicates first
12459
      *  since we cannot go back *up* the operator tree!
12460
      *  Options we have:
12461
      *  1) Use of recursive functions (like is it currently done
12462
      *     via xmlXPathCompOpEval())
12463
      *  2) Add a predicate evaluation information stack to the
12464
      *     context struct
12465
      *  3) Change the way the operators are linked; we need a
12466
      *     "parent" field on xmlXPathStepOp
12467
      *
12468
      * For the moment, I'll try to solve this with a recursive
12469
      * function: xmlXPathCompOpEvalPredicate().
12470
      */
12471
134k
      if (hasPredicateRange != 0)
12472
10.7k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12473
10.7k
              hasNsNodes);
12474
123k
      else
12475
123k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12476
123k
              hasNsNodes);
12477
12478
134k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12479
6.76k
    total = 0;
12480
6.76k
    goto error;
12481
6.76k
      }
12482
134k
        }
12483
12484
6.30M
        if (seq->nodeNr > 0) {
12485
      /*
12486
      * Add to result set.
12487
      */
12488
2.66M
      if (outSeq == NULL) {
12489
1.66M
    outSeq = seq;
12490
1.66M
    seq = NULL;
12491
1.66M
      } else {
12492
                /* TODO: Check memory error. */
12493
994k
    outSeq = mergeAndClear(outSeq, seq);
12494
994k
      }
12495
12496
2.66M
            if (toBool)
12497
455
                break;
12498
2.66M
  }
12499
6.30M
    }
12500
12501
4.25M
error:
12502
4.25M
    if ((obj->boolval) && (obj->user != NULL)) {
12503
  /*
12504
  * QUESTION TODO: What does this do and why?
12505
  * TODO: Do we have to do this also for the "error"
12506
  * cleanup further down?
12507
  */
12508
0
  ctxt->value->boolval = 1;
12509
0
  ctxt->value->user = obj->user;
12510
0
  obj->user = NULL;
12511
0
  obj->boolval = 0;
12512
0
    }
12513
4.25M
    xmlXPathReleaseObject(xpctxt, obj);
12514
12515
    /*
12516
    * Ensure we return at least an empty set.
12517
    */
12518
4.25M
    if (outSeq == NULL) {
12519
2.55M
  if ((seq != NULL) && (seq->nodeNr == 0))
12520
2.54M
      outSeq = seq;
12521
5.75k
  else
12522
            /* TODO: Check memory error. */
12523
5.75k
      outSeq = xmlXPathNodeSetCreate(NULL);
12524
2.55M
    }
12525
4.25M
    if ((seq != NULL) && (seq != outSeq)) {
12526
46.3k
   xmlXPathFreeNodeSet(seq);
12527
46.3k
    }
12528
    /*
12529
    * Hand over the result. Better to push the set also in
12530
    * case of errors.
12531
    */
12532
4.25M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12533
    /*
12534
    * Reset the context node.
12535
    */
12536
4.25M
    xpctxt->node = oldContextNode;
12537
    /*
12538
    * When traversing the namespace axis in "toBool" mode, it's
12539
    * possible that tmpNsList wasn't freed.
12540
    */
12541
4.25M
    if (xpctxt->tmpNsList != NULL) {
12542
1.86k
        xmlFree(xpctxt->tmpNsList);
12543
1.86k
        xpctxt->tmpNsList = NULL;
12544
1.86k
    }
12545
12546
#ifdef DEBUG_STEP
12547
    xmlGenericError(xmlGenericErrorContext,
12548
  "\nExamined %d nodes, found %d nodes at that step\n",
12549
  total, nbMatches);
12550
#endif
12551
12552
4.25M
    return(total);
12553
4.25M
}
12554
12555
static int
12556
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12557
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12558
12559
/**
12560
 * xmlXPathCompOpEvalFirst:
12561
 * @ctxt:  the XPath parser context with the compiled expression
12562
 * @op:  an XPath compiled operation
12563
 * @first:  the first elem found so far
12564
 *
12565
 * Evaluate the Precompiled XPath operation searching only the first
12566
 * element in document order
12567
 *
12568
 * Returns the number of examined objects.
12569
 */
12570
static int
12571
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12572
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12573
198k
{
12574
198k
    int total = 0, cur;
12575
198k
    xmlXPathCompExprPtr comp;
12576
198k
    xmlXPathObjectPtr arg1, arg2;
12577
12578
198k
    CHECK_ERROR0;
12579
198k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12580
2
        return(0);
12581
198k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12582
197k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12583
197k
    ctxt->context->depth += 1;
12584
197k
    comp = ctxt->comp;
12585
197k
    switch (op->op) {
12586
0
        case XPATH_OP_END:
12587
0
            break;
12588
50.0k
        case XPATH_OP_UNION:
12589
50.0k
            total =
12590
50.0k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12591
50.0k
                                        first);
12592
50.0k
      CHECK_ERROR0;
12593
42.6k
            if ((ctxt->value != NULL)
12594
42.6k
                && (ctxt->value->type == XPATH_NODESET)
12595
42.6k
                && (ctxt->value->nodesetval != NULL)
12596
42.6k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12597
                /*
12598
                 * limit tree traversing to first node in the result
12599
                 */
12600
    /*
12601
    * OPTIMIZE TODO: This implicitly sorts
12602
    *  the result, even if not needed. E.g. if the argument
12603
    *  of the count() function, no sorting is needed.
12604
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12605
    *  already sorted?
12606
    */
12607
34.4k
    if (ctxt->value->nodesetval->nodeNr > 1)
12608
9.65k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12609
34.4k
                *first = ctxt->value->nodesetval->nodeTab[0];
12610
34.4k
            }
12611
42.6k
            cur =
12612
42.6k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12613
42.6k
                                        first);
12614
42.6k
      CHECK_ERROR0;
12615
12616
39.9k
            arg2 = valuePop(ctxt);
12617
39.9k
            arg1 = valuePop(ctxt);
12618
39.9k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12619
39.9k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12620
321
          xmlXPathReleaseObject(ctxt->context, arg1);
12621
321
          xmlXPathReleaseObject(ctxt->context, arg2);
12622
321
                XP_ERROR0(XPATH_INVALID_TYPE);
12623
0
            }
12624
39.6k
            if ((ctxt->context->opLimit != 0) &&
12625
39.6k
                (((arg1->nodesetval != NULL) &&
12626
39.6k
                  (xmlXPathCheckOpLimit(ctxt,
12627
36.4k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12628
39.6k
                 ((arg2->nodesetval != NULL) &&
12629
39.6k
                  (xmlXPathCheckOpLimit(ctxt,
12630
30.6k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12631
2
          xmlXPathReleaseObject(ctxt->context, arg1);
12632
2
          xmlXPathReleaseObject(ctxt->context, arg2);
12633
2
                break;
12634
2
            }
12635
12636
            /* TODO: Check memory error. */
12637
39.6k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12638
39.6k
                                                    arg2->nodesetval);
12639
39.6k
            valuePush(ctxt, arg1);
12640
39.6k
      xmlXPathReleaseObject(ctxt->context, arg2);
12641
            /* optimizer */
12642
39.6k
      if (total > cur)
12643
24.4k
    xmlXPathCompSwap(op);
12644
39.6k
            total += cur;
12645
39.6k
            break;
12646
641
        case XPATH_OP_ROOT:
12647
641
            xmlXPathRoot(ctxt);
12648
641
            break;
12649
9.45k
        case XPATH_OP_NODE:
12650
9.45k
            if (op->ch1 != -1)
12651
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12652
9.45k
      CHECK_ERROR0;
12653
9.45k
            if (op->ch2 != -1)
12654
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12655
9.45k
      CHECK_ERROR0;
12656
9.45k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12657
9.45k
    ctxt->context->node));
12658
9.45k
            break;
12659
49.6k
        case XPATH_OP_COLLECT:{
12660
49.6k
                if (op->ch1 == -1)
12661
0
                    break;
12662
12663
49.6k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12664
49.6k
    CHECK_ERROR0;
12665
12666
47.0k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12667
47.0k
                break;
12668
49.6k
            }
12669
401
        case XPATH_OP_VALUE:
12670
401
            valuePush(ctxt,
12671
401
                      xmlXPathCacheObjectCopy(ctxt->context,
12672
401
      (xmlXPathObjectPtr) op->value4));
12673
401
            break;
12674
19.2k
        case XPATH_OP_SORT:
12675
19.2k
            if (op->ch1 != -1)
12676
19.2k
                total +=
12677
19.2k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12678
19.2k
                                            first);
12679
19.2k
      CHECK_ERROR0;
12680
14.7k
            if ((ctxt->value != NULL)
12681
14.7k
                && (ctxt->value->type == XPATH_NODESET)
12682
14.7k
                && (ctxt->value->nodesetval != NULL)
12683
14.7k
    && (ctxt->value->nodesetval->nodeNr > 1))
12684
6.34k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12685
14.7k
            break;
12686
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12687
67.3k
  case XPATH_OP_FILTER:
12688
67.3k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12689
67.3k
            break;
12690
0
#endif
12691
638
        default:
12692
638
            total += xmlXPathCompOpEval(ctxt, op);
12693
638
            break;
12694
197k
    }
12695
12696
179k
    ctxt->context->depth -= 1;
12697
179k
    return(total);
12698
197k
}
12699
12700
/**
12701
 * xmlXPathCompOpEvalLast:
12702
 * @ctxt:  the XPath parser context with the compiled expression
12703
 * @op:  an XPath compiled operation
12704
 * @last:  the last elem found so far
12705
 *
12706
 * Evaluate the Precompiled XPath operation searching only the last
12707
 * element in document order
12708
 *
12709
 * Returns the number of nodes traversed
12710
 */
12711
static int
12712
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12713
                       xmlNodePtr * last)
12714
238k
{
12715
238k
    int total = 0, cur;
12716
238k
    xmlXPathCompExprPtr comp;
12717
238k
    xmlXPathObjectPtr arg1, arg2;
12718
12719
238k
    CHECK_ERROR0;
12720
238k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12721
3
        return(0);
12722
238k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12723
237k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12724
237k
    ctxt->context->depth += 1;
12725
237k
    comp = ctxt->comp;
12726
237k
    switch (op->op) {
12727
0
        case XPATH_OP_END:
12728
0
            break;
12729
76.5k
        case XPATH_OP_UNION:
12730
76.5k
            total =
12731
76.5k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12732
76.5k
      CHECK_ERROR0;
12733
72.7k
            if ((ctxt->value != NULL)
12734
72.7k
                && (ctxt->value->type == XPATH_NODESET)
12735
72.7k
                && (ctxt->value->nodesetval != NULL)
12736
72.7k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12737
                /*
12738
                 * limit tree traversing to first node in the result
12739
                 */
12740
49.3k
    if (ctxt->value->nodesetval->nodeNr > 1)
12741
7.91k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12742
49.3k
                *last =
12743
49.3k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12744
49.3k
                                                     nodesetval->nodeNr -
12745
49.3k
                                                     1];
12746
49.3k
            }
12747
72.7k
            cur =
12748
72.7k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12749
72.7k
      CHECK_ERROR0;
12750
71.6k
            if ((ctxt->value != NULL)
12751
71.6k
                && (ctxt->value->type == XPATH_NODESET)
12752
71.6k
                && (ctxt->value->nodesetval != NULL)
12753
71.6k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12754
24.4k
            }
12755
12756
71.6k
            arg2 = valuePop(ctxt);
12757
71.6k
            arg1 = valuePop(ctxt);
12758
71.6k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12759
71.6k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12760
479
          xmlXPathReleaseObject(ctxt->context, arg1);
12761
479
          xmlXPathReleaseObject(ctxt->context, arg2);
12762
479
                XP_ERROR0(XPATH_INVALID_TYPE);
12763
0
            }
12764
71.2k
            if ((ctxt->context->opLimit != 0) &&
12765
71.2k
                (((arg1->nodesetval != NULL) &&
12766
71.2k
                  (xmlXPathCheckOpLimit(ctxt,
12767
65.4k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12768
71.2k
                 ((arg2->nodesetval != NULL) &&
12769
71.2k
                  (xmlXPathCheckOpLimit(ctxt,
12770
53.1k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12771
3
          xmlXPathReleaseObject(ctxt->context, arg1);
12772
3
          xmlXPathReleaseObject(ctxt->context, arg2);
12773
3
                break;
12774
3
            }
12775
12776
            /* TODO: Check memory error. */
12777
71.2k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12778
71.2k
                                                    arg2->nodesetval);
12779
71.2k
            valuePush(ctxt, arg1);
12780
71.2k
      xmlXPathReleaseObject(ctxt->context, arg2);
12781
            /* optimizer */
12782
71.2k
      if (total > cur)
12783
21.1k
    xmlXPathCompSwap(op);
12784
71.2k
            total += cur;
12785
71.2k
            break;
12786
17.1k
        case XPATH_OP_ROOT:
12787
17.1k
            xmlXPathRoot(ctxt);
12788
17.1k
            break;
12789
7.16k
        case XPATH_OP_NODE:
12790
7.16k
            if (op->ch1 != -1)
12791
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12792
7.16k
      CHECK_ERROR0;
12793
7.16k
            if (op->ch2 != -1)
12794
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12795
7.16k
      CHECK_ERROR0;
12796
7.16k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12797
7.16k
    ctxt->context->node));
12798
7.16k
            break;
12799
89.5k
        case XPATH_OP_COLLECT:{
12800
89.5k
                if (op->ch1 == -1)
12801
0
                    break;
12802
12803
89.5k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12804
89.5k
    CHECK_ERROR0;
12805
12806
88.5k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12807
88.5k
                break;
12808
89.5k
            }
12809
482
        case XPATH_OP_VALUE:
12810
482
            valuePush(ctxt,
12811
482
                      xmlXPathCacheObjectCopy(ctxt->context,
12812
482
      (xmlXPathObjectPtr) op->value4));
12813
482
            break;
12814
44.6k
        case XPATH_OP_SORT:
12815
44.6k
            if (op->ch1 != -1)
12816
44.6k
                total +=
12817
44.6k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12818
44.6k
                                           last);
12819
44.6k
      CHECK_ERROR0;
12820
40.5k
            if ((ctxt->value != NULL)
12821
40.5k
                && (ctxt->value->type == XPATH_NODESET)
12822
40.5k
                && (ctxt->value->nodesetval != NULL)
12823
40.5k
    && (ctxt->value->nodesetval->nodeNr > 1))
12824
12.4k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12825
40.5k
            break;
12826
1.90k
        default:
12827
1.90k
            total += xmlXPathCompOpEval(ctxt, op);
12828
1.90k
            break;
12829
237k
    }
12830
12831
226k
    ctxt->context->depth -= 1;
12832
226k
    return (total);
12833
237k
}
12834
12835
#ifdef XP_OPTIMIZED_FILTER_FIRST
12836
static int
12837
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12838
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12839
67.3k
{
12840
67.3k
    int total = 0;
12841
67.3k
    xmlXPathCompExprPtr comp;
12842
67.3k
    xmlXPathObjectPtr obj;
12843
67.3k
    xmlNodeSetPtr set;
12844
12845
67.3k
    CHECK_ERROR0;
12846
67.3k
    comp = ctxt->comp;
12847
    /*
12848
    * Optimization for ()[last()] selection i.e. the last elem
12849
    */
12850
67.3k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12851
67.3k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12852
67.3k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12853
23.2k
  int f = comp->steps[op->ch2].ch1;
12854
12855
23.2k
  if ((f != -1) &&
12856
23.2k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12857
23.2k
      (comp->steps[f].value5 == NULL) &&
12858
23.2k
      (comp->steps[f].value == 0) &&
12859
23.2k
      (comp->steps[f].value4 != NULL) &&
12860
23.2k
      (xmlStrEqual
12861
20.0k
      (comp->steps[f].value4, BAD_CAST "last"))) {
12862
19.3k
      xmlNodePtr last = NULL;
12863
12864
19.3k
      total +=
12865
19.3k
    xmlXPathCompOpEvalLast(ctxt,
12866
19.3k
        &comp->steps[op->ch1],
12867
19.3k
        &last);
12868
19.3k
      CHECK_ERROR0;
12869
      /*
12870
      * The nodeset should be in document order,
12871
      * Keep only the last value
12872
      */
12873
17.9k
      if ((ctxt->value != NULL) &&
12874
17.9k
    (ctxt->value->type == XPATH_NODESET) &&
12875
17.9k
    (ctxt->value->nodesetval != NULL) &&
12876
17.9k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12877
17.9k
    (ctxt->value->nodesetval->nodeNr > 1)) {
12878
3.89k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12879
3.89k
    *first = *(ctxt->value->nodesetval->nodeTab);
12880
3.89k
      }
12881
17.9k
      return (total);
12882
19.3k
  }
12883
23.2k
    }
12884
12885
48.0k
    if (op->ch1 != -1)
12886
48.0k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12887
48.0k
    CHECK_ERROR0;
12888
35.7k
    if (op->ch2 == -1)
12889
0
  return (total);
12890
35.7k
    if (ctxt->value == NULL)
12891
0
  return (total);
12892
12893
#ifdef LIBXML_XPTR_LOCS_ENABLED
12894
    /*
12895
    * Hum are we filtering the result of an XPointer expression
12896
    */
12897
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12898
        xmlLocationSetPtr locset = ctxt->value->user;
12899
12900
        if (locset != NULL) {
12901
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12902
            if (locset->locNr > 0)
12903
                *first = (xmlNodePtr) locset->locTab[0]->user;
12904
        }
12905
12906
  return (total);
12907
    }
12908
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12909
12910
    /*
12911
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12912
     * the stack. We have to temporarily remove the nodeset object from the
12913
     * stack to avoid freeing it prematurely.
12914
     */
12915
35.7k
    CHECK_TYPE0(XPATH_NODESET);
12916
34.7k
    obj = valuePop(ctxt);
12917
34.7k
    set = obj->nodesetval;
12918
34.7k
    if (set != NULL) {
12919
34.4k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12920
34.4k
        if (set->nodeNr > 0)
12921
11.9k
            *first = set->nodeTab[0];
12922
34.4k
    }
12923
34.7k
    valuePush(ctxt, obj);
12924
12925
34.7k
    return (total);
12926
35.7k
}
12927
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12928
12929
/**
12930
 * xmlXPathCompOpEval:
12931
 * @ctxt:  the XPath parser context with the compiled expression
12932
 * @op:  an XPath compiled operation
12933
 *
12934
 * Evaluate the Precompiled XPath operation
12935
 * Returns the number of nodes traversed
12936
 */
12937
static int
12938
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12939
30.5M
{
12940
30.5M
    int total = 0;
12941
30.5M
    int equal, ret;
12942
30.5M
    xmlXPathCompExprPtr comp;
12943
30.5M
    xmlXPathObjectPtr arg1, arg2;
12944
12945
30.5M
    CHECK_ERROR0;
12946
30.5M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12947
429k
        return(0);
12948
30.0M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12949
30.0M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12950
30.0M
    ctxt->context->depth += 1;
12951
30.0M
    comp = ctxt->comp;
12952
30.0M
    switch (op->op) {
12953
0
        case XPATH_OP_END:
12954
0
            break;
12955
67.1k
        case XPATH_OP_AND:
12956
67.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12957
67.1k
      CHECK_ERROR0;
12958
35.2k
            xmlXPathBooleanFunction(ctxt, 1);
12959
35.2k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12960
20.2k
                break;
12961
15.0k
            arg2 = valuePop(ctxt);
12962
15.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12963
15.0k
      if (ctxt->error) {
12964
3.12k
    xmlXPathFreeObject(arg2);
12965
3.12k
    break;
12966
3.12k
      }
12967
11.8k
            xmlXPathBooleanFunction(ctxt, 1);
12968
11.8k
            if (ctxt->value != NULL)
12969
11.8k
                ctxt->value->boolval &= arg2->boolval;
12970
11.8k
      xmlXPathReleaseObject(ctxt->context, arg2);
12971
11.8k
            break;
12972
76.6k
        case XPATH_OP_OR:
12973
76.6k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974
76.6k
      CHECK_ERROR0;
12975
64.1k
            xmlXPathBooleanFunction(ctxt, 1);
12976
64.1k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12977
4.06k
                break;
12978
60.0k
            arg2 = valuePop(ctxt);
12979
60.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12980
60.0k
      if (ctxt->error) {
12981
3.60k
    xmlXPathFreeObject(arg2);
12982
3.60k
    break;
12983
3.60k
      }
12984
56.4k
            xmlXPathBooleanFunction(ctxt, 1);
12985
56.4k
            if (ctxt->value != NULL)
12986
56.3k
                ctxt->value->boolval |= arg2->boolval;
12987
56.4k
      xmlXPathReleaseObject(ctxt->context, arg2);
12988
56.4k
            break;
12989
1.00M
        case XPATH_OP_EQUAL:
12990
1.00M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12991
1.00M
      CHECK_ERROR0;
12992
821k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12993
821k
      CHECK_ERROR0;
12994
691k
      if (op->value)
12995
406k
    equal = xmlXPathEqualValues(ctxt);
12996
284k
      else
12997
284k
    equal = xmlXPathNotEqualValues(ctxt);
12998
691k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12999
691k
            break;
13000
842k
        case XPATH_OP_CMP:
13001
842k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13002
842k
      CHECK_ERROR0;
13003
695k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13004
695k
      CHECK_ERROR0;
13005
640k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13006
640k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13007
640k
            break;
13008
2.13M
        case XPATH_OP_PLUS:
13009
2.13M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13010
2.13M
      CHECK_ERROR0;
13011
1.80M
            if (op->ch2 != -1) {
13012
779k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13013
779k
      }
13014
1.80M
      CHECK_ERROR0;
13015
1.71M
            if (op->value == 0)
13016
546k
                xmlXPathSubValues(ctxt);
13017
1.16M
            else if (op->value == 1)
13018
137k
                xmlXPathAddValues(ctxt);
13019
1.02M
            else if (op->value == 2)
13020
777k
                xmlXPathValueFlipSign(ctxt);
13021
248k
            else if (op->value == 3) {
13022
248k
                CAST_TO_NUMBER;
13023
248k
                CHECK_TYPE0(XPATH_NUMBER);
13024
248k
            }
13025
1.71M
            break;
13026
1.71M
        case XPATH_OP_MULT:
13027
764k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13028
764k
      CHECK_ERROR0;
13029
329k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13030
329k
      CHECK_ERROR0;
13031
320k
            if (op->value == 0)
13032
163k
                xmlXPathMultValues(ctxt);
13033
157k
            else if (op->value == 1)
13034
1.39k
                xmlXPathDivValues(ctxt);
13035
156k
            else if (op->value == 2)
13036
156k
                xmlXPathModValues(ctxt);
13037
320k
            break;
13038
1.13M
        case XPATH_OP_UNION:
13039
1.13M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13040
1.13M
      CHECK_ERROR0;
13041
1.11M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13042
1.11M
      CHECK_ERROR0;
13043
13044
1.06M
            arg2 = valuePop(ctxt);
13045
1.06M
            arg1 = valuePop(ctxt);
13046
1.06M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13047
1.06M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13048
22.4k
          xmlXPathReleaseObject(ctxt->context, arg1);
13049
22.4k
          xmlXPathReleaseObject(ctxt->context, arg2);
13050
22.4k
                XP_ERROR0(XPATH_INVALID_TYPE);
13051
0
            }
13052
1.04M
            if ((ctxt->context->opLimit != 0) &&
13053
1.04M
                (((arg1->nodesetval != NULL) &&
13054
1.04M
                  (xmlXPathCheckOpLimit(ctxt,
13055
993k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13056
1.04M
                 ((arg2->nodesetval != NULL) &&
13057
1.04M
                  (xmlXPathCheckOpLimit(ctxt,
13058
991k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13059
114
          xmlXPathReleaseObject(ctxt->context, arg1);
13060
114
          xmlXPathReleaseObject(ctxt->context, arg2);
13061
114
                break;
13062
114
            }
13063
13064
1.04M
      if ((arg1->nodesetval == NULL) ||
13065
1.04M
    ((arg2->nodesetval != NULL) &&
13066
993k
     (arg2->nodesetval->nodeNr != 0)))
13067
829k
      {
13068
                /* TODO: Check memory error. */
13069
829k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13070
829k
              arg2->nodesetval);
13071
829k
      }
13072
13073
1.04M
            valuePush(ctxt, arg1);
13074
1.04M
      xmlXPathReleaseObject(ctxt->context, arg2);
13075
1.04M
            break;
13076
1.89M
        case XPATH_OP_ROOT:
13077
1.89M
            xmlXPathRoot(ctxt);
13078
1.89M
            break;
13079
5.06M
        case XPATH_OP_NODE:
13080
5.06M
            if (op->ch1 != -1)
13081
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13082
5.06M
      CHECK_ERROR0;
13083
5.06M
            if (op->ch2 != -1)
13084
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13085
5.06M
      CHECK_ERROR0;
13086
5.06M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13087
5.06M
    ctxt->context->node));
13088
5.06M
            break;
13089
4.76M
        case XPATH_OP_COLLECT:{
13090
4.76M
                if (op->ch1 == -1)
13091
0
                    break;
13092
13093
4.76M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13094
4.76M
    CHECK_ERROR0;
13095
13096
4.67M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13097
4.67M
                break;
13098
4.76M
            }
13099
840k
        case XPATH_OP_VALUE:
13100
840k
            valuePush(ctxt,
13101
840k
                      xmlXPathCacheObjectCopy(ctxt->context,
13102
840k
      (xmlXPathObjectPtr) op->value4));
13103
840k
            break;
13104
86.4k
        case XPATH_OP_VARIABLE:{
13105
86.4k
    xmlXPathObjectPtr val;
13106
13107
86.4k
                if (op->ch1 != -1)
13108
0
                    total +=
13109
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13110
86.4k
                if (op->value5 == NULL) {
13111
84.7k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13112
84.7k
        if (val == NULL)
13113
57.1k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13114
57.1k
                    valuePush(ctxt, val);
13115
57.1k
    } else {
13116
1.71k
                    const xmlChar *URI;
13117
13118
1.71k
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13119
1.71k
                    if (URI == NULL) {
13120
1.36k
                        xmlGenericError(xmlGenericErrorContext,
13121
1.36k
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13122
1.36k
                                    (char *) op->value4, (char *)op->value5);
13123
1.36k
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13124
1.36k
                        break;
13125
1.36k
                    }
13126
356
        val = xmlXPathVariableLookupNS(ctxt->context,
13127
356
                                                       op->value4, URI);
13128
356
        if (val == NULL)
13129
356
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13130
0
                    valuePush(ctxt, val);
13131
0
                }
13132
57.1k
                break;
13133
86.4k
            }
13134
2.36M
        case XPATH_OP_FUNCTION:{
13135
2.36M
                xmlXPathFunction func;
13136
2.36M
                const xmlChar *oldFunc, *oldFuncURI;
13137
2.36M
    int i;
13138
2.36M
                int frame;
13139
13140
2.36M
                frame = ctxt->valueNr;
13141
2.36M
                if (op->ch1 != -1) {
13142
1.87M
                    total +=
13143
1.87M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13144
1.87M
                    if (ctxt->error != XPATH_EXPRESSION_OK)
13145
69.0k
                        break;
13146
1.87M
                }
13147
2.29M
    if (ctxt->valueNr < frame + op->value) {
13148
0
        xmlGenericError(xmlGenericErrorContext,
13149
0
          "xmlXPathCompOpEval: parameter error\n");
13150
0
        ctxt->error = XPATH_INVALID_OPERAND;
13151
0
        break;
13152
0
    }
13153
5.34M
    for (i = 0; i < op->value; i++) {
13154
3.05M
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13155
0
      xmlGenericError(xmlGenericErrorContext,
13156
0
        "xmlXPathCompOpEval: parameter error\n");
13157
0
      ctxt->error = XPATH_INVALID_OPERAND;
13158
0
      break;
13159
0
        }
13160
3.05M
                }
13161
2.29M
                if (op->cache != NULL)
13162
1.73M
                    func = op->cache;
13163
558k
                else {
13164
558k
                    const xmlChar *URI = NULL;
13165
13166
558k
                    if (op->value5 == NULL)
13167
56.6k
                        func =
13168
56.6k
                            xmlXPathFunctionLookup(ctxt->context,
13169
56.6k
                                                   op->value4);
13170
501k
                    else {
13171
501k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13172
501k
                        if (URI == NULL) {
13173
35.8k
                            xmlGenericError(xmlGenericErrorContext,
13174
35.8k
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13175
35.8k
                                    (char *)op->value4, (char *)op->value5);
13176
35.8k
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13177
35.8k
                            break;
13178
35.8k
                        }
13179
465k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13180
465k
                                                        op->value4, URI);
13181
465k
                    }
13182
522k
                    if (func == NULL) {
13183
46.0k
                        xmlGenericError(xmlGenericErrorContext,
13184
46.0k
                                "xmlXPathCompOpEval: function %s not found\n",
13185
46.0k
                                        (char *)op->value4);
13186
46.0k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13187
0
                    }
13188
476k
                    op->cache = func;
13189
476k
                    op->cacheURI = (void *) URI;
13190
476k
                }
13191
2.21M
                oldFunc = ctxt->context->function;
13192
2.21M
                oldFuncURI = ctxt->context->functionURI;
13193
2.21M
                ctxt->context->function = op->value4;
13194
2.21M
                ctxt->context->functionURI = op->cacheURI;
13195
2.21M
                func(ctxt, op->value);
13196
2.21M
                ctxt->context->function = oldFunc;
13197
2.21M
                ctxt->context->functionURI = oldFuncURI;
13198
2.21M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13199
2.21M
                    (ctxt->valueNr != frame + 1))
13200
2.20M
                    XP_ERROR0(XPATH_STACK_ERROR);
13201
2.20M
                break;
13202
2.21M
            }
13203
3.18M
        case XPATH_OP_ARG:
13204
3.18M
            if (op->ch1 != -1) {
13205
1.30M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206
1.30M
          CHECK_ERROR0;
13207
1.30M
            }
13208
3.13M
            if (op->ch2 != -1) {
13209
3.13M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13210
3.13M
          CHECK_ERROR0;
13211
3.13M
      }
13212
3.07M
            break;
13213
3.07M
        case XPATH_OP_PREDICATE:
13214
262k
        case XPATH_OP_FILTER:{
13215
262k
                xmlXPathObjectPtr obj;
13216
262k
                xmlNodeSetPtr set;
13217
13218
                /*
13219
                 * Optimization for ()[1] selection i.e. the first elem
13220
                 */
13221
262k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13222
262k
#ifdef XP_OPTIMIZED_FILTER_FIRST
13223
        /*
13224
        * FILTER TODO: Can we assume that the inner processing
13225
        *  will result in an ordered list if we have an
13226
        *  XPATH_OP_FILTER?
13227
        *  What about an additional field or flag on
13228
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13229
        *  to assume anything, so it would be more robust and
13230
        *  easier to optimize.
13231
        */
13232
262k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13233
262k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13234
#else
13235
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13236
#endif
13237
262k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13238
142k
                    xmlXPathObjectPtr val;
13239
13240
142k
                    val = comp->steps[op->ch2].value4;
13241
142k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13242
142k
                        (val->floatval == 1.0)) {
13243
86.6k
                        xmlNodePtr first = NULL;
13244
13245
86.6k
                        total +=
13246
86.6k
                            xmlXPathCompOpEvalFirst(ctxt,
13247
86.6k
                                                    &comp->steps[op->ch1],
13248
86.6k
                                                    &first);
13249
86.6k
      CHECK_ERROR0;
13250
                        /*
13251
                         * The nodeset should be in document order,
13252
                         * Keep only the first value
13253
                         */
13254
66.5k
                        if ((ctxt->value != NULL) &&
13255
66.5k
                            (ctxt->value->type == XPATH_NODESET) &&
13256
66.5k
                            (ctxt->value->nodesetval != NULL) &&
13257
66.5k
                            (ctxt->value->nodesetval->nodeNr > 1))
13258
6.34k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13259
6.34k
                                                        1, 1);
13260
66.5k
                        break;
13261
86.6k
                    }
13262
142k
                }
13263
                /*
13264
                 * Optimization for ()[last()] selection i.e. the last elem
13265
                 */
13266
176k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13267
176k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13268
176k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13269
30.9k
                    int f = comp->steps[op->ch2].ch1;
13270
13271
30.9k
                    if ((f != -1) &&
13272
30.9k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13273
30.9k
                        (comp->steps[f].value5 == NULL) &&
13274
30.9k
                        (comp->steps[f].value == 0) &&
13275
30.9k
                        (comp->steps[f].value4 != NULL) &&
13276
30.9k
                        (xmlStrEqual
13277
25.9k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13278
25.4k
                        xmlNodePtr last = NULL;
13279
13280
25.4k
                        total +=
13281
25.4k
                            xmlXPathCompOpEvalLast(ctxt,
13282
25.4k
                                                   &comp->steps[op->ch1],
13283
25.4k
                                                   &last);
13284
25.4k
      CHECK_ERROR0;
13285
                        /*
13286
                         * The nodeset should be in document order,
13287
                         * Keep only the last value
13288
                         */
13289
22.5k
                        if ((ctxt->value != NULL) &&
13290
22.5k
                            (ctxt->value->type == XPATH_NODESET) &&
13291
22.5k
                            (ctxt->value->nodesetval != NULL) &&
13292
22.5k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13293
22.5k
                            (ctxt->value->nodesetval->nodeNr > 1))
13294
8.54k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13295
22.5k
                        break;
13296
25.4k
                    }
13297
30.9k
                }
13298
    /*
13299
    * Process inner predicates first.
13300
    * Example "index[parent::book][1]":
13301
    * ...
13302
    *   PREDICATE   <-- we are here "[1]"
13303
    *     PREDICATE <-- process "[parent::book]" first
13304
    *       SORT
13305
    *         COLLECT  'parent' 'name' 'node' book
13306
    *           NODE
13307
    *     ELEM Object is a number : 1
13308
    */
13309
150k
                if (op->ch1 != -1)
13310
150k
                    total +=
13311
150k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13312
150k
    CHECK_ERROR0;
13313
137k
                if (op->ch2 == -1)
13314
0
                    break;
13315
137k
                if (ctxt->value == NULL)
13316
0
                    break;
13317
13318
#ifdef LIBXML_XPTR_LOCS_ENABLED
13319
                /*
13320
                 * Hum are we filtering the result of an XPointer expression
13321
                 */
13322
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13323
                    xmlLocationSetPtr locset = ctxt->value->user;
13324
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13325
                                              1, locset->locNr);
13326
                    break;
13327
                }
13328
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13329
13330
                /*
13331
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
13332
                 * nodes from the stack. We have to temporarily remove the
13333
                 * nodeset object from the stack to avoid freeing it
13334
                 * prematurely.
13335
                 */
13336
137k
                CHECK_TYPE0(XPATH_NODESET);
13337
126k
                obj = valuePop(ctxt);
13338
126k
                set = obj->nodesetval;
13339
126k
                if (set != NULL)
13340
123k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13341
123k
                                          1, set->nodeNr, 1);
13342
126k
                valuePush(ctxt, obj);
13343
126k
                break;
13344
137k
            }
13345
5.54M
        case XPATH_OP_SORT:
13346
5.54M
            if (op->ch1 != -1)
13347
5.54M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13348
5.54M
      CHECK_ERROR0;
13349
5.12M
            if ((ctxt->value != NULL) &&
13350
5.12M
                (ctxt->value->type == XPATH_NODESET) &&
13351
5.12M
                (ctxt->value->nodesetval != NULL) &&
13352
5.12M
    (ctxt->value->nodesetval->nodeNr > 1))
13353
810k
      {
13354
810k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13355
810k
      }
13356
5.12M
            break;
13357
#ifdef LIBXML_XPTR_LOCS_ENABLED
13358
        case XPATH_OP_RANGETO:{
13359
                xmlXPathObjectPtr range;
13360
                xmlXPathObjectPtr res, obj;
13361
                xmlXPathObjectPtr tmp;
13362
                xmlLocationSetPtr newlocset = NULL;
13363
        xmlLocationSetPtr oldlocset;
13364
                xmlNodeSetPtr oldset;
13365
                xmlNodePtr oldnode = ctxt->context->node;
13366
                int oldcs = ctxt->context->contextSize;
13367
                int oldpp = ctxt->context->proximityPosition;
13368
                int i, j;
13369
13370
                if (op->ch1 != -1) {
13371
                    total +=
13372
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13373
                    CHECK_ERROR0;
13374
                }
13375
                if (ctxt->value == NULL) {
13376
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13377
                }
13378
                if (op->ch2 == -1)
13379
                    break;
13380
13381
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13382
                    /*
13383
                     * Extract the old locset, and then evaluate the result of the
13384
                     * expression for all the element in the locset. use it to grow
13385
                     * up a new locset.
13386
                     */
13387
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13388
13389
                    if ((ctxt->value->user == NULL) ||
13390
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13391
                        break;
13392
13393
                    obj = valuePop(ctxt);
13394
                    oldlocset = obj->user;
13395
13396
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13397
13398
                    for (i = 0; i < oldlocset->locNr; i++) {
13399
                        /*
13400
                         * Run the evaluation with a node list made of a
13401
                         * single item in the nodelocset.
13402
                         */
13403
                        ctxt->context->node = oldlocset->locTab[i]->user;
13404
                        ctxt->context->contextSize = oldlocset->locNr;
13405
                        ctxt->context->proximityPosition = i + 1;
13406
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13407
          ctxt->context->node);
13408
                        valuePush(ctxt, tmp);
13409
13410
                        if (op->ch2 != -1)
13411
                            total +=
13412
                                xmlXPathCompOpEval(ctxt,
13413
                                                   &comp->steps[op->ch2]);
13414
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13415
                            xmlXPtrFreeLocationSet(newlocset);
13416
                            goto rangeto_error;
13417
      }
13418
13419
                        res = valuePop(ctxt);
13420
      if (res->type == XPATH_LOCATIONSET) {
13421
          xmlLocationSetPtr rloc =
13422
              (xmlLocationSetPtr)res->user;
13423
          for (j=0; j<rloc->locNr; j++) {
13424
              range = xmlXPtrNewRange(
13425
          oldlocset->locTab[i]->user,
13426
          oldlocset->locTab[i]->index,
13427
          rloc->locTab[j]->user2,
13428
          rloc->locTab[j]->index2);
13429
        if (range != NULL) {
13430
            xmlXPtrLocationSetAdd(newlocset, range);
13431
        }
13432
          }
13433
      } else {
13434
          range = xmlXPtrNewRangeNodeObject(
13435
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13436
                            if (range != NULL) {
13437
                                xmlXPtrLocationSetAdd(newlocset,range);
13438
          }
13439
                        }
13440
13441
                        /*
13442
                         * Cleanup
13443
                         */
13444
                        if (res != NULL) {
13445
          xmlXPathReleaseObject(ctxt->context, res);
13446
      }
13447
                        if (ctxt->value == tmp) {
13448
                            res = valuePop(ctxt);
13449
          xmlXPathReleaseObject(ctxt->context, res);
13450
                        }
13451
                    }
13452
    } else {  /* Not a location set */
13453
                    CHECK_TYPE0(XPATH_NODESET);
13454
                    obj = valuePop(ctxt);
13455
                    oldset = obj->nodesetval;
13456
13457
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13458
13459
                    if (oldset != NULL) {
13460
                        for (i = 0; i < oldset->nodeNr; i++) {
13461
                            /*
13462
                             * Run the evaluation with a node list made of a single item
13463
                             * in the nodeset.
13464
                             */
13465
                            ctxt->context->node = oldset->nodeTab[i];
13466
          /*
13467
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13468
          */
13469
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13470
        ctxt->context->node);
13471
                            valuePush(ctxt, tmp);
13472
13473
                            if (op->ch2 != -1)
13474
                                total +=
13475
                                    xmlXPathCompOpEval(ctxt,
13476
                                                   &comp->steps[op->ch2]);
13477
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13478
                                xmlXPtrFreeLocationSet(newlocset);
13479
                                goto rangeto_error;
13480
          }
13481
13482
                            res = valuePop(ctxt);
13483
                            range =
13484
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13485
                                                      res);
13486
                            if (range != NULL) {
13487
                                xmlXPtrLocationSetAdd(newlocset, range);
13488
                            }
13489
13490
                            /*
13491
                             * Cleanup
13492
                             */
13493
                            if (res != NULL) {
13494
        xmlXPathReleaseObject(ctxt->context, res);
13495
          }
13496
                            if (ctxt->value == tmp) {
13497
                                res = valuePop(ctxt);
13498
        xmlXPathReleaseObject(ctxt->context, res);
13499
                            }
13500
                        }
13501
                    }
13502
                }
13503
13504
                /*
13505
                 * The result is used as the new evaluation set.
13506
                 */
13507
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13508
rangeto_error:
13509
    xmlXPathReleaseObject(ctxt->context, obj);
13510
                ctxt->context->node = oldnode;
13511
                ctxt->context->contextSize = oldcs;
13512
                ctxt->context->proximityPosition = oldpp;
13513
                break;
13514
            }
13515
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13516
0
        default:
13517
0
            xmlGenericError(xmlGenericErrorContext,
13518
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13519
0
            ctxt->error = XPATH_INVALID_OPERAND;
13520
0
            break;
13521
30.0M
    }
13522
13523
27.7M
    ctxt->context->depth -= 1;
13524
27.7M
    return (total);
13525
30.0M
}
13526
13527
/**
13528
 * xmlXPathCompOpEvalToBoolean:
13529
 * @ctxt:  the XPath parser context
13530
 *
13531
 * Evaluates if the expression evaluates to true.
13532
 *
13533
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13534
 */
13535
static int
13536
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13537
          xmlXPathStepOpPtr op,
13538
          int isPredicate)
13539
1.16M
{
13540
1.16M
    xmlXPathObjectPtr resObj = NULL;
13541
13542
1.41M
start:
13543
1.41M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13544
401
        return(0);
13545
    /* comp = ctxt->comp; */
13546
1.40M
    switch (op->op) {
13547
0
        case XPATH_OP_END:
13548
0
            return (0);
13549
210k
  case XPATH_OP_VALUE:
13550
210k
      resObj = (xmlXPathObjectPtr) op->value4;
13551
210k
      if (isPredicate)
13552
210k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13553
43
      return(xmlXPathCastToBoolean(resObj));
13554
243k
  case XPATH_OP_SORT:
13555
      /*
13556
      * We don't need sorting for boolean results. Skip this one.
13557
      */
13558
243k
            if (op->ch1 != -1) {
13559
243k
    op = &ctxt->comp->steps[op->ch1];
13560
243k
    goto start;
13561
243k
      }
13562
0
      return(0);
13563
173k
  case XPATH_OP_COLLECT:
13564
173k
      if (op->ch1 == -1)
13565
0
    return(0);
13566
13567
173k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13568
173k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13569
2.02k
    return(-1);
13570
13571
171k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13572
171k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13573
931
    return(-1);
13574
13575
170k
      resObj = valuePop(ctxt);
13576
170k
      if (resObj == NULL)
13577
0
    return(-1);
13578
170k
      break;
13579
782k
  default:
13580
      /*
13581
      * Fallback to call xmlXPathCompOpEval().
13582
      */
13583
782k
      xmlXPathCompOpEval(ctxt, op);
13584
782k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13585
8.62k
    return(-1);
13586
13587
773k
      resObj = valuePop(ctxt);
13588
773k
      if (resObj == NULL)
13589
0
    return(-1);
13590
773k
      break;
13591
1.40M
    }
13592
13593
943k
    if (resObj) {
13594
943k
  int res;
13595
13596
943k
  if (resObj->type == XPATH_BOOLEAN) {
13597
115k
      res = resObj->boolval;
13598
828k
  } else if (isPredicate) {
13599
      /*
13600
      * For predicates a result of type "number" is handled
13601
      * differently:
13602
      * SPEC XPath 1.0:
13603
      * "If the result is a number, the result will be converted
13604
      *  to true if the number is equal to the context position
13605
      *  and will be converted to false otherwise;"
13606
      */
13607
827k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13608
827k
  } else {
13609
690
      res = xmlXPathCastToBoolean(resObj);
13610
690
  }
13611
943k
  xmlXPathReleaseObject(ctxt->context, resObj);
13612
943k
  return(res);
13613
943k
    }
13614
13615
0
    return(0);
13616
943k
}
13617
13618
#ifdef XPATH_STREAMING
13619
/**
13620
 * xmlXPathRunStreamEval:
13621
 * @ctxt:  the XPath parser context with the compiled expression
13622
 *
13623
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13624
 */
13625
static int
13626
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13627
          xmlXPathObjectPtr *resultSeq, int toBool)
13628
2.22M
{
13629
2.22M
    int max_depth, min_depth;
13630
2.22M
    int from_root;
13631
2.22M
    int ret, depth;
13632
2.22M
    int eval_all_nodes;
13633
2.22M
    xmlNodePtr cur = NULL, limit = NULL;
13634
2.22M
    xmlStreamCtxtPtr patstream = NULL;
13635
13636
2.22M
    if ((ctxt == NULL) || (comp == NULL))
13637
0
        return(-1);
13638
2.22M
    max_depth = xmlPatternMaxDepth(comp);
13639
2.22M
    if (max_depth == -1)
13640
0
        return(-1);
13641
2.22M
    if (max_depth == -2)
13642
10.2k
        max_depth = 10000;
13643
2.22M
    min_depth = xmlPatternMinDepth(comp);
13644
2.22M
    if (min_depth == -1)
13645
0
        return(-1);
13646
2.22M
    from_root = xmlPatternFromRoot(comp);
13647
2.22M
    if (from_root < 0)
13648
0
        return(-1);
13649
#if 0
13650
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13651
#endif
13652
13653
2.22M
    if (! toBool) {
13654
2.22M
  if (resultSeq == NULL)
13655
0
      return(-1);
13656
2.22M
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13657
2.22M
  if (*resultSeq == NULL)
13658
44
      return(-1);
13659
2.22M
    }
13660
13661
    /*
13662
     * handle the special cases of "/" amd "." being matched
13663
     */
13664
2.22M
    if (min_depth == 0) {
13665
561k
  if (from_root) {
13666
      /* Select "/" */
13667
0
      if (toBool)
13668
0
    return(1);
13669
            /* TODO: Check memory error. */
13670
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13671
0
                         (xmlNodePtr) ctxt->doc);
13672
561k
  } else {
13673
      /* Select "self::node()" */
13674
561k
      if (toBool)
13675
0
    return(1);
13676
            /* TODO: Check memory error. */
13677
561k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13678
561k
  }
13679
561k
    }
13680
2.22M
    if (max_depth == 0) {
13681
207k
  return(0);
13682
207k
    }
13683
13684
2.01M
    if (from_root) {
13685
31.7k
        cur = (xmlNodePtr)ctxt->doc;
13686
1.98M
    } else if (ctxt->node != NULL) {
13687
1.98M
        switch (ctxt->node->type) {
13688
1.01M
            case XML_ELEMENT_NODE:
13689
1.02M
            case XML_DOCUMENT_NODE:
13690
1.02M
            case XML_DOCUMENT_FRAG_NODE:
13691
1.02M
            case XML_HTML_DOCUMENT_NODE:
13692
1.02M
          cur = ctxt->node;
13693
1.02M
    break;
13694
31
            case XML_ATTRIBUTE_NODE:
13695
933k
            case XML_TEXT_NODE:
13696
933k
            case XML_CDATA_SECTION_NODE:
13697
933k
            case XML_ENTITY_REF_NODE:
13698
933k
            case XML_ENTITY_NODE:
13699
941k
            case XML_PI_NODE:
13700
961k
            case XML_COMMENT_NODE:
13701
961k
            case XML_NOTATION_NODE:
13702
961k
            case XML_DTD_NODE:
13703
961k
            case XML_DOCUMENT_TYPE_NODE:
13704
961k
            case XML_ELEMENT_DECL:
13705
961k
            case XML_ATTRIBUTE_DECL:
13706
961k
            case XML_ENTITY_DECL:
13707
961k
            case XML_NAMESPACE_DECL:
13708
961k
            case XML_XINCLUDE_START:
13709
961k
            case XML_XINCLUDE_END:
13710
961k
    break;
13711
1.98M
  }
13712
1.98M
  limit = cur;
13713
1.98M
    }
13714
2.01M
    if (cur == NULL) {
13715
961k
        return(0);
13716
961k
    }
13717
13718
1.05M
    patstream = xmlPatternGetStreamCtxt(comp);
13719
1.05M
    if (patstream == NULL) {
13720
  /*
13721
  * QUESTION TODO: Is this an error?
13722
  */
13723
106
  return(0);
13724
106
    }
13725
13726
1.05M
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13727
13728
1.05M
    if (from_root) {
13729
31.7k
  ret = xmlStreamPush(patstream, NULL, NULL);
13730
31.7k
  if (ret < 0) {
13731
31.7k
  } else if (ret == 1) {
13732
1.78k
      if (toBool)
13733
0
    goto return_1;
13734
            /* TODO: Check memory error. */
13735
1.78k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13736
1.78k
  }
13737
31.7k
    }
13738
1.05M
    depth = 0;
13739
1.05M
    goto scan_children;
13740
2.17M
next_node:
13741
3.40M
    do {
13742
3.40M
        if (ctxt->opLimit != 0) {
13743
3.40M
            if (ctxt->opCount >= ctxt->opLimit) {
13744
898
                xmlGenericError(xmlGenericErrorContext,
13745
898
                        "XPath operation limit exceeded\n");
13746
898
                xmlFreeStreamCtxt(patstream);
13747
898
                return(-1);
13748
898
            }
13749
3.40M
            ctxt->opCount++;
13750
3.40M
        }
13751
13752
3.40M
  switch (cur->type) {
13753
1.56M
      case XML_ELEMENT_NODE:
13754
3.34M
      case XML_TEXT_NODE:
13755
3.34M
      case XML_CDATA_SECTION_NODE:
13756
3.37M
      case XML_COMMENT_NODE:
13757
3.40M
      case XML_PI_NODE:
13758
3.40M
    if (cur->type == XML_ELEMENT_NODE) {
13759
1.56M
        ret = xmlStreamPush(patstream, cur->name,
13760
1.56M
        (cur->ns ? cur->ns->href : NULL));
13761
1.83M
    } else if (eval_all_nodes)
13762
215k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13763
1.62M
    else
13764
1.62M
        break;
13765
13766
1.77M
    if (ret < 0) {
13767
        /* NOP. */
13768
1.77M
    } else if (ret == 1) {
13769
353k
        if (toBool)
13770
73
      goto return_1;
13771
353k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13772
353k
            < 0) {
13773
829
      ctxt->lastError.domain = XML_FROM_XPATH;
13774
829
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13775
829
        }
13776
353k
    }
13777
1.77M
    if ((cur->children == NULL) || (depth >= max_depth)) {
13778
1.49M
        ret = xmlStreamPop(patstream);
13779
1.49M
        while (cur->next != NULL) {
13780
1.24M
      cur = cur->next;
13781
1.24M
      if ((cur->type != XML_ENTITY_DECL) &&
13782
1.24M
          (cur->type != XML_DTD_NODE))
13783
1.24M
          goto next_node;
13784
1.24M
        }
13785
1.49M
    }
13786
526k
      default:
13787
526k
    break;
13788
3.40M
  }
13789
13790
3.20M
scan_children:
13791
3.20M
  if (cur->type == XML_NAMESPACE_DECL) break;
13792
3.20M
  if ((cur->children != NULL) && (depth < max_depth)) {
13793
      /*
13794
       * Do not descend on entities declarations
13795
       */
13796
1.00M
      if (cur->children->type != XML_ENTITY_DECL) {
13797
1.00M
    cur = cur->children;
13798
1.00M
    depth++;
13799
    /*
13800
     * Skip DTDs
13801
     */
13802
1.00M
    if (cur->type != XML_DTD_NODE)
13803
1.00M
        continue;
13804
1.00M
      }
13805
1.00M
  }
13806
13807
2.19M
  if (cur == limit)
13808
323k
      break;
13809
13810
1.87M
  while (cur->next != NULL) {
13811
922k
      cur = cur->next;
13812
922k
      if ((cur->type != XML_ENTITY_DECL) &&
13813
922k
    (cur->type != XML_DTD_NODE))
13814
922k
    goto next_node;
13815
922k
  }
13816
13817
1.00M
  do {
13818
1.00M
      cur = cur->parent;
13819
1.00M
      depth--;
13820
1.00M
      if ((cur == NULL) || (cur == limit) ||
13821
1.00M
                (cur->type == XML_DOCUMENT_NODE))
13822
731k
          goto done;
13823
276k
      if (cur->type == XML_ELEMENT_NODE) {
13824
276k
    ret = xmlStreamPop(patstream);
13825
276k
      } else if ((eval_all_nodes) &&
13826
0
    ((cur->type == XML_TEXT_NODE) ||
13827
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13828
0
     (cur->type == XML_COMMENT_NODE) ||
13829
0
     (cur->type == XML_PI_NODE)))
13830
0
      {
13831
0
    ret = xmlStreamPop(patstream);
13832
0
      }
13833
276k
      if (cur->next != NULL) {
13834
220k
    cur = cur->next;
13835
220k
    break;
13836
220k
      }
13837
276k
  } while (cur != NULL);
13838
13839
1.22M
    } while ((cur != NULL) && (depth >= 0));
13840
13841
1.05M
done:
13842
13843
1.05M
    if (patstream)
13844
1.05M
  xmlFreeStreamCtxt(patstream);
13845
1.05M
    return(0);
13846
13847
73
return_1:
13848
73
    if (patstream)
13849
73
  xmlFreeStreamCtxt(patstream);
13850
73
    return(1);
13851
2.17M
}
13852
#endif /* XPATH_STREAMING */
13853
13854
/**
13855
 * xmlXPathRunEval:
13856
 * @ctxt:  the XPath parser context with the compiled expression
13857
 * @toBool:  evaluate to a boolean result
13858
 *
13859
 * Evaluate the Precompiled XPath expression in the given context.
13860
 */
13861
static int
13862
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13863
4.99M
{
13864
4.99M
    xmlXPathCompExprPtr comp;
13865
4.99M
    int oldDepth;
13866
13867
4.99M
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13868
0
  return(-1);
13869
13870
4.99M
    if (ctxt->valueTab == NULL) {
13871
  /* Allocate the value stack */
13872
20.6k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13873
20.6k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13874
20.6k
  if (ctxt->valueTab == NULL) {
13875
14
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13876
14
      return(-1);
13877
14
  }
13878
20.6k
  ctxt->valueNr = 0;
13879
20.6k
  ctxt->valueMax = 10;
13880
20.6k
  ctxt->value = NULL;
13881
20.6k
    }
13882
4.99M
#ifdef XPATH_STREAMING
13883
4.99M
    if (ctxt->comp->stream) {
13884
2.22M
  int res;
13885
13886
2.22M
  if (toBool) {
13887
      /*
13888
      * Evaluation to boolean result.
13889
      */
13890
83
      res = xmlXPathRunStreamEval(ctxt->context,
13891
83
    ctxt->comp->stream, NULL, 1);
13892
83
      if (res != -1)
13893
83
    return(res);
13894
2.22M
  } else {
13895
2.22M
      xmlXPathObjectPtr resObj = NULL;
13896
13897
      /*
13898
      * Evaluation to a sequence.
13899
      */
13900
2.22M
      res = xmlXPathRunStreamEval(ctxt->context,
13901
2.22M
    ctxt->comp->stream, &resObj, 0);
13902
13903
2.22M
      if ((res != -1) && (resObj != NULL)) {
13904
2.22M
    valuePush(ctxt, resObj);
13905
2.22M
    return(0);
13906
2.22M
      }
13907
942
      if (resObj != NULL)
13908
898
    xmlXPathReleaseObject(ctxt->context, resObj);
13909
942
  }
13910
  /*
13911
  * QUESTION TODO: This falls back to normal XPath evaluation
13912
  * if res == -1. Is this intended?
13913
  */
13914
2.22M
    }
13915
2.76M
#endif
13916
2.76M
    comp = ctxt->comp;
13917
2.76M
    if (comp->last < 0) {
13918
942
  xmlGenericError(xmlGenericErrorContext,
13919
942
      "xmlXPathRunEval: last is less than zero\n");
13920
942
  return(-1);
13921
942
    }
13922
2.76M
    oldDepth = ctxt->context->depth;
13923
2.76M
    if (toBool)
13924
21.1k
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13925
21.1k
      &comp->steps[comp->last], 0));
13926
2.74M
    else
13927
2.74M
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13928
2.74M
    ctxt->context->depth = oldDepth;
13929
13930
2.74M
    return(0);
13931
2.76M
}
13932
13933
/************************************************************************
13934
 *                  *
13935
 *      Public interfaces       *
13936
 *                  *
13937
 ************************************************************************/
13938
13939
/**
13940
 * xmlXPathEvalPredicate:
13941
 * @ctxt:  the XPath context
13942
 * @res:  the Predicate Expression evaluation result
13943
 *
13944
 * Evaluate a predicate result for the current node.
13945
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13946
 * the result to a boolean. If the result is a number, the result will
13947
 * be converted to true if the number is equal to the position of the
13948
 * context node in the context node list (as returned by the position
13949
 * function) and will be converted to false otherwise; if the result
13950
 * is not a number, then the result will be converted as if by a call
13951
 * to the boolean function.
13952
 *
13953
 * Returns 1 if predicate is true, 0 otherwise
13954
 */
13955
int
13956
25.5k
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13957
25.5k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13958
25.5k
    switch (res->type) {
13959
13.8k
        case XPATH_BOOLEAN:
13960
13.8k
      return(res->boolval);
13961
5.98k
        case XPATH_NUMBER:
13962
5.98k
      return(res->floatval == ctxt->proximityPosition);
13963
2.83k
        case XPATH_NODESET:
13964
2.83k
        case XPATH_XSLT_TREE:
13965
2.83k
      if (res->nodesetval == NULL)
13966
687
    return(0);
13967
2.14k
      return(res->nodesetval->nodeNr != 0);
13968
2.88k
        case XPATH_STRING:
13969
2.88k
      return((res->stringval != NULL) &&
13970
2.88k
             (xmlStrlen(res->stringval) != 0));
13971
0
        default:
13972
0
      STRANGE
13973
25.5k
    }
13974
0
    return(0);
13975
25.5k
}
13976
13977
/**
13978
 * xmlXPathEvaluatePredicateResult:
13979
 * @ctxt:  the XPath Parser context
13980
 * @res:  the Predicate Expression evaluation result
13981
 *
13982
 * Evaluate a predicate result for the current node.
13983
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13984
 * the result to a boolean. If the result is a number, the result will
13985
 * be converted to true if the number is equal to the position of the
13986
 * context node in the context node list (as returned by the position
13987
 * function) and will be converted to false otherwise; if the result
13988
 * is not a number, then the result will be converted as if by a call
13989
 * to the boolean function.
13990
 *
13991
 * Returns 1 if predicate is true, 0 otherwise
13992
 */
13993
int
13994
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13995
1.03M
                                xmlXPathObjectPtr res) {
13996
1.03M
    if ((ctxt == NULL) || (res == NULL)) return(0);
13997
1.03M
    switch (res->type) {
13998
0
        case XPATH_BOOLEAN:
13999
0
      return(res->boolval);
14000
656k
        case XPATH_NUMBER:
14001
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14002
      return((res->floatval == ctxt->context->proximityPosition) &&
14003
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14004
#else
14005
656k
      return(res->floatval == ctxt->context->proximityPosition);
14006
0
#endif
14007
216k
        case XPATH_NODESET:
14008
216k
        case XPATH_XSLT_TREE:
14009
216k
      if (res->nodesetval == NULL)
14010
22.4k
    return(0);
14011
193k
      return(res->nodesetval->nodeNr != 0);
14012
165k
        case XPATH_STRING:
14013
165k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14014
#ifdef LIBXML_XPTR_LOCS_ENABLED
14015
  case XPATH_LOCATIONSET:{
14016
      xmlLocationSetPtr ptr = res->user;
14017
      if (ptr == NULL)
14018
          return(0);
14019
      return (ptr->locNr != 0);
14020
      }
14021
#endif
14022
0
        default:
14023
0
      STRANGE
14024
1.03M
    }
14025
0
    return(0);
14026
1.03M
}
14027
14028
#ifdef XPATH_STREAMING
14029
/**
14030
 * xmlXPathTryStreamCompile:
14031
 * @ctxt: an XPath context
14032
 * @str:  the XPath expression
14033
 *
14034
 * Try to compile the XPath expression as a streamable subset.
14035
 *
14036
 * Returns the compiled expression or NULL if failed to compile.
14037
 */
14038
static xmlXPathCompExprPtr
14039
1.15M
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14040
    /*
14041
     * Optimization: use streaming patterns when the XPath expression can
14042
     * be compiled to a stream lookup
14043
     */
14044
1.15M
    xmlPatternPtr stream;
14045
1.15M
    xmlXPathCompExprPtr comp;
14046
1.15M
    xmlDictPtr dict = NULL;
14047
1.15M
    const xmlChar **namespaces = NULL;
14048
1.15M
    xmlNsPtr ns;
14049
1.15M
    int i, j;
14050
14051
1.15M
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14052
1.15M
        (!xmlStrchr(str, '@'))) {
14053
495k
  const xmlChar *tmp;
14054
14055
  /*
14056
   * We don't try to handle expressions using the verbose axis
14057
   * specifiers ("::"), just the simplified form at this point.
14058
   * Additionally, if there is no list of namespaces available and
14059
   *  there's a ":" in the expression, indicating a prefixed QName,
14060
   *  then we won't try to compile either. xmlPatterncompile() needs
14061
   *  to have a list of namespaces at compilation time in order to
14062
   *  compile prefixed name tests.
14063
   */
14064
495k
  tmp = xmlStrchr(str, ':');
14065
495k
  if ((tmp != NULL) &&
14066
495k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14067
9.58k
      return(NULL);
14068
14069
486k
  if (ctxt != NULL) {
14070
486k
      dict = ctxt->dict;
14071
486k
      if (ctxt->nsNr > 0) {
14072
424k
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14073
424k
    if (namespaces == NULL) {
14074
37
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14075
37
        return(NULL);
14076
37
    }
14077
5.11M
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14078
4.68M
        ns = ctxt->namespaces[j];
14079
4.68M
        namespaces[i++] = ns->href;
14080
4.68M
        namespaces[i++] = ns->prefix;
14081
4.68M
    }
14082
424k
    namespaces[i++] = NULL;
14083
424k
    namespaces[i] = NULL;
14084
424k
      }
14085
486k
  }
14086
14087
486k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14088
486k
  if (namespaces != NULL) {
14089
424k
      xmlFree((xmlChar **)namespaces);
14090
424k
  }
14091
486k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14092
200k
      comp = xmlXPathNewCompExpr();
14093
200k
      if (comp == NULL) {
14094
19
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14095
19
          xmlFreePattern(stream);
14096
19
    return(NULL);
14097
19
      }
14098
200k
      comp->stream = stream;
14099
200k
      comp->dict = dict;
14100
200k
      if (comp->dict)
14101
22.5k
    xmlDictReference(comp->dict);
14102
200k
      return(comp);
14103
200k
  }
14104
285k
  xmlFreePattern(stream);
14105
285k
    }
14106
947k
    return(NULL);
14107
1.15M
}
14108
#endif /* XPATH_STREAMING */
14109
14110
static void
14111
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14112
                           xmlXPathStepOpPtr op)
14113
18.8M
{
14114
18.8M
    xmlXPathCompExprPtr comp = pctxt->comp;
14115
18.8M
    xmlXPathContextPtr ctxt;
14116
14117
    /*
14118
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14119
    * internal representation.
14120
    */
14121
14122
18.8M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14123
18.8M
        (op->ch1 != -1) &&
14124
18.8M
        (op->ch2 == -1 /* no predicate */))
14125
3.59M
    {
14126
3.59M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14127
14128
3.59M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14129
3.59M
            ((xmlXPathAxisVal) prevop->value ==
14130
350k
                AXIS_DESCENDANT_OR_SELF) &&
14131
3.59M
            (prevop->ch2 == -1) &&
14132
3.59M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14133
3.59M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14134
221k
        {
14135
            /*
14136
            * This is a "descendant-or-self::node()" without predicates.
14137
            * Try to eliminate it.
14138
            */
14139
14140
221k
            switch ((xmlXPathAxisVal) op->value) {
14141
216k
                case AXIS_CHILD:
14142
216k
                case AXIS_DESCENDANT:
14143
                    /*
14144
                    * Convert "descendant-or-self::node()/child::" or
14145
                    * "descendant-or-self::node()/descendant::" to
14146
                    * "descendant::"
14147
                    */
14148
216k
                    op->ch1   = prevop->ch1;
14149
216k
                    op->value = AXIS_DESCENDANT;
14150
216k
                    break;
14151
0
                case AXIS_SELF:
14152
4
                case AXIS_DESCENDANT_OR_SELF:
14153
                    /*
14154
                    * Convert "descendant-or-self::node()/self::" or
14155
                    * "descendant-or-self::node()/descendant-or-self::" to
14156
                    * to "descendant-or-self::"
14157
                    */
14158
4
                    op->ch1   = prevop->ch1;
14159
4
                    op->value = AXIS_DESCENDANT_OR_SELF;
14160
4
                    break;
14161
4.86k
                default:
14162
4.86k
                    break;
14163
221k
            }
14164
221k
  }
14165
3.59M
    }
14166
14167
    /* OP_VALUE has invalid ch1. */
14168
18.8M
    if (op->op == XPATH_OP_VALUE)
14169
862k
        return;
14170
14171
    /* Recurse */
14172
17.9M
    ctxt = pctxt->context;
14173
17.9M
    if (ctxt != NULL) {
14174
17.9M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14175
105k
            return;
14176
17.8M
        ctxt->depth += 1;
14177
17.8M
    }
14178
17.8M
    if (op->ch1 != -1)
14179
12.2M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14180
17.8M
    if (op->ch2 != -1)
14181
6.17M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14182
17.8M
    if (ctxt != NULL)
14183
17.8M
        ctxt->depth -= 1;
14184
17.8M
}
14185
14186
/**
14187
 * xmlXPathCtxtCompile:
14188
 * @ctxt: an XPath context
14189
 * @str:  the XPath expression
14190
 *
14191
 * Compile an XPath expression
14192
 *
14193
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14194
 *         the caller has to free the object.
14195
 */
14196
xmlXPathCompExprPtr
14197
1.11M
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14198
1.11M
    xmlXPathParserContextPtr pctxt;
14199
1.11M
    xmlXPathCompExprPtr comp;
14200
1.11M
    int oldDepth = 0;
14201
14202
1.11M
#ifdef XPATH_STREAMING
14203
1.11M
    comp = xmlXPathTryStreamCompile(ctxt, str);
14204
1.11M
    if (comp != NULL)
14205
196k
        return(comp);
14206
922k
#endif
14207
14208
922k
    xmlInitParser();
14209
14210
922k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14211
922k
    if (pctxt == NULL)
14212
1.05k
        return NULL;
14213
921k
    if (ctxt != NULL)
14214
921k
        oldDepth = ctxt->depth;
14215
921k
    xmlXPathCompileExpr(pctxt, 1);
14216
921k
    if (ctxt != NULL)
14217
921k
        ctxt->depth = oldDepth;
14218
14219
921k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14220
398k
    {
14221
398k
        xmlXPathFreeParserContext(pctxt);
14222
398k
        return(NULL);
14223
398k
    }
14224
14225
522k
    if (*pctxt->cur != 0) {
14226
  /*
14227
   * aleksey: in some cases this line prints *second* error message
14228
   * (see bug #78858) and probably this should be fixed.
14229
   * However, we are not sure that all error messages are printed
14230
   * out in other places. It's not critical so we leave it as-is for now
14231
   */
14232
151k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14233
151k
  comp = NULL;
14234
370k
    } else {
14235
370k
  comp = pctxt->comp;
14236
370k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14237
357k
            if (ctxt != NULL)
14238
357k
                oldDepth = ctxt->depth;
14239
357k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14240
357k
            if (ctxt != NULL)
14241
357k
                ctxt->depth = oldDepth;
14242
357k
  }
14243
370k
  pctxt->comp = NULL;
14244
370k
    }
14245
522k
    xmlXPathFreeParserContext(pctxt);
14246
14247
522k
    if (comp != NULL) {
14248
370k
  comp->expr = xmlStrdup(str);
14249
#ifdef DEBUG_EVAL_COUNTS
14250
  comp->string = xmlStrdup(str);
14251
  comp->nb = 0;
14252
#endif
14253
370k
    }
14254
522k
    return(comp);
14255
921k
}
14256
14257
/**
14258
 * xmlXPathCompile:
14259
 * @str:  the XPath expression
14260
 *
14261
 * Compile an XPath expression
14262
 *
14263
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14264
 *         the caller has to free the object.
14265
 */
14266
xmlXPathCompExprPtr
14267
0
xmlXPathCompile(const xmlChar *str) {
14268
0
    return(xmlXPathCtxtCompile(NULL, str));
14269
0
}
14270
14271
/**
14272
 * xmlXPathCompiledEvalInternal:
14273
 * @comp:  the compiled XPath expression
14274
 * @ctxt:  the XPath context
14275
 * @resObj: the resulting XPath object or NULL
14276
 * @toBool: 1 if only a boolean result is requested
14277
 *
14278
 * Evaluate the Precompiled XPath expression in the given context.
14279
 * The caller has to free @resObj.
14280
 *
14281
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14282
 *         the caller has to free the object.
14283
 */
14284
static int
14285
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14286
           xmlXPathContextPtr ctxt,
14287
           xmlXPathObjectPtr *resObjPtr,
14288
           int toBool)
14289
5.02M
{
14290
5.02M
    xmlXPathParserContextPtr pctxt;
14291
5.02M
    xmlXPathObjectPtr resObj;
14292
#ifndef LIBXML_THREAD_ENABLED
14293
    static int reentance = 0;
14294
#endif
14295
5.02M
    int res;
14296
14297
5.02M
    CHECK_CTXT_NEG(ctxt)
14298
14299
5.02M
    if (comp == NULL)
14300
5.30k
  return(-1);
14301
5.01M
    xmlInitParser();
14302
14303
#ifndef LIBXML_THREAD_ENABLED
14304
    reentance++;
14305
    if (reentance > 1)
14306
  xmlXPathDisableOptimizer = 1;
14307
#endif
14308
14309
#ifdef DEBUG_EVAL_COUNTS
14310
    comp->nb++;
14311
    if ((comp->string != NULL) && (comp->nb > 100)) {
14312
  fprintf(stderr, "100 x %s\n", comp->string);
14313
  comp->nb = 0;
14314
    }
14315
#endif
14316
5.01M
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14317
5.01M
    if (pctxt == NULL)
14318
44.6k
        return(-1);
14319
4.97M
    res = xmlXPathRunEval(pctxt, toBool);
14320
14321
4.97M
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14322
769k
        resObj = NULL;
14323
4.20M
    } else {
14324
4.20M
        resObj = valuePop(pctxt);
14325
4.20M
        if (resObj == NULL) {
14326
22.1k
            if (!toBool)
14327
942
                xmlGenericError(xmlGenericErrorContext,
14328
942
                    "xmlXPathCompiledEval: No result on the stack.\n");
14329
4.18M
        } else if (pctxt->valueNr > 0) {
14330
0
            xmlGenericError(xmlGenericErrorContext,
14331
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14332
0
                pctxt->valueNr);
14333
0
        }
14334
4.20M
    }
14335
14336
4.97M
    if (resObjPtr)
14337
4.95M
        *resObjPtr = resObj;
14338
21.2k
    else
14339
21.2k
        xmlXPathReleaseObject(ctxt, resObj);
14340
14341
4.97M
    pctxt->comp = NULL;
14342
4.97M
    xmlXPathFreeParserContext(pctxt);
14343
#ifndef LIBXML_THREAD_ENABLED
14344
    reentance--;
14345
#endif
14346
14347
4.97M
    return(res);
14348
5.01M
}
14349
14350
/**
14351
 * xmlXPathCompiledEval:
14352
 * @comp:  the compiled XPath expression
14353
 * @ctx:  the XPath context
14354
 *
14355
 * Evaluate the Precompiled XPath expression in the given context.
14356
 *
14357
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14358
 *         the caller has to free the object.
14359
 */
14360
xmlXPathObjectPtr
14361
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14362
5.00M
{
14363
5.00M
    xmlXPathObjectPtr res = NULL;
14364
14365
5.00M
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14366
5.00M
    return(res);
14367
5.00M
}
14368
14369
/**
14370
 * xmlXPathCompiledEvalToBoolean:
14371
 * @comp:  the compiled XPath expression
14372
 * @ctxt:  the XPath context
14373
 *
14374
 * Applies the XPath boolean() function on the result of the given
14375
 * compiled expression.
14376
 *
14377
 * Returns 1 if the expression evaluated to true, 0 if to false and
14378
 *         -1 in API and internal errors.
14379
 */
14380
int
14381
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14382
            xmlXPathContextPtr ctxt)
14383
21.2k
{
14384
21.2k
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14385
21.2k
}
14386
14387
/**
14388
 * xmlXPathEvalExpr:
14389
 * @ctxt:  the XPath Parser context
14390
 *
14391
 * Parse and evaluate an XPath expression in the given context,
14392
 * then push the result on the context stack
14393
 */
14394
void
14395
38.7k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14396
38.7k
#ifdef XPATH_STREAMING
14397
38.7k
    xmlXPathCompExprPtr comp;
14398
38.7k
#endif
14399
38.7k
    int oldDepth = 0;
14400
14401
38.7k
    if (ctxt == NULL) return;
14402
14403
38.7k
#ifdef XPATH_STREAMING
14404
38.7k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14405
38.7k
    if (comp != NULL) {
14406
3.59k
        if (ctxt->comp != NULL)
14407
3.59k
      xmlXPathFreeCompExpr(ctxt->comp);
14408
3.59k
        ctxt->comp = comp;
14409
3.59k
    } else
14410
35.1k
#endif
14411
35.1k
    {
14412
35.1k
        if (ctxt->context != NULL)
14413
35.1k
            oldDepth = ctxt->context->depth;
14414
35.1k
  xmlXPathCompileExpr(ctxt, 1);
14415
35.1k
        if (ctxt->context != NULL)
14416
35.1k
            ctxt->context->depth = oldDepth;
14417
35.1k
        CHECK_ERROR;
14418
14419
        /* Check for trailing characters. */
14420
23.7k
        if (*ctxt->cur != 0)
14421
17.1k
            XP_ERROR(XPATH_EXPR_ERROR);
14422
14423
17.1k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14424
15.2k
            if (ctxt->context != NULL)
14425
15.2k
                oldDepth = ctxt->context->depth;
14426
15.2k
      xmlXPathOptimizeExpression(ctxt,
14427
15.2k
    &ctxt->comp->steps[ctxt->comp->last]);
14428
15.2k
            if (ctxt->context != NULL)
14429
15.2k
                ctxt->context->depth = oldDepth;
14430
15.2k
        }
14431
17.1k
    }
14432
14433
20.7k
    xmlXPathRunEval(ctxt, 0);
14434
20.7k
}
14435
14436
/**
14437
 * xmlXPathEval:
14438
 * @str:  the XPath expression
14439
 * @ctx:  the XPath context
14440
 *
14441
 * Evaluate the XPath Location Path in the given context.
14442
 *
14443
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14444
 *         the caller has to free the object.
14445
 */
14446
xmlXPathObjectPtr
14447
40.8k
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14448
40.8k
    xmlXPathParserContextPtr ctxt;
14449
40.8k
    xmlXPathObjectPtr res;
14450
14451
40.8k
    CHECK_CTXT(ctx)
14452
14453
40.8k
    xmlInitParser();
14454
14455
40.8k
    ctxt = xmlXPathNewParserContext(str, ctx);
14456
40.8k
    if (ctxt == NULL)
14457
2.21k
        return NULL;
14458
38.6k
    xmlXPathEvalExpr(ctxt);
14459
14460
38.6k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14461
24.4k
  res = NULL;
14462
24.4k
    } else {
14463
14.2k
  res = valuePop(ctxt);
14464
14.2k
        if (res == NULL) {
14465
0
            xmlGenericError(xmlGenericErrorContext,
14466
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14467
14.2k
        } else if (ctxt->valueNr > 0) {
14468
0
            xmlGenericError(xmlGenericErrorContext,
14469
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14470
0
                ctxt->valueNr);
14471
0
        }
14472
14.2k
    }
14473
14474
38.6k
    xmlXPathFreeParserContext(ctxt);
14475
38.6k
    return(res);
14476
40.8k
}
14477
14478
/**
14479
 * xmlXPathSetContextNode:
14480
 * @node: the node to to use as the context node
14481
 * @ctx:  the XPath context
14482
 *
14483
 * Sets 'node' as the context node. The node must be in the same
14484
 * document as that associated with the context.
14485
 *
14486
 * Returns -1 in case of error or 0 if successful
14487
 */
14488
int
14489
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14490
0
    if ((node == NULL) || (ctx == NULL))
14491
0
        return(-1);
14492
14493
0
    if (node->doc == ctx->doc) {
14494
0
        ctx->node = node;
14495
0
  return(0);
14496
0
    }
14497
0
    return(-1);
14498
0
}
14499
14500
/**
14501
 * xmlXPathNodeEval:
14502
 * @node: the node to to use as the context node
14503
 * @str:  the XPath expression
14504
 * @ctx:  the XPath context
14505
 *
14506
 * Evaluate the XPath Location Path in the given context. The node 'node'
14507
 * is set as the context node. The context node is not restored.
14508
 *
14509
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14510
 *         the caller has to free the object.
14511
 */
14512
xmlXPathObjectPtr
14513
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14514
0
    if (str == NULL)
14515
0
        return(NULL);
14516
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14517
0
        return(NULL);
14518
0
    return(xmlXPathEval(str, ctx));
14519
0
}
14520
14521
/**
14522
 * xmlXPathEvalExpression:
14523
 * @str:  the XPath expression
14524
 * @ctxt:  the XPath context
14525
 *
14526
 * Alias for xmlXPathEval().
14527
 *
14528
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14529
 *         the caller has to free the object.
14530
 */
14531
xmlXPathObjectPtr
14532
4.27k
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14533
4.27k
    return(xmlXPathEval(str, ctxt));
14534
4.27k
}
14535
14536
/************************************************************************
14537
 *                  *
14538
 *  Extra functions not pertaining to the XPath spec    *
14539
 *                  *
14540
 ************************************************************************/
14541
/**
14542
 * xmlXPathEscapeUriFunction:
14543
 * @ctxt:  the XPath Parser context
14544
 * @nargs:  the number of arguments
14545
 *
14546
 * Implement the escape-uri() XPath function
14547
 *    string escape-uri(string $str, bool $escape-reserved)
14548
 *
14549
 * This function applies the URI escaping rules defined in section 2 of [RFC
14550
 * 2396] to the string supplied as $uri-part, which typically represents all
14551
 * or part of a URI. The effect of the function is to replace any special
14552
 * character in the string by an escape sequence of the form %xx%yy...,
14553
 * where xxyy... is the hexadecimal representation of the octets used to
14554
 * represent the character in UTF-8.
14555
 *
14556
 * The set of characters that are escaped depends on the setting of the
14557
 * boolean argument $escape-reserved.
14558
 *
14559
 * If $escape-reserved is true, all characters are escaped other than lower
14560
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14561
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14562
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14563
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14564
 * A-F).
14565
 *
14566
 * If $escape-reserved is false, the behavior differs in that characters
14567
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14568
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14569
 *
14570
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14571
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14572
 * compared using string comparison functions, this function must always use
14573
 * the upper-case letters A-F.
14574
 *
14575
 * Generally, $escape-reserved should be set to true when escaping a string
14576
 * that is to form a single part of a URI, and to false when escaping an
14577
 * entire URI or URI reference.
14578
 *
14579
 * In the case of non-ascii characters, the string is encoded according to
14580
 * utf-8 and then converted according to RFC 2396.
14581
 *
14582
 * Examples
14583
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14584
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14585
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14586
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14587
 *
14588
 */
14589
static void
14590
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14591
0
    xmlXPathObjectPtr str;
14592
0
    int escape_reserved;
14593
0
    xmlBufPtr target;
14594
0
    xmlChar *cptr;
14595
0
    xmlChar escape[4];
14596
14597
0
    CHECK_ARITY(2);
14598
14599
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14600
14601
0
    CAST_TO_STRING;
14602
0
    str = valuePop(ctxt);
14603
14604
0
    target = xmlBufCreate();
14605
14606
0
    escape[0] = '%';
14607
0
    escape[3] = 0;
14608
14609
0
    if (target) {
14610
0
  for (cptr = str->stringval; *cptr; cptr++) {
14611
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14612
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14613
0
    (*cptr >= '0' && *cptr <= '9') ||
14614
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14615
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14616
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14617
0
    (*cptr == '%' &&
14618
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14619
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14620
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14621
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14622
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14623
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14624
0
    (!escape_reserved &&
14625
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14626
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14627
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14628
0
      *cptr == ','))) {
14629
0
    xmlBufAdd(target, cptr, 1);
14630
0
      } else {
14631
0
    if ((*cptr >> 4) < 10)
14632
0
        escape[1] = '0' + (*cptr >> 4);
14633
0
    else
14634
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14635
0
    if ((*cptr & 0xF) < 10)
14636
0
        escape[2] = '0' + (*cptr & 0xF);
14637
0
    else
14638
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14639
14640
0
    xmlBufAdd(target, &escape[0], 3);
14641
0
      }
14642
0
  }
14643
0
    }
14644
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14645
0
  xmlBufContent(target)));
14646
0
    xmlBufFree(target);
14647
0
    xmlXPathReleaseObject(ctxt->context, str);
14648
0
}
14649
14650
/**
14651
 * xmlXPathRegisterAllFunctions:
14652
 * @ctxt:  the XPath context
14653
 *
14654
 * Registers all default XPath functions in this context
14655
 */
14656
void
14657
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14658
60.0k
{
14659
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14660
60.0k
                         xmlXPathBooleanFunction);
14661
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14662
60.0k
                         xmlXPathCeilingFunction);
14663
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14664
60.0k
                         xmlXPathCountFunction);
14665
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14666
60.0k
                         xmlXPathConcatFunction);
14667
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14668
60.0k
                         xmlXPathContainsFunction);
14669
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14670
60.0k
                         xmlXPathIdFunction);
14671
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14672
60.0k
                         xmlXPathFalseFunction);
14673
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14674
60.0k
                         xmlXPathFloorFunction);
14675
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14676
60.0k
                         xmlXPathLastFunction);
14677
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14678
60.0k
                         xmlXPathLangFunction);
14679
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14680
60.0k
                         xmlXPathLocalNameFunction);
14681
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14682
60.0k
                         xmlXPathNotFunction);
14683
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14684
60.0k
                         xmlXPathNameFunction);
14685
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14686
60.0k
                         xmlXPathNamespaceURIFunction);
14687
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14688
60.0k
                         xmlXPathNormalizeFunction);
14689
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14690
60.0k
                         xmlXPathNumberFunction);
14691
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14692
60.0k
                         xmlXPathPositionFunction);
14693
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14694
60.0k
                         xmlXPathRoundFunction);
14695
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14696
60.0k
                         xmlXPathStringFunction);
14697
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14698
60.0k
                         xmlXPathStringLengthFunction);
14699
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14700
60.0k
                         xmlXPathStartsWithFunction);
14701
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14702
60.0k
                         xmlXPathSubstringFunction);
14703
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14704
60.0k
                         xmlXPathSubstringBeforeFunction);
14705
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14706
60.0k
                         xmlXPathSubstringAfterFunction);
14707
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14708
60.0k
                         xmlXPathSumFunction);
14709
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14710
60.0k
                         xmlXPathTrueFunction);
14711
60.0k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14712
60.0k
                         xmlXPathTranslateFunction);
14713
14714
60.0k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14715
60.0k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14716
60.0k
                         xmlXPathEscapeUriFunction);
14717
60.0k
}
14718
14719
#endif /* LIBXML_XPATH_ENABLED */