Coverage Report

Created: 2023-06-24 16:08

/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
28.8k
    xmlGenericError(xmlGenericErrorContext,       \
62
28.8k
      "Unimplemented block at %s:%d\n",       \
63
28.8k
            __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
3.68M
#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
10.9k
#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
8.66M
#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
563M
#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
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
149
/**
150
 * xmlXPathCmpNodesExt:
151
 * @node1:  the first node
152
 * @node2:  the second node
153
 *
154
 * Compare two nodes w.r.t document order.
155
 * This one is optimized for handling of non-element nodes.
156
 *
157
 * Returns -2 in case of error 1 if first point < second point, 0 if
158
 *         it's the same node, -1 otherwise
159
 */
160
static int
161
91.3M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
162
91.3M
    int depth1, depth2;
163
91.3M
    int misc = 0, precedence1 = 0, precedence2 = 0;
164
91.3M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
165
91.3M
    xmlNodePtr cur, root;
166
91.3M
    ptrdiff_t l1, l2;
167
168
91.3M
    if ((node1 == NULL) || (node2 == NULL))
169
0
  return(-2);
170
171
91.3M
    if (node1 == node2)
172
0
  return(0);
173
174
    /*
175
     * a couple of optimizations which will avoid computations in most cases
176
     */
177
91.3M
    switch (node1->type) {
178
47.9M
  case XML_ELEMENT_NODE:
179
47.9M
      if (node2->type == XML_ELEMENT_NODE) {
180
29.6M
    if ((0 > (ptrdiff_t) node1->content) &&
181
29.6M
        (0 > (ptrdiff_t) node2->content) &&
182
29.6M
        (node1->doc == node2->doc))
183
10.2M
    {
184
10.2M
        l1 = -((ptrdiff_t) node1->content);
185
10.2M
        l2 = -((ptrdiff_t) node2->content);
186
10.2M
        if (l1 < l2)
187
8.94M
      return(1);
188
1.31M
        if (l1 > l2)
189
1.31M
      return(-1);
190
1.31M
    } else
191
19.3M
        goto turtle_comparison;
192
29.6M
      }
193
18.3M
      break;
194
18.3M
  case XML_ATTRIBUTE_NODE:
195
1.07M
      precedence1 = 1; /* element is owner */
196
1.07M
      miscNode1 = node1;
197
1.07M
      node1 = node1->parent;
198
1.07M
      misc = 1;
199
1.07M
      break;
200
34.0M
  case XML_TEXT_NODE:
201
35.0M
  case XML_CDATA_SECTION_NODE:
202
36.3M
  case XML_COMMENT_NODE:
203
37.6M
  case XML_PI_NODE: {
204
37.6M
      miscNode1 = node1;
205
      /*
206
      * Find nearest element node.
207
      */
208
37.6M
      if (node1->prev != NULL) {
209
22.9M
    do {
210
22.9M
        node1 = node1->prev;
211
22.9M
        if (node1->type == XML_ELEMENT_NODE) {
212
14.7M
      precedence1 = 3; /* element in prev-sibl axis */
213
14.7M
      break;
214
14.7M
        }
215
8.17M
        if (node1->prev == NULL) {
216
0
      precedence1 = 2; /* element is parent */
217
      /*
218
      * URGENT TODO: Are there any cases, where the
219
      * parent of such a node is not an element node?
220
      */
221
0
      node1 = node1->parent;
222
0
      break;
223
0
        }
224
8.17M
    } while (1);
225
22.9M
      } else {
226
22.9M
    precedence1 = 2; /* element is parent */
227
22.9M
    node1 = node1->parent;
228
22.9M
      }
229
37.6M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
230
37.6M
    (0 <= (ptrdiff_t) node1->content)) {
231
    /*
232
    * Fallback for whatever case.
233
    */
234
14.1M
    node1 = miscNode1;
235
14.1M
    precedence1 = 0;
236
14.1M
      } else
237
23.5M
    misc = 1;
238
37.6M
  }
239
0
      break;
240
2.91M
  case XML_NAMESPACE_DECL:
241
      /*
242
      * TODO: why do we return 1 for namespace nodes?
243
      */
244
2.91M
      return(1);
245
1.74M
  default:
246
1.74M
      break;
247
91.3M
    }
248
58.8M
    switch (node2->type) {
249
16.8M
  case XML_ELEMENT_NODE:
250
16.8M
      break;
251
725k
  case XML_ATTRIBUTE_NODE:
252
725k
      precedence2 = 1; /* element is owner */
253
725k
      miscNode2 = node2;
254
725k
      node2 = node2->parent;
255
725k
      misc = 1;
256
725k
      break;
257
33.7M
  case XML_TEXT_NODE:
258
34.5M
  case XML_CDATA_SECTION_NODE:
259
35.8M
  case XML_COMMENT_NODE:
260
38.1M
  case XML_PI_NODE: {
261
38.1M
      miscNode2 = node2;
262
38.1M
      if (node2->prev != NULL) {
263
25.2M
    do {
264
25.2M
        node2 = node2->prev;
265
25.2M
        if (node2->type == XML_ELEMENT_NODE) {
266
15.8M
      precedence2 = 3; /* element in prev-sibl axis */
267
15.8M
      break;
268
15.8M
        }
269
9.48M
        if (node2->prev == NULL) {
270
0
      precedence2 = 2; /* element is parent */
271
0
      node2 = node2->parent;
272
0
      break;
273
0
        }
274
9.48M
    } while (1);
275
22.3M
      } else {
276
22.3M
    precedence2 = 2; /* element is parent */
277
22.3M
    node2 = node2->parent;
278
22.3M
      }
279
38.1M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
280
38.1M
    (0 <= (ptrdiff_t) node2->content))
281
15.2M
      {
282
15.2M
    node2 = miscNode2;
283
15.2M
    precedence2 = 0;
284
15.2M
      } else
285
22.9M
    misc = 1;
286
38.1M
  }
287
0
      break;
288
249k
  case XML_NAMESPACE_DECL:
289
249k
      return(1);
290
2.73M
  default:
291
2.73M
      break;
292
58.8M
    }
293
58.5M
    if (misc) {
294
32.3M
  if (node1 == node2) {
295
12.9M
      if (precedence1 == precedence2) {
296
    /*
297
    * The ugly case; but normally there aren't many
298
    * adjacent non-element nodes around.
299
    */
300
3.33M
    cur = miscNode2->prev;
301
3.67M
    while (cur != NULL) {
302
3.66M
        if (cur == miscNode1)
303
3.06M
      return(1);
304
592k
        if (cur->type == XML_ELEMENT_NODE)
305
244k
      return(-1);
306
347k
        cur = cur->prev;
307
347k
    }
308
16.7k
    return (-1);
309
9.62M
      } else {
310
    /*
311
    * Evaluate based on higher precedence wrt to the element.
312
    * TODO: This assumes attributes are sorted before content.
313
    *   Is this 100% correct?
314
    */
315
9.62M
    if (precedence1 < precedence2)
316
8.70M
        return(1);
317
915k
    else
318
915k
        return(-1);
319
9.62M
      }
320
12.9M
  }
321
  /*
322
  * Special case: One of the helper-elements is contained by the other.
323
  * <foo>
324
  *   <node2>
325
  *     <node1>Text-1(precedence1 == 2)</node1>
326
  *   </node2>
327
  *   Text-6(precedence2 == 3)
328
  * </foo>
329
  */
330
19.4M
  if ((precedence2 == 3) && (precedence1 > 1)) {
331
5.90M
      cur = node1->parent;
332
17.5M
      while (cur) {
333
13.1M
    if (cur == node2)
334
1.53M
        return(1);
335
11.6M
    cur = cur->parent;
336
11.6M
      }
337
5.90M
  }
338
17.9M
  if ((precedence1 == 3) && (precedence2 > 1)) {
339
4.06M
      cur = node2->parent;
340
13.9M
      while (cur) {
341
10.0M
    if (cur == node1)
342
178k
        return(-1);
343
9.91M
    cur = cur->parent;
344
9.91M
      }
345
4.06M
  }
346
17.9M
    }
347
348
    /*
349
     * Speedup using document order if available.
350
     */
351
43.8M
    if ((node1->type == XML_ELEMENT_NODE) &&
352
43.8M
  (node2->type == XML_ELEMENT_NODE) &&
353
43.8M
  (0 > (ptrdiff_t) node1->content) &&
354
43.8M
  (0 > (ptrdiff_t) node2->content) &&
355
43.8M
  (node1->doc == node2->doc)) {
356
357
16.1M
  l1 = -((ptrdiff_t) node1->content);
358
16.1M
  l2 = -((ptrdiff_t) node2->content);
359
16.1M
  if (l1 < l2)
360
9.83M
      return(1);
361
6.26M
  if (l1 > l2)
362
6.26M
      return(-1);
363
6.26M
    }
364
365
47.1M
turtle_comparison:
366
367
47.1M
    if (node1 == node2->prev)
368
14.0M
  return(1);
369
33.0M
    if (node1 == node2->next)
370
2.02M
  return(-1);
371
    /*
372
     * compute depth to root
373
     */
374
59.8M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
375
36.6M
  if (cur->parent == node1)
376
7.80M
      return(1);
377
28.8M
  depth2++;
378
28.8M
    }
379
23.2M
    root = cur;
380
59.1M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
381
38.9M
  if (cur->parent == node2)
382
3.03M
      return(-1);
383
35.9M
  depth1++;
384
35.9M
    }
385
    /*
386
     * Distinct document (or distinct entities :-( ) case.
387
     */
388
20.1M
    if (root != cur) {
389
1.37M
  return(-2);
390
1.37M
    }
391
    /*
392
     * get the nearest common ancestor.
393
     */
394
27.9M
    while (depth1 > depth2) {
395
9.14M
  depth1--;
396
9.14M
  node1 = node1->parent;
397
9.14M
    }
398
21.4M
    while (depth2 > depth1) {
399
2.61M
  depth2--;
400
2.61M
  node2 = node2->parent;
401
2.61M
    }
402
23.2M
    while (node1->parent != node2->parent) {
403
4.48M
  node1 = node1->parent;
404
4.48M
  node2 = node2->parent;
405
  /* should not happen but just in case ... */
406
4.48M
  if ((node1 == NULL) || (node2 == NULL))
407
0
      return(-2);
408
4.48M
    }
409
    /*
410
     * Find who's first.
411
     */
412
18.8M
    if (node1 == node2->prev)
413
8.05M
  return(1);
414
10.7M
    if (node1 == node2->next)
415
2.92M
  return(-1);
416
    /*
417
     * Speedup using document order if available.
418
     */
419
7.82M
    if ((node1->type == XML_ELEMENT_NODE) &&
420
7.82M
  (node2->type == XML_ELEMENT_NODE) &&
421
7.82M
  (0 > (ptrdiff_t) node1->content) &&
422
7.82M
  (0 > (ptrdiff_t) node2->content) &&
423
7.82M
  (node1->doc == node2->doc)) {
424
425
0
  l1 = -((ptrdiff_t) node1->content);
426
0
  l2 = -((ptrdiff_t) node2->content);
427
0
  if (l1 < l2)
428
0
      return(1);
429
0
  if (l1 > l2)
430
0
      return(-1);
431
0
    }
432
433
481M
    for (cur = node1->next;cur != NULL;cur = cur->next)
434
475M
  if (cur == node2)
435
1.68M
      return(1);
436
6.14M
    return(-1); /* assume there is no sibling list corruption */
437
7.82M
}
438
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
439
440
/*
441
 * Wrapper for the Timsort algorithm from timsort.h
442
 */
443
#ifdef WITH_TIM_SORT
444
#define SORT_NAME libxml_domnode
445
43.2M
#define SORT_TYPE xmlNodePtr
446
/**
447
 * wrap_cmp:
448
 * @x: a node
449
 * @y: another node
450
 *
451
 * Comparison function for the Timsort implementation
452
 *
453
 * Returns -2 in case of error -1 if first point < second point, 0 if
454
 *         it's the same node, +1 otherwise
455
 */
456
static
457
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
458
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
459
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
460
91.0M
    {
461
91.0M
        int res = xmlXPathCmpNodesExt(x, y);
462
91.0M
        return res == -2 ? res : -res;
463
91.0M
    }
464
#else
465
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
466
    {
467
        int res = xmlXPathCmpNodes(x, y);
468
        return res == -2 ? res : -res;
469
    }
470
#endif
471
91.0M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
472
#include "timsort.h"
473
#endif /* WITH_TIM_SORT */
474
475
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
476
477
/************************************************************************
478
 *                  *
479
 *      Floating point stuff        *
480
 *                  *
481
 ************************************************************************/
482
483
double xmlXPathNAN = 0.0;
484
double xmlXPathPINF = 0.0;
485
double xmlXPathNINF = 0.0;
486
487
/**
488
 * xmlXPathInit:
489
 *
490
 * DEPRECATED: Alias for xmlInitParser.
491
 */
492
void
493
0
xmlXPathInit(void) {
494
0
    xmlInitParser();
495
0
}
496
497
/**
498
 * xmlInitXPathInternal:
499
 *
500
 * Initialize the XPath environment
501
 */
502
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
503
void
504
3.69k
xmlInitXPathInternal(void) {
505
3.69k
#if defined(NAN) && defined(INFINITY)
506
3.69k
    xmlXPathNAN = NAN;
507
3.69k
    xmlXPathPINF = INFINITY;
508
3.69k
    xmlXPathNINF = -INFINITY;
509
#else
510
    /* MSVC doesn't allow division by zero in constant expressions. */
511
    double zero = 0.0;
512
    xmlXPathNAN = 0.0 / zero;
513
    xmlXPathPINF = 1.0 / zero;
514
    xmlXPathNINF = -xmlXPathPINF;
515
#endif
516
3.69k
}
517
518
/**
519
 * xmlXPathIsNaN:
520
 * @val:  a double value
521
 *
522
 * Returns 1 if the value is a NaN, 0 otherwise
523
 */
524
int
525
39.6M
xmlXPathIsNaN(double val) {
526
39.6M
#ifdef isnan
527
39.6M
    return isnan(val);
528
#else
529
    return !(val == val);
530
#endif
531
39.6M
}
532
533
/**
534
 * xmlXPathIsInf:
535
 * @val:  a double value
536
 *
537
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
538
 */
539
int
540
15.0M
xmlXPathIsInf(double val) {
541
15.0M
#ifdef isinf
542
15.0M
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
543
#else
544
    if (val >= xmlXPathPINF)
545
        return 1;
546
    if (val <= -xmlXPathPINF)
547
        return -1;
548
    return 0;
549
#endif
550
15.0M
}
551
552
#endif /* SCHEMAS or XPATH */
553
554
#ifdef LIBXML_XPATH_ENABLED
555
556
/*
557
 * TODO: when compatibility allows remove all "fake node libxslt" strings
558
 *       the test should just be name[0] = ' '
559
 */
560
#ifdef DEBUG_XPATH_EXPRESSION
561
#define DEBUG_STEP
562
#define DEBUG_EXPR
563
#define DEBUG_EVAL_COUNTS
564
#endif
565
566
static xmlNs xmlXPathXMLNamespaceStruct = {
567
    NULL,
568
    XML_NAMESPACE_DECL,
569
    XML_XML_NAMESPACE,
570
    BAD_CAST "xml",
571
    NULL,
572
    NULL
573
};
574
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
575
#ifndef LIBXML_THREAD_ENABLED
576
/*
577
 * Optimizer is disabled only when threaded apps are detected while
578
 * the library ain't compiled for thread safety.
579
 */
580
static int xmlXPathDisableOptimizer = 0;
581
#endif
582
583
/************************************************************************
584
 *                  *
585
 *      Error handling routines       *
586
 *                  *
587
 ************************************************************************/
588
589
/**
590
 * XP_ERRORNULL:
591
 * @X:  the error code
592
 *
593
 * Macro to raise an XPath error and return NULL.
594
 */
595
#define XP_ERRORNULL(X)             \
596
737k
    { xmlXPathErr(ctxt, X); return(NULL); }
597
598
/*
599
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
600
 */
601
static const char* const xmlXPathErrorMessages[] = {
602
    "Ok\n",
603
    "Number encoding\n",
604
    "Unfinished literal\n",
605
    "Start of literal\n",
606
    "Expected $ for variable reference\n",
607
    "Undefined variable\n",
608
    "Invalid predicate\n",
609
    "Invalid expression\n",
610
    "Missing closing curly brace\n",
611
    "Unregistered function\n",
612
    "Invalid operand\n",
613
    "Invalid type\n",
614
    "Invalid number of arguments\n",
615
    "Invalid context size\n",
616
    "Invalid context position\n",
617
    "Memory allocation error\n",
618
    "Syntax error\n",
619
    "Resource error\n",
620
    "Sub resource error\n",
621
    "Undefined namespace prefix\n",
622
    "Encoding error\n",
623
    "Char out of XML range\n",
624
    "Invalid or incomplete context\n",
625
    "Stack usage error\n",
626
    "Forbidden variable\n",
627
    "Operation limit exceeded\n",
628
    "Recursion limit exceeded\n",
629
    "?? Unknown error ??\n" /* Must be last in the list! */
630
};
631
7.74M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
632
7.74M
       sizeof(xmlXPathErrorMessages[0])) - 1)
633
/**
634
 * xmlXPathErrMemory:
635
 * @ctxt:  an XPath context
636
 * @extra:  extra information
637
 *
638
 * Handle a redefinition of attribute error
639
 */
640
static void
641
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
642
0
{
643
0
    if (ctxt != NULL) {
644
0
        xmlResetError(&ctxt->lastError);
645
0
        if (extra) {
646
0
            xmlChar buf[200];
647
648
0
            xmlStrPrintf(buf, 200,
649
0
                         "Memory allocation failed : %s\n",
650
0
                         extra);
651
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
652
0
        } else {
653
0
            ctxt->lastError.message = (char *)
654
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
655
0
        }
656
0
        ctxt->lastError.domain = XML_FROM_XPATH;
657
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
658
0
  if (ctxt->error != NULL)
659
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
660
0
    } else {
661
0
        if (extra)
662
0
            __xmlRaiseError(NULL, NULL, NULL,
663
0
                            NULL, NULL, XML_FROM_XPATH,
664
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665
0
                            extra, NULL, NULL, 0, 0,
666
0
                            "Memory allocation failed : %s\n", extra);
667
0
        else
668
0
            __xmlRaiseError(NULL, NULL, NULL,
669
0
                            NULL, NULL, XML_FROM_XPATH,
670
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671
0
                            NULL, NULL, NULL, 0, 0,
672
0
                            "Memory allocation failed\n");
673
0
    }
674
0
}
675
676
/**
677
 * xmlXPathPErrMemory:
678
 * @ctxt:  an XPath parser context
679
 * @extra:  extra information
680
 *
681
 * Handle a redefinition of attribute error
682
 */
683
static void
684
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685
0
{
686
0
    if (ctxt == NULL)
687
0
  xmlXPathErrMemory(NULL, extra);
688
0
    else {
689
0
  ctxt->error = XPATH_MEMORY_ERROR;
690
0
  xmlXPathErrMemory(ctxt->context, extra);
691
0
    }
692
0
}
693
694
/**
695
 * xmlXPathErr:
696
 * @ctxt:  a XPath parser context
697
 * @error:  the error code
698
 *
699
 * Handle an XPath error
700
 */
701
void
702
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703
7.74M
{
704
7.74M
    if ((error < 0) || (error > MAXERRNO))
705
0
  error = MAXERRNO;
706
7.74M
    if (ctxt == NULL) {
707
0
  __xmlRaiseError(NULL, NULL, NULL,
708
0
      NULL, NULL, XML_FROM_XPATH,
709
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710
0
      XML_ERR_ERROR, NULL, 0,
711
0
      NULL, NULL, NULL, 0, 0,
712
0
      "%s", xmlXPathErrorMessages[error]);
713
0
  return;
714
0
    }
715
7.74M
    ctxt->error = error;
716
7.74M
    if (ctxt->context == NULL) {
717
0
  __xmlRaiseError(NULL, NULL, NULL,
718
0
      NULL, NULL, XML_FROM_XPATH,
719
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720
0
      XML_ERR_ERROR, NULL, 0,
721
0
      (const char *) ctxt->base, NULL, NULL,
722
0
      ctxt->cur - ctxt->base, 0,
723
0
      "%s", xmlXPathErrorMessages[error]);
724
0
  return;
725
0
    }
726
727
    /* cleanup current last error */
728
7.74M
    xmlResetError(&ctxt->context->lastError);
729
730
7.74M
    ctxt->context->lastError.domain = XML_FROM_XPATH;
731
7.74M
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732
7.74M
                           XPATH_EXPRESSION_OK;
733
7.74M
    ctxt->context->lastError.level = XML_ERR_ERROR;
734
7.74M
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735
7.74M
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736
7.74M
    ctxt->context->lastError.node = ctxt->context->debugNode;
737
7.74M
    if (ctxt->context->error != NULL) {
738
0
  ctxt->context->error(ctxt->context->userData,
739
0
                       &ctxt->context->lastError);
740
7.74M
    } else {
741
7.74M
  __xmlRaiseError(NULL, NULL, NULL,
742
7.74M
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743
7.74M
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744
7.74M
      XML_ERR_ERROR, NULL, 0,
745
7.74M
      (const char *) ctxt->base, NULL, NULL,
746
7.74M
      ctxt->cur - ctxt->base, 0,
747
7.74M
      "%s", xmlXPathErrorMessages[error]);
748
7.74M
    }
749
750
7.74M
}
751
752
/**
753
 * xmlXPatherror:
754
 * @ctxt:  the XPath Parser context
755
 * @file:  the file name
756
 * @line:  the line number
757
 * @no:  the error number
758
 *
759
 * Formats an error message.
760
 */
761
void
762
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763
1.57M
              int line ATTRIBUTE_UNUSED, int no) {
764
1.57M
    xmlXPathErr(ctxt, no);
765
1.57M
}
766
767
/**
768
 * xmlXPathCheckOpLimit:
769
 * @ctxt:  the XPath Parser context
770
 * @opCount:  the number of operations to be added
771
 *
772
 * Adds opCount to the running total of operations and returns -1 if the
773
 * operation limit is exceeded. Returns 0 otherwise.
774
 */
775
static int
776
1.06G
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
777
1.06G
    xmlXPathContextPtr xpctxt = ctxt->context;
778
779
1.06G
    if ((opCount > xpctxt->opLimit) ||
780
1.06G
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
781
8.53k
        xpctxt->opCount = xpctxt->opLimit;
782
8.53k
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
783
8.53k
        return(-1);
784
8.53k
    }
785
786
1.06G
    xpctxt->opCount += opCount;
787
1.06G
    return(0);
788
1.06G
}
789
790
#define OP_LIMIT_EXCEEDED(ctxt, n) \
791
1.03G
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
792
793
/************************************************************************
794
 *                  *
795
 *      Utilities         *
796
 *                  *
797
 ************************************************************************/
798
799
/**
800
 * xsltPointerList:
801
 *
802
 * Pointer-list for various purposes.
803
 */
804
typedef struct _xmlPointerList xmlPointerList;
805
typedef xmlPointerList *xmlPointerListPtr;
806
struct _xmlPointerList {
807
    void **items;
808
    int number;
809
    int size;
810
};
811
/*
812
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
813
* and here, we should make the functions public.
814
*/
815
static int
816
xmlPointerListAddSize(xmlPointerListPtr list,
817
           void *item,
818
           int initialSize)
819
341M
{
820
341M
    if (list->items == NULL) {
821
498k
  if (initialSize <= 0)
822
0
      initialSize = 1;
823
498k
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
824
498k
  if (list->items == NULL) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListCreate: allocating item\n");
827
0
      return(-1);
828
0
  }
829
498k
  list->number = 0;
830
498k
  list->size = initialSize;
831
340M
    } else if (list->size <= list->number) {
832
368k
        if (list->size > 50000000) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
            return(-1);
836
0
        }
837
368k
  list->size *= 2;
838
368k
  list->items = (void **) xmlRealloc(list->items,
839
368k
      list->size * sizeof(void *));
840
368k
  if (list->items == NULL) {
841
0
      xmlXPathErrMemory(NULL,
842
0
    "xmlPointerListAddSize: re-allocating item\n");
843
0
      list->size = 0;
844
0
      return(-1);
845
0
  }
846
368k
    }
847
341M
    list->items[list->number++] = item;
848
341M
    return(0);
849
341M
}
850
851
/**
852
 * xsltPointerListCreate:
853
 *
854
 * Creates an xsltPointerList structure.
855
 *
856
 * Returns a xsltPointerList structure or NULL in case of an error.
857
 */
858
static xmlPointerListPtr
859
xmlPointerListCreate(int initialSize)
860
498k
{
861
498k
    xmlPointerListPtr ret;
862
863
498k
    ret = xmlMalloc(sizeof(xmlPointerList));
864
498k
    if (ret == NULL) {
865
0
  xmlXPathErrMemory(NULL,
866
0
      "xmlPointerListCreate: allocating item\n");
867
0
  return (NULL);
868
0
    }
869
498k
    memset(ret, 0, sizeof(xmlPointerList));
870
498k
    if (initialSize > 0) {
871
498k
  xmlPointerListAddSize(ret, NULL, initialSize);
872
498k
  ret->number = 0;
873
498k
    }
874
498k
    return (ret);
875
498k
}
876
877
/**
878
 * xsltPointerListFree:
879
 *
880
 * Frees the xsltPointerList structure. This does not free
881
 * the content of the list.
882
 */
883
static void
884
xmlPointerListFree(xmlPointerListPtr list)
885
496k
{
886
496k
    if (list == NULL)
887
0
  return;
888
496k
    if (list->items != NULL)
889
496k
  xmlFree(list->items);
890
496k
    xmlFree(list);
891
496k
}
892
893
/************************************************************************
894
 *                  *
895
 *      Parser Types          *
896
 *                  *
897
 ************************************************************************/
898
899
/*
900
 * Types are private:
901
 */
902
903
typedef enum {
904
    XPATH_OP_END=0,
905
    XPATH_OP_AND,
906
    XPATH_OP_OR,
907
    XPATH_OP_EQUAL,
908
    XPATH_OP_CMP,
909
    XPATH_OP_PLUS,
910
    XPATH_OP_MULT,
911
    XPATH_OP_UNION,
912
    XPATH_OP_ROOT,
913
    XPATH_OP_NODE,
914
    XPATH_OP_COLLECT,
915
    XPATH_OP_VALUE, /* 11 */
916
    XPATH_OP_VARIABLE,
917
    XPATH_OP_FUNCTION,
918
    XPATH_OP_ARG,
919
    XPATH_OP_PREDICATE,
920
    XPATH_OP_FILTER, /* 16 */
921
    XPATH_OP_SORT /* 17 */
922
#ifdef LIBXML_XPTR_LOCS_ENABLED
923
    ,XPATH_OP_RANGETO
924
#endif
925
} xmlXPathOp;
926
927
typedef enum {
928
    AXIS_ANCESTOR = 1,
929
    AXIS_ANCESTOR_OR_SELF,
930
    AXIS_ATTRIBUTE,
931
    AXIS_CHILD,
932
    AXIS_DESCENDANT,
933
    AXIS_DESCENDANT_OR_SELF,
934
    AXIS_FOLLOWING,
935
    AXIS_FOLLOWING_SIBLING,
936
    AXIS_NAMESPACE,
937
    AXIS_PARENT,
938
    AXIS_PRECEDING,
939
    AXIS_PRECEDING_SIBLING,
940
    AXIS_SELF
941
} xmlXPathAxisVal;
942
943
typedef enum {
944
    NODE_TEST_NONE = 0,
945
    NODE_TEST_TYPE = 1,
946
    NODE_TEST_PI = 2,
947
    NODE_TEST_ALL = 3,
948
    NODE_TEST_NS = 4,
949
    NODE_TEST_NAME = 5
950
} xmlXPathTestVal;
951
952
typedef enum {
953
    NODE_TYPE_NODE = 0,
954
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
955
    NODE_TYPE_TEXT = XML_TEXT_NODE,
956
    NODE_TYPE_PI = XML_PI_NODE
957
} xmlXPathTypeVal;
958
959
typedef struct _xmlXPathStepOp xmlXPathStepOp;
960
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
961
struct _xmlXPathStepOp {
962
    xmlXPathOp op;    /* The identifier of the operation */
963
    int ch1;      /* First child */
964
    int ch2;      /* Second child */
965
    int value;
966
    int value2;
967
    int value3;
968
    void *value4;
969
    void *value5;
970
    xmlXPathFunction cache;
971
    void *cacheURI;
972
};
973
974
struct _xmlXPathCompExpr {
975
    int nbStep;     /* Number of steps in this expression */
976
    int maxStep;    /* Maximum number of steps allocated */
977
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
978
    int last;     /* index of last step in expression */
979
    xmlChar *expr;    /* the expression being computed */
980
    xmlDictPtr dict;    /* the dictionary to use if any */
981
#ifdef DEBUG_EVAL_COUNTS
982
    int nb;
983
    xmlChar *string;
984
#endif
985
#ifdef XPATH_STREAMING
986
    xmlPatternPtr stream;
987
#endif
988
};
989
990
/************************************************************************
991
 *                  *
992
 *      Forward declarations        *
993
 *                  *
994
 ************************************************************************/
995
static void
996
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
997
static void
998
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
999
static int
1000
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1001
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1002
static int
1003
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1004
          xmlXPathStepOpPtr op,
1005
          int isPredicate);
1006
static void
1007
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1008
1009
/************************************************************************
1010
 *                  *
1011
 *      Parser Type functions       *
1012
 *                  *
1013
 ************************************************************************/
1014
1015
/**
1016
 * xmlXPathNewCompExpr:
1017
 *
1018
 * Create a new Xpath component
1019
 *
1020
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1021
 */
1022
static xmlXPathCompExprPtr
1023
10.4M
xmlXPathNewCompExpr(void) {
1024
10.4M
    xmlXPathCompExprPtr cur;
1025
1026
10.4M
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1027
10.4M
    if (cur == NULL) {
1028
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1029
0
  return(NULL);
1030
0
    }
1031
10.4M
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1032
10.4M
    cur->maxStep = 10;
1033
10.4M
    cur->nbStep = 0;
1034
10.4M
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1035
10.4M
                                     sizeof(xmlXPathStepOp));
1036
10.4M
    if (cur->steps == NULL) {
1037
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1038
0
  xmlFree(cur);
1039
0
  return(NULL);
1040
0
    }
1041
10.4M
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1042
10.4M
    cur->last = -1;
1043
#ifdef DEBUG_EVAL_COUNTS
1044
    cur->nb = 0;
1045
#endif
1046
10.4M
    return(cur);
1047
10.4M
}
1048
1049
/**
1050
 * xmlXPathFreeCompExpr:
1051
 * @comp:  an XPATH comp
1052
 *
1053
 * Free up the memory allocated by @comp
1054
 */
1055
void
1056
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1057
10.4M
{
1058
10.4M
    xmlXPathStepOpPtr op;
1059
10.4M
    int i;
1060
1061
10.4M
    if (comp == NULL)
1062
0
        return;
1063
10.4M
    if (comp->dict == NULL) {
1064
93.0M
  for (i = 0; i < comp->nbStep; i++) {
1065
82.6M
      op = &comp->steps[i];
1066
82.6M
      if (op->value4 != NULL) {
1067
12.3M
    if (op->op == XPATH_OP_VALUE)
1068
5.68M
        xmlXPathFreeObject(op->value4);
1069
6.64M
    else
1070
6.64M
        xmlFree(op->value4);
1071
12.3M
      }
1072
82.6M
      if (op->value5 != NULL)
1073
12.9M
    xmlFree(op->value5);
1074
82.6M
  }
1075
10.4M
    } else {
1076
0
  for (i = 0; i < comp->nbStep; i++) {
1077
0
      op = &comp->steps[i];
1078
0
      if (op->value4 != NULL) {
1079
0
    if (op->op == XPATH_OP_VALUE)
1080
0
        xmlXPathFreeObject(op->value4);
1081
0
      }
1082
0
  }
1083
0
        xmlDictFree(comp->dict);
1084
0
    }
1085
10.4M
    if (comp->steps != NULL) {
1086
10.4M
        xmlFree(comp->steps);
1087
10.4M
    }
1088
#ifdef DEBUG_EVAL_COUNTS
1089
    if (comp->string != NULL) {
1090
        xmlFree(comp->string);
1091
    }
1092
#endif
1093
10.4M
#ifdef XPATH_STREAMING
1094
10.4M
    if (comp->stream != NULL) {
1095
871k
        xmlFreePatternList(comp->stream);
1096
871k
    }
1097
10.4M
#endif
1098
10.4M
    if (comp->expr != NULL) {
1099
5.35M
        xmlFree(comp->expr);
1100
5.35M
    }
1101
1102
10.4M
    xmlFree(comp);
1103
10.4M
}
1104
1105
/**
1106
 * xmlXPathCompExprAdd:
1107
 * @comp:  the compiled expression
1108
 * @ch1: first child index
1109
 * @ch2: second child index
1110
 * @op:  an op
1111
 * @value:  the first int value
1112
 * @value2:  the second int value
1113
 * @value3:  the third int value
1114
 * @value4:  the first string value
1115
 * @value5:  the second string value
1116
 *
1117
 * Add a step to an XPath Compiled Expression
1118
 *
1119
 * Returns -1 in case of failure, the index otherwise
1120
 */
1121
static int
1122
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1123
   xmlXPathOp op, int value,
1124
82.6M
   int value2, int value3, void *value4, void *value5) {
1125
82.6M
    xmlXPathCompExprPtr comp = ctxt->comp;
1126
82.6M
    if (comp->nbStep >= comp->maxStep) {
1127
3.68M
  xmlXPathStepOp *real;
1128
1129
3.68M
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
        }
1133
3.68M
  comp->maxStep *= 2;
1134
3.68M
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1135
3.68M
                          comp->maxStep * sizeof(xmlXPathStepOp));
1136
3.68M
  if (real == NULL) {
1137
0
      comp->maxStep /= 2;
1138
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1139
0
      return(-1);
1140
0
  }
1141
3.68M
  comp->steps = real;
1142
3.68M
    }
1143
82.6M
    comp->last = comp->nbStep;
1144
82.6M
    comp->steps[comp->nbStep].ch1 = ch1;
1145
82.6M
    comp->steps[comp->nbStep].ch2 = ch2;
1146
82.6M
    comp->steps[comp->nbStep].op = op;
1147
82.6M
    comp->steps[comp->nbStep].value = value;
1148
82.6M
    comp->steps[comp->nbStep].value2 = value2;
1149
82.6M
    comp->steps[comp->nbStep].value3 = value3;
1150
82.6M
    if ((comp->dict != NULL) &&
1151
82.6M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1152
0
   (op == XPATH_OP_COLLECT))) {
1153
0
        if (value4 != NULL) {
1154
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1155
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1156
0
      xmlFree(value4);
1157
0
  } else
1158
0
      comp->steps[comp->nbStep].value4 = NULL;
1159
0
        if (value5 != NULL) {
1160
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1161
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1162
0
      xmlFree(value5);
1163
0
  } else
1164
0
      comp->steps[comp->nbStep].value5 = NULL;
1165
82.6M
    } else {
1166
82.6M
  comp->steps[comp->nbStep].value4 = value4;
1167
82.6M
  comp->steps[comp->nbStep].value5 = value5;
1168
82.6M
    }
1169
82.6M
    comp->steps[comp->nbStep].cache = NULL;
1170
82.6M
    return(comp->nbStep++);
1171
82.6M
}
1172
1173
/**
1174
 * xmlXPathCompSwap:
1175
 * @comp:  the compiled expression
1176
 * @op: operation index
1177
 *
1178
 * Swaps 2 operations in the compiled expression
1179
 */
1180
static void
1181
76.2k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1182
76.2k
    int tmp;
1183
1184
#ifndef LIBXML_THREAD_ENABLED
1185
    /*
1186
     * Since this manipulates possibly shared variables, this is
1187
     * disabled if one detects that the library is used in a multithreaded
1188
     * application
1189
     */
1190
    if (xmlXPathDisableOptimizer)
1191
  return;
1192
#endif
1193
1194
76.2k
    tmp = op->ch1;
1195
76.2k
    op->ch1 = op->ch2;
1196
76.2k
    op->ch2 = tmp;
1197
76.2k
}
1198
1199
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1200
16.9M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1201
16.9M
                  (op), (val), (val2), (val3), (val4), (val5))
1202
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1203
14.1M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1204
14.1M
                  (op), (val), (val2), (val3), (val4), (val5))
1205
1206
20.1M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1207
20.1M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1208
1209
12.6M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1210
12.6M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1211
1212
18.6M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1213
18.6M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1214
18.6M
      (val), (val2), 0 ,NULL ,NULL)
1215
1216
/************************************************************************
1217
 *                  *
1218
 *    XPath object cache structures       *
1219
 *                  *
1220
 ************************************************************************/
1221
1222
/* #define XP_DEFAULT_CACHE_ON */
1223
1224
55.8M
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1225
1226
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1227
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1228
struct _xmlXPathContextCache {
1229
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1230
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1231
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1232
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1233
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1234
    int maxNodeset;
1235
    int maxString;
1236
    int maxBoolean;
1237
    int maxNumber;
1238
    int maxMisc;
1239
#ifdef XP_DEBUG_OBJ_USAGE
1240
    int dbgCachedAll;
1241
    int dbgCachedNodeset;
1242
    int dbgCachedString;
1243
    int dbgCachedBool;
1244
    int dbgCachedNumber;
1245
    int dbgCachedPoint;
1246
    int dbgCachedRange;
1247
    int dbgCachedLocset;
1248
    int dbgCachedUsers;
1249
    int dbgCachedXSLTTree;
1250
    int dbgCachedUndefined;
1251
1252
1253
    int dbgReusedAll;
1254
    int dbgReusedNodeset;
1255
    int dbgReusedString;
1256
    int dbgReusedBool;
1257
    int dbgReusedNumber;
1258
    int dbgReusedPoint;
1259
    int dbgReusedRange;
1260
    int dbgReusedLocset;
1261
    int dbgReusedUsers;
1262
    int dbgReusedXSLTTree;
1263
    int dbgReusedUndefined;
1264
1265
#endif
1266
};
1267
1268
/************************************************************************
1269
 *                  *
1270
 *    Debugging related functions       *
1271
 *                  *
1272
 ************************************************************************/
1273
1274
#define STRANGE             \
1275
611
    xmlGenericError(xmlGenericErrorContext,       \
1276
611
      "Internal error at %s:%d\n",        \
1277
611
            __FILE__, __LINE__);
1278
1279
#ifdef LIBXML_DEBUG_ENABLED
1280
static void
1281
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1282
0
    int i;
1283
0
    char shift[100];
1284
1285
0
    for (i = 0;((i < depth) && (i < 25));i++)
1286
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1287
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1288
0
    if (cur == NULL) {
1289
0
  fprintf(output, "%s", shift);
1290
0
  fprintf(output, "Node is NULL !\n");
1291
0
  return;
1292
1293
0
    }
1294
1295
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1296
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1297
0
  fprintf(output, "%s", shift);
1298
0
  fprintf(output, " /\n");
1299
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1300
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1301
0
    else
1302
0
  xmlDebugDumpOneNode(output, cur, depth);
1303
0
}
1304
static void
1305
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1306
0
    xmlNodePtr tmp;
1307
0
    int i;
1308
0
    char shift[100];
1309
1310
0
    for (i = 0;((i < depth) && (i < 25));i++)
1311
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1312
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1313
0
    if (cur == NULL) {
1314
0
  fprintf(output, "%s", shift);
1315
0
  fprintf(output, "Node is NULL !\n");
1316
0
  return;
1317
1318
0
    }
1319
1320
0
    while (cur != NULL) {
1321
0
  tmp = cur;
1322
0
  cur = cur->next;
1323
0
  xmlDebugDumpOneNode(output, tmp, depth);
1324
0
    }
1325
0
}
1326
1327
static void
1328
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1329
0
    int i;
1330
0
    char shift[100];
1331
1332
0
    for (i = 0;((i < depth) && (i < 25));i++)
1333
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1334
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1335
1336
0
    if (cur == NULL) {
1337
0
  fprintf(output, "%s", shift);
1338
0
  fprintf(output, "NodeSet is NULL !\n");
1339
0
  return;
1340
1341
0
    }
1342
1343
0
    if (cur != NULL) {
1344
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1345
0
  for (i = 0;i < cur->nodeNr;i++) {
1346
0
      fprintf(output, "%s", shift);
1347
0
      fprintf(output, "%d", i + 1);
1348
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1349
0
  }
1350
0
    }
1351
0
}
1352
1353
static void
1354
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1355
0
    int i;
1356
0
    char shift[100];
1357
1358
0
    for (i = 0;((i < depth) && (i < 25));i++)
1359
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1360
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1361
1362
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1363
0
  fprintf(output, "%s", shift);
1364
0
  fprintf(output, "Value Tree is NULL !\n");
1365
0
  return;
1366
1367
0
    }
1368
1369
0
    fprintf(output, "%s", shift);
1370
0
    fprintf(output, "%d", i + 1);
1371
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1372
0
}
1373
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1374
static void
1375
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1376
    int i;
1377
    char shift[100];
1378
1379
    for (i = 0;((i < depth) && (i < 25));i++)
1380
        shift[2 * i] = shift[2 * i + 1] = ' ';
1381
    shift[2 * i] = shift[2 * i + 1] = 0;
1382
1383
    if (cur == NULL) {
1384
  fprintf(output, "%s", shift);
1385
  fprintf(output, "LocationSet is NULL !\n");
1386
  return;
1387
1388
    }
1389
1390
    for (i = 0;i < cur->locNr;i++) {
1391
  fprintf(output, "%s", shift);
1392
        fprintf(output, "%d : ", i + 1);
1393
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1394
    }
1395
}
1396
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1397
1398
/**
1399
 * xmlXPathDebugDumpObject:
1400
 * @output:  the FILE * to dump the output
1401
 * @cur:  the object to inspect
1402
 * @depth:  indentation level
1403
 *
1404
 * Dump the content of the object for debugging purposes
1405
 */
1406
void
1407
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1408
0
    int i;
1409
0
    char shift[100];
1410
1411
0
    if (output == NULL) return;
1412
1413
0
    for (i = 0;((i < depth) && (i < 25));i++)
1414
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1415
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1416
1417
1418
0
    fprintf(output, "%s", shift);
1419
1420
0
    if (cur == NULL) {
1421
0
        fprintf(output, "Object is empty (NULL)\n");
1422
0
  return;
1423
0
    }
1424
0
    switch(cur->type) {
1425
0
        case XPATH_UNDEFINED:
1426
0
      fprintf(output, "Object is uninitialized\n");
1427
0
      break;
1428
0
        case XPATH_NODESET:
1429
0
      fprintf(output, "Object is a Node Set :\n");
1430
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1431
0
      break;
1432
0
  case XPATH_XSLT_TREE:
1433
0
      fprintf(output, "Object is an XSLT value tree :\n");
1434
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
        case XPATH_BOOLEAN:
1437
0
      fprintf(output, "Object is a Boolean : ");
1438
0
      if (cur->boolval) fprintf(output, "true\n");
1439
0
      else fprintf(output, "false\n");
1440
0
      break;
1441
0
        case XPATH_NUMBER:
1442
0
      switch (xmlXPathIsInf(cur->floatval)) {
1443
0
      case 1:
1444
0
    fprintf(output, "Object is a number : Infinity\n");
1445
0
    break;
1446
0
      case -1:
1447
0
    fprintf(output, "Object is a number : -Infinity\n");
1448
0
    break;
1449
0
      default:
1450
0
    if (xmlXPathIsNaN(cur->floatval)) {
1451
0
        fprintf(output, "Object is a number : NaN\n");
1452
0
    } else if (cur->floatval == 0) {
1453
                    /* Omit sign for negative zero. */
1454
0
        fprintf(output, "Object is a number : 0\n");
1455
0
    } else {
1456
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1457
0
    }
1458
0
      }
1459
0
      break;
1460
0
        case XPATH_STRING:
1461
0
      fprintf(output, "Object is a string : ");
1462
0
      xmlDebugDumpString(output, cur->stringval);
1463
0
      fprintf(output, "\n");
1464
0
      break;
1465
#ifdef LIBXML_XPTR_LOCS_ENABLED
1466
  case XPATH_POINT:
1467
      fprintf(output, "Object is a point : index %d in node", cur->index);
1468
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1469
      fprintf(output, "\n");
1470
      break;
1471
  case XPATH_RANGE:
1472
      if ((cur->user2 == NULL) ||
1473
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1474
    fprintf(output, "Object is a collapsed range :\n");
1475
    fprintf(output, "%s", shift);
1476
    if (cur->index >= 0)
1477
        fprintf(output, "index %d in ", cur->index);
1478
    fprintf(output, "node\n");
1479
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1480
                    depth + 1);
1481
      } else  {
1482
    fprintf(output, "Object is a range :\n");
1483
    fprintf(output, "%s", shift);
1484
    fprintf(output, "From ");
1485
    if (cur->index >= 0)
1486
        fprintf(output, "index %d in ", cur->index);
1487
    fprintf(output, "node\n");
1488
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1489
                    depth + 1);
1490
    fprintf(output, "%s", shift);
1491
    fprintf(output, "To ");
1492
    if (cur->index2 >= 0)
1493
        fprintf(output, "index %d in ", cur->index2);
1494
    fprintf(output, "node\n");
1495
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1496
                    depth + 1);
1497
    fprintf(output, "\n");
1498
      }
1499
      break;
1500
  case XPATH_LOCATIONSET:
1501
      fprintf(output, "Object is a Location Set:\n");
1502
      xmlXPathDebugDumpLocationSet(output,
1503
        (xmlLocationSetPtr) cur->user, depth);
1504
      break;
1505
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1506
0
  case XPATH_USERS:
1507
0
      fprintf(output, "Object is user defined\n");
1508
0
      break;
1509
0
    }
1510
0
}
1511
1512
static void
1513
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1514
0
                       xmlXPathStepOpPtr op, int depth) {
1515
0
    int i;
1516
0
    char shift[100];
1517
1518
0
    for (i = 0;((i < depth) && (i < 25));i++)
1519
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1520
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1521
1522
0
    fprintf(output, "%s", shift);
1523
0
    if (op == NULL) {
1524
0
  fprintf(output, "Step is NULL\n");
1525
0
  return;
1526
0
    }
1527
0
    switch (op->op) {
1528
0
        case XPATH_OP_END:
1529
0
      fprintf(output, "END"); break;
1530
0
        case XPATH_OP_AND:
1531
0
      fprintf(output, "AND"); break;
1532
0
        case XPATH_OP_OR:
1533
0
      fprintf(output, "OR"); break;
1534
0
        case XPATH_OP_EQUAL:
1535
0
       if (op->value)
1536
0
     fprintf(output, "EQUAL =");
1537
0
       else
1538
0
     fprintf(output, "EQUAL !=");
1539
0
       break;
1540
0
        case XPATH_OP_CMP:
1541
0
       if (op->value)
1542
0
     fprintf(output, "CMP <");
1543
0
       else
1544
0
     fprintf(output, "CMP >");
1545
0
       if (!op->value2)
1546
0
     fprintf(output, "=");
1547
0
       break;
1548
0
        case XPATH_OP_PLUS:
1549
0
       if (op->value == 0)
1550
0
     fprintf(output, "PLUS -");
1551
0
       else if (op->value == 1)
1552
0
     fprintf(output, "PLUS +");
1553
0
       else if (op->value == 2)
1554
0
     fprintf(output, "PLUS unary -");
1555
0
       else if (op->value == 3)
1556
0
     fprintf(output, "PLUS unary - -");
1557
0
       break;
1558
0
        case XPATH_OP_MULT:
1559
0
       if (op->value == 0)
1560
0
     fprintf(output, "MULT *");
1561
0
       else if (op->value == 1)
1562
0
     fprintf(output, "MULT div");
1563
0
       else
1564
0
     fprintf(output, "MULT mod");
1565
0
       break;
1566
0
        case XPATH_OP_UNION:
1567
0
       fprintf(output, "UNION"); break;
1568
0
        case XPATH_OP_ROOT:
1569
0
       fprintf(output, "ROOT"); break;
1570
0
        case XPATH_OP_NODE:
1571
0
       fprintf(output, "NODE"); break;
1572
0
        case XPATH_OP_SORT:
1573
0
       fprintf(output, "SORT"); break;
1574
0
        case XPATH_OP_COLLECT: {
1575
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1576
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1577
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1578
0
      const xmlChar *prefix = op->value4;
1579
0
      const xmlChar *name = op->value5;
1580
1581
0
      fprintf(output, "COLLECT ");
1582
0
      switch (axis) {
1583
0
    case AXIS_ANCESTOR:
1584
0
        fprintf(output, " 'ancestors' "); break;
1585
0
    case AXIS_ANCESTOR_OR_SELF:
1586
0
        fprintf(output, " 'ancestors-or-self' "); break;
1587
0
    case AXIS_ATTRIBUTE:
1588
0
        fprintf(output, " 'attributes' "); break;
1589
0
    case AXIS_CHILD:
1590
0
        fprintf(output, " 'child' "); break;
1591
0
    case AXIS_DESCENDANT:
1592
0
        fprintf(output, " 'descendant' "); break;
1593
0
    case AXIS_DESCENDANT_OR_SELF:
1594
0
        fprintf(output, " 'descendant-or-self' "); break;
1595
0
    case AXIS_FOLLOWING:
1596
0
        fprintf(output, " 'following' "); break;
1597
0
    case AXIS_FOLLOWING_SIBLING:
1598
0
        fprintf(output, " 'following-siblings' "); break;
1599
0
    case AXIS_NAMESPACE:
1600
0
        fprintf(output, " 'namespace' "); break;
1601
0
    case AXIS_PARENT:
1602
0
        fprintf(output, " 'parent' "); break;
1603
0
    case AXIS_PRECEDING:
1604
0
        fprintf(output, " 'preceding' "); break;
1605
0
    case AXIS_PRECEDING_SIBLING:
1606
0
        fprintf(output, " 'preceding-sibling' "); break;
1607
0
    case AXIS_SELF:
1608
0
        fprintf(output, " 'self' "); break;
1609
0
      }
1610
0
      switch (test) {
1611
0
                case NODE_TEST_NONE:
1612
0
        fprintf(output, "'none' "); break;
1613
0
                case NODE_TEST_TYPE:
1614
0
        fprintf(output, "'type' "); break;
1615
0
                case NODE_TEST_PI:
1616
0
        fprintf(output, "'PI' "); break;
1617
0
                case NODE_TEST_ALL:
1618
0
        fprintf(output, "'all' "); break;
1619
0
                case NODE_TEST_NS:
1620
0
        fprintf(output, "'namespace' "); break;
1621
0
                case NODE_TEST_NAME:
1622
0
        fprintf(output, "'name' "); break;
1623
0
      }
1624
0
      switch (type) {
1625
0
                case NODE_TYPE_NODE:
1626
0
        fprintf(output, "'node' "); break;
1627
0
                case NODE_TYPE_COMMENT:
1628
0
        fprintf(output, "'comment' "); break;
1629
0
                case NODE_TYPE_TEXT:
1630
0
        fprintf(output, "'text' "); break;
1631
0
                case NODE_TYPE_PI:
1632
0
        fprintf(output, "'PI' "); break;
1633
0
      }
1634
0
      if (prefix != NULL)
1635
0
    fprintf(output, "%s:", prefix);
1636
0
      if (name != NULL)
1637
0
    fprintf(output, "%s", (const char *) name);
1638
0
      break;
1639
1640
0
        }
1641
0
  case XPATH_OP_VALUE: {
1642
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1643
1644
0
      fprintf(output, "ELEM ");
1645
0
      xmlXPathDebugDumpObject(output, object, 0);
1646
0
      goto finish;
1647
0
  }
1648
0
  case XPATH_OP_VARIABLE: {
1649
0
      const xmlChar *prefix = op->value5;
1650
0
      const xmlChar *name = op->value4;
1651
1652
0
      if (prefix != NULL)
1653
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1654
0
      else
1655
0
    fprintf(output, "VARIABLE %s", name);
1656
0
      break;
1657
0
  }
1658
0
  case XPATH_OP_FUNCTION: {
1659
0
      int nbargs = op->value;
1660
0
      const xmlChar *prefix = op->value5;
1661
0
      const xmlChar *name = op->value4;
1662
1663
0
      if (prefix != NULL)
1664
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1665
0
      prefix, name, nbargs);
1666
0
      else
1667
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1668
0
      break;
1669
0
  }
1670
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1671
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1672
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1673
#ifdef LIBXML_XPTR_LOCS_ENABLED
1674
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1675
#endif
1676
0
  default:
1677
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1678
0
    }
1679
0
    fprintf(output, "\n");
1680
0
finish:
1681
0
    if (op->ch1 >= 0)
1682
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1683
0
    if (op->ch2 >= 0)
1684
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1685
0
}
1686
1687
/**
1688
 * xmlXPathDebugDumpCompExpr:
1689
 * @output:  the FILE * for the output
1690
 * @comp:  the precompiled XPath expression
1691
 * @depth:  the indentation level.
1692
 *
1693
 * Dumps the tree of the compiled XPath expression.
1694
 */
1695
void
1696
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1697
0
                    int depth) {
1698
0
    int i;
1699
0
    char shift[100];
1700
1701
0
    if ((output == NULL) || (comp == NULL)) return;
1702
1703
0
    for (i = 0;((i < depth) && (i < 25));i++)
1704
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1705
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1706
1707
0
    fprintf(output, "%s", shift);
1708
1709
0
#ifdef XPATH_STREAMING
1710
0
    if (comp->stream) {
1711
0
        fprintf(output, "Streaming Expression\n");
1712
0
    } else
1713
0
#endif
1714
0
    {
1715
0
        fprintf(output, "Compiled Expression : %d elements\n",
1716
0
                comp->nbStep);
1717
0
        i = comp->last;
1718
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1719
0
    }
1720
0
}
1721
1722
#ifdef XP_DEBUG_OBJ_USAGE
1723
1724
/*
1725
* XPath object usage related debugging variables.
1726
*/
1727
static int xmlXPathDebugObjCounterUndefined = 0;
1728
static int xmlXPathDebugObjCounterNodeset = 0;
1729
static int xmlXPathDebugObjCounterBool = 0;
1730
static int xmlXPathDebugObjCounterNumber = 0;
1731
static int xmlXPathDebugObjCounterString = 0;
1732
static int xmlXPathDebugObjCounterPoint = 0;
1733
static int xmlXPathDebugObjCounterRange = 0;
1734
static int xmlXPathDebugObjCounterLocset = 0;
1735
static int xmlXPathDebugObjCounterUsers = 0;
1736
static int xmlXPathDebugObjCounterXSLTTree = 0;
1737
static int xmlXPathDebugObjCounterAll = 0;
1738
1739
static int xmlXPathDebugObjTotalUndefined = 0;
1740
static int xmlXPathDebugObjTotalNodeset = 0;
1741
static int xmlXPathDebugObjTotalBool = 0;
1742
static int xmlXPathDebugObjTotalNumber = 0;
1743
static int xmlXPathDebugObjTotalString = 0;
1744
static int xmlXPathDebugObjTotalPoint = 0;
1745
static int xmlXPathDebugObjTotalRange = 0;
1746
static int xmlXPathDebugObjTotalLocset = 0;
1747
static int xmlXPathDebugObjTotalUsers = 0;
1748
static int xmlXPathDebugObjTotalXSLTTree = 0;
1749
static int xmlXPathDebugObjTotalAll = 0;
1750
1751
static int xmlXPathDebugObjMaxUndefined = 0;
1752
static int xmlXPathDebugObjMaxNodeset = 0;
1753
static int xmlXPathDebugObjMaxBool = 0;
1754
static int xmlXPathDebugObjMaxNumber = 0;
1755
static int xmlXPathDebugObjMaxString = 0;
1756
static int xmlXPathDebugObjMaxPoint = 0;
1757
static int xmlXPathDebugObjMaxRange = 0;
1758
static int xmlXPathDebugObjMaxLocset = 0;
1759
static int xmlXPathDebugObjMaxUsers = 0;
1760
static int xmlXPathDebugObjMaxXSLTTree = 0;
1761
static int xmlXPathDebugObjMaxAll = 0;
1762
1763
static void
1764
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1765
{
1766
    if (ctxt != NULL) {
1767
  if (ctxt->cache != NULL) {
1768
      xmlXPathContextCachePtr cache =
1769
    (xmlXPathContextCachePtr) ctxt->cache;
1770
1771
      cache->dbgCachedAll = 0;
1772
      cache->dbgCachedNodeset = 0;
1773
      cache->dbgCachedString = 0;
1774
      cache->dbgCachedBool = 0;
1775
      cache->dbgCachedNumber = 0;
1776
      cache->dbgCachedPoint = 0;
1777
      cache->dbgCachedRange = 0;
1778
      cache->dbgCachedLocset = 0;
1779
      cache->dbgCachedUsers = 0;
1780
      cache->dbgCachedXSLTTree = 0;
1781
      cache->dbgCachedUndefined = 0;
1782
1783
      cache->dbgReusedAll = 0;
1784
      cache->dbgReusedNodeset = 0;
1785
      cache->dbgReusedString = 0;
1786
      cache->dbgReusedBool = 0;
1787
      cache->dbgReusedNumber = 0;
1788
      cache->dbgReusedPoint = 0;
1789
      cache->dbgReusedRange = 0;
1790
      cache->dbgReusedLocset = 0;
1791
      cache->dbgReusedUsers = 0;
1792
      cache->dbgReusedXSLTTree = 0;
1793
      cache->dbgReusedUndefined = 0;
1794
  }
1795
    }
1796
1797
    xmlXPathDebugObjCounterUndefined = 0;
1798
    xmlXPathDebugObjCounterNodeset = 0;
1799
    xmlXPathDebugObjCounterBool = 0;
1800
    xmlXPathDebugObjCounterNumber = 0;
1801
    xmlXPathDebugObjCounterString = 0;
1802
    xmlXPathDebugObjCounterPoint = 0;
1803
    xmlXPathDebugObjCounterRange = 0;
1804
    xmlXPathDebugObjCounterLocset = 0;
1805
    xmlXPathDebugObjCounterUsers = 0;
1806
    xmlXPathDebugObjCounterXSLTTree = 0;
1807
    xmlXPathDebugObjCounterAll = 0;
1808
1809
    xmlXPathDebugObjTotalUndefined = 0;
1810
    xmlXPathDebugObjTotalNodeset = 0;
1811
    xmlXPathDebugObjTotalBool = 0;
1812
    xmlXPathDebugObjTotalNumber = 0;
1813
    xmlXPathDebugObjTotalString = 0;
1814
    xmlXPathDebugObjTotalPoint = 0;
1815
    xmlXPathDebugObjTotalRange = 0;
1816
    xmlXPathDebugObjTotalLocset = 0;
1817
    xmlXPathDebugObjTotalUsers = 0;
1818
    xmlXPathDebugObjTotalXSLTTree = 0;
1819
    xmlXPathDebugObjTotalAll = 0;
1820
1821
    xmlXPathDebugObjMaxUndefined = 0;
1822
    xmlXPathDebugObjMaxNodeset = 0;
1823
    xmlXPathDebugObjMaxBool = 0;
1824
    xmlXPathDebugObjMaxNumber = 0;
1825
    xmlXPathDebugObjMaxString = 0;
1826
    xmlXPathDebugObjMaxPoint = 0;
1827
    xmlXPathDebugObjMaxRange = 0;
1828
    xmlXPathDebugObjMaxLocset = 0;
1829
    xmlXPathDebugObjMaxUsers = 0;
1830
    xmlXPathDebugObjMaxXSLTTree = 0;
1831
    xmlXPathDebugObjMaxAll = 0;
1832
1833
}
1834
1835
static void
1836
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1837
            xmlXPathObjectType objType)
1838
{
1839
    int isCached = 0;
1840
1841
    if (ctxt != NULL) {
1842
  if (ctxt->cache != NULL) {
1843
      xmlXPathContextCachePtr cache =
1844
    (xmlXPathContextCachePtr) ctxt->cache;
1845
1846
      isCached = 1;
1847
1848
      cache->dbgReusedAll++;
1849
      switch (objType) {
1850
    case XPATH_UNDEFINED:
1851
        cache->dbgReusedUndefined++;
1852
        break;
1853
    case XPATH_NODESET:
1854
        cache->dbgReusedNodeset++;
1855
        break;
1856
    case XPATH_BOOLEAN:
1857
        cache->dbgReusedBool++;
1858
        break;
1859
    case XPATH_NUMBER:
1860
        cache->dbgReusedNumber++;
1861
        break;
1862
    case XPATH_STRING:
1863
        cache->dbgReusedString++;
1864
        break;
1865
#ifdef LIBXML_XPTR_LOCS_ENABLED
1866
    case XPATH_POINT:
1867
        cache->dbgReusedPoint++;
1868
        break;
1869
    case XPATH_RANGE:
1870
        cache->dbgReusedRange++;
1871
        break;
1872
    case XPATH_LOCATIONSET:
1873
        cache->dbgReusedLocset++;
1874
        break;
1875
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1876
    case XPATH_USERS:
1877
        cache->dbgReusedUsers++;
1878
        break;
1879
    case XPATH_XSLT_TREE:
1880
        cache->dbgReusedXSLTTree++;
1881
        break;
1882
    default:
1883
        break;
1884
      }
1885
  }
1886
    }
1887
1888
    switch (objType) {
1889
  case XPATH_UNDEFINED:
1890
      if (! isCached)
1891
    xmlXPathDebugObjTotalUndefined++;
1892
      xmlXPathDebugObjCounterUndefined++;
1893
      if (xmlXPathDebugObjCounterUndefined >
1894
    xmlXPathDebugObjMaxUndefined)
1895
    xmlXPathDebugObjMaxUndefined =
1896
        xmlXPathDebugObjCounterUndefined;
1897
      break;
1898
  case XPATH_NODESET:
1899
      if (! isCached)
1900
    xmlXPathDebugObjTotalNodeset++;
1901
      xmlXPathDebugObjCounterNodeset++;
1902
      if (xmlXPathDebugObjCounterNodeset >
1903
    xmlXPathDebugObjMaxNodeset)
1904
    xmlXPathDebugObjMaxNodeset =
1905
        xmlXPathDebugObjCounterNodeset;
1906
      break;
1907
  case XPATH_BOOLEAN:
1908
      if (! isCached)
1909
    xmlXPathDebugObjTotalBool++;
1910
      xmlXPathDebugObjCounterBool++;
1911
      if (xmlXPathDebugObjCounterBool >
1912
    xmlXPathDebugObjMaxBool)
1913
    xmlXPathDebugObjMaxBool =
1914
        xmlXPathDebugObjCounterBool;
1915
      break;
1916
  case XPATH_NUMBER:
1917
      if (! isCached)
1918
    xmlXPathDebugObjTotalNumber++;
1919
      xmlXPathDebugObjCounterNumber++;
1920
      if (xmlXPathDebugObjCounterNumber >
1921
    xmlXPathDebugObjMaxNumber)
1922
    xmlXPathDebugObjMaxNumber =
1923
        xmlXPathDebugObjCounterNumber;
1924
      break;
1925
  case XPATH_STRING:
1926
      if (! isCached)
1927
    xmlXPathDebugObjTotalString++;
1928
      xmlXPathDebugObjCounterString++;
1929
      if (xmlXPathDebugObjCounterString >
1930
    xmlXPathDebugObjMaxString)
1931
    xmlXPathDebugObjMaxString =
1932
        xmlXPathDebugObjCounterString;
1933
      break;
1934
#ifdef LIBXML_XPTR_LOCS_ENABLED
1935
  case XPATH_POINT:
1936
      if (! isCached)
1937
    xmlXPathDebugObjTotalPoint++;
1938
      xmlXPathDebugObjCounterPoint++;
1939
      if (xmlXPathDebugObjCounterPoint >
1940
    xmlXPathDebugObjMaxPoint)
1941
    xmlXPathDebugObjMaxPoint =
1942
        xmlXPathDebugObjCounterPoint;
1943
      break;
1944
  case XPATH_RANGE:
1945
      if (! isCached)
1946
    xmlXPathDebugObjTotalRange++;
1947
      xmlXPathDebugObjCounterRange++;
1948
      if (xmlXPathDebugObjCounterRange >
1949
    xmlXPathDebugObjMaxRange)
1950
    xmlXPathDebugObjMaxRange =
1951
        xmlXPathDebugObjCounterRange;
1952
      break;
1953
  case XPATH_LOCATIONSET:
1954
      if (! isCached)
1955
    xmlXPathDebugObjTotalLocset++;
1956
      xmlXPathDebugObjCounterLocset++;
1957
      if (xmlXPathDebugObjCounterLocset >
1958
    xmlXPathDebugObjMaxLocset)
1959
    xmlXPathDebugObjMaxLocset =
1960
        xmlXPathDebugObjCounterLocset;
1961
      break;
1962
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1963
  case XPATH_USERS:
1964
      if (! isCached)
1965
    xmlXPathDebugObjTotalUsers++;
1966
      xmlXPathDebugObjCounterUsers++;
1967
      if (xmlXPathDebugObjCounterUsers >
1968
    xmlXPathDebugObjMaxUsers)
1969
    xmlXPathDebugObjMaxUsers =
1970
        xmlXPathDebugObjCounterUsers;
1971
      break;
1972
  case XPATH_XSLT_TREE:
1973
      if (! isCached)
1974
    xmlXPathDebugObjTotalXSLTTree++;
1975
      xmlXPathDebugObjCounterXSLTTree++;
1976
      if (xmlXPathDebugObjCounterXSLTTree >
1977
    xmlXPathDebugObjMaxXSLTTree)
1978
    xmlXPathDebugObjMaxXSLTTree =
1979
        xmlXPathDebugObjCounterXSLTTree;
1980
      break;
1981
  default:
1982
      break;
1983
    }
1984
    if (! isCached)
1985
  xmlXPathDebugObjTotalAll++;
1986
    xmlXPathDebugObjCounterAll++;
1987
    if (xmlXPathDebugObjCounterAll >
1988
  xmlXPathDebugObjMaxAll)
1989
  xmlXPathDebugObjMaxAll =
1990
      xmlXPathDebugObjCounterAll;
1991
}
1992
1993
static void
1994
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1995
            xmlXPathObjectType objType)
1996
{
1997
    int isCached = 0;
1998
1999
    if (ctxt != NULL) {
2000
  if (ctxt->cache != NULL) {
2001
      xmlXPathContextCachePtr cache =
2002
    (xmlXPathContextCachePtr) ctxt->cache;
2003
2004
      isCached = 1;
2005
2006
      cache->dbgCachedAll++;
2007
      switch (objType) {
2008
    case XPATH_UNDEFINED:
2009
        cache->dbgCachedUndefined++;
2010
        break;
2011
    case XPATH_NODESET:
2012
        cache->dbgCachedNodeset++;
2013
        break;
2014
    case XPATH_BOOLEAN:
2015
        cache->dbgCachedBool++;
2016
        break;
2017
    case XPATH_NUMBER:
2018
        cache->dbgCachedNumber++;
2019
        break;
2020
    case XPATH_STRING:
2021
        cache->dbgCachedString++;
2022
        break;
2023
#ifdef LIBXML_XPTR_LOCS_ENABLED
2024
    case XPATH_POINT:
2025
        cache->dbgCachedPoint++;
2026
        break;
2027
    case XPATH_RANGE:
2028
        cache->dbgCachedRange++;
2029
        break;
2030
    case XPATH_LOCATIONSET:
2031
        cache->dbgCachedLocset++;
2032
        break;
2033
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2034
    case XPATH_USERS:
2035
        cache->dbgCachedUsers++;
2036
        break;
2037
    case XPATH_XSLT_TREE:
2038
        cache->dbgCachedXSLTTree++;
2039
        break;
2040
    default:
2041
        break;
2042
      }
2043
2044
  }
2045
    }
2046
    switch (objType) {
2047
  case XPATH_UNDEFINED:
2048
      xmlXPathDebugObjCounterUndefined--;
2049
      break;
2050
  case XPATH_NODESET:
2051
      xmlXPathDebugObjCounterNodeset--;
2052
      break;
2053
  case XPATH_BOOLEAN:
2054
      xmlXPathDebugObjCounterBool--;
2055
      break;
2056
  case XPATH_NUMBER:
2057
      xmlXPathDebugObjCounterNumber--;
2058
      break;
2059
  case XPATH_STRING:
2060
      xmlXPathDebugObjCounterString--;
2061
      break;
2062
#ifdef LIBXML_XPTR_LOCS_ENABLED
2063
  case XPATH_POINT:
2064
      xmlXPathDebugObjCounterPoint--;
2065
      break;
2066
  case XPATH_RANGE:
2067
      xmlXPathDebugObjCounterRange--;
2068
      break;
2069
  case XPATH_LOCATIONSET:
2070
      xmlXPathDebugObjCounterLocset--;
2071
      break;
2072
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2073
  case XPATH_USERS:
2074
      xmlXPathDebugObjCounterUsers--;
2075
      break;
2076
  case XPATH_XSLT_TREE:
2077
      xmlXPathDebugObjCounterXSLTTree--;
2078
      break;
2079
  default:
2080
      break;
2081
    }
2082
    xmlXPathDebugObjCounterAll--;
2083
}
2084
2085
static void
2086
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2087
{
2088
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2089
  reqXSLTTree, reqUndefined;
2090
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2091
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2092
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2093
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2094
    int leftObjs = xmlXPathDebugObjCounterAll;
2095
2096
    reqAll = xmlXPathDebugObjTotalAll;
2097
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2098
    reqString = xmlXPathDebugObjTotalString;
2099
    reqBool = xmlXPathDebugObjTotalBool;
2100
    reqNumber = xmlXPathDebugObjTotalNumber;
2101
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2102
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2103
2104
    printf("# XPath object usage:\n");
2105
2106
    if (ctxt != NULL) {
2107
  if (ctxt->cache != NULL) {
2108
      xmlXPathContextCachePtr cache =
2109
    (xmlXPathContextCachePtr) ctxt->cache;
2110
2111
      reAll = cache->dbgReusedAll;
2112
      reqAll += reAll;
2113
      reNodeset = cache->dbgReusedNodeset;
2114
      reqNodeset += reNodeset;
2115
      reString = cache->dbgReusedString;
2116
      reqString += reString;
2117
      reBool = cache->dbgReusedBool;
2118
      reqBool += reBool;
2119
      reNumber = cache->dbgReusedNumber;
2120
      reqNumber += reNumber;
2121
      reXSLTTree = cache->dbgReusedXSLTTree;
2122
      reqXSLTTree += reXSLTTree;
2123
      reUndefined = cache->dbgReusedUndefined;
2124
      reqUndefined += reUndefined;
2125
2126
      caAll = cache->dbgCachedAll;
2127
      caBool = cache->dbgCachedBool;
2128
      caNodeset = cache->dbgCachedNodeset;
2129
      caString = cache->dbgCachedString;
2130
      caNumber = cache->dbgCachedNumber;
2131
      caXSLTTree = cache->dbgCachedXSLTTree;
2132
      caUndefined = cache->dbgCachedUndefined;
2133
2134
      if (cache->nodesetObjs)
2135
    leftObjs -= cache->nodesetObjs->number;
2136
      if (cache->stringObjs)
2137
    leftObjs -= cache->stringObjs->number;
2138
      if (cache->booleanObjs)
2139
    leftObjs -= cache->booleanObjs->number;
2140
      if (cache->numberObjs)
2141
    leftObjs -= cache->numberObjs->number;
2142
      if (cache->miscObjs)
2143
    leftObjs -= cache->miscObjs->number;
2144
  }
2145
    }
2146
2147
    printf("# all\n");
2148
    printf("#   total  : %d\n", reqAll);
2149
    printf("#   left  : %d\n", leftObjs);
2150
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2151
    printf("#   reused : %d\n", reAll);
2152
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2153
2154
    printf("# node-sets\n");
2155
    printf("#   total  : %d\n", reqNodeset);
2156
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2157
    printf("#   reused : %d\n", reNodeset);
2158
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2159
2160
    printf("# strings\n");
2161
    printf("#   total  : %d\n", reqString);
2162
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2163
    printf("#   reused : %d\n", reString);
2164
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2165
2166
    printf("# booleans\n");
2167
    printf("#   total  : %d\n", reqBool);
2168
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2169
    printf("#   reused : %d\n", reBool);
2170
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2171
2172
    printf("# numbers\n");
2173
    printf("#   total  : %d\n", reqNumber);
2174
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2175
    printf("#   reused : %d\n", reNumber);
2176
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2177
2178
    printf("# XSLT result tree fragments\n");
2179
    printf("#   total  : %d\n", reqXSLTTree);
2180
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2181
    printf("#   reused : %d\n", reXSLTTree);
2182
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2183
2184
    printf("# undefined\n");
2185
    printf("#   total  : %d\n", reqUndefined);
2186
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2187
    printf("#   reused : %d\n", reUndefined);
2188
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2189
2190
}
2191
2192
#endif /* XP_DEBUG_OBJ_USAGE */
2193
2194
#endif /* LIBXML_DEBUG_ENABLED */
2195
2196
/************************************************************************
2197
 *                  *
2198
 *      XPath object caching        *
2199
 *                  *
2200
 ************************************************************************/
2201
2202
/**
2203
 * xmlXPathNewCache:
2204
 *
2205
 * Create a new object cache
2206
 *
2207
 * Returns the xmlXPathCache just allocated.
2208
 */
2209
static xmlXPathContextCachePtr
2210
xmlXPathNewCache(void)
2211
188k
{
2212
188k
    xmlXPathContextCachePtr ret;
2213
2214
188k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2215
188k
    if (ret == NULL) {
2216
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2217
0
  return(NULL);
2218
0
    }
2219
188k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2220
188k
    ret->maxNodeset = 100;
2221
188k
    ret->maxString = 100;
2222
188k
    ret->maxBoolean = 100;
2223
188k
    ret->maxNumber = 100;
2224
188k
    ret->maxMisc = 100;
2225
188k
    return(ret);
2226
188k
}
2227
2228
static void
2229
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2230
496k
{
2231
496k
    int i;
2232
496k
    xmlXPathObjectPtr obj;
2233
2234
496k
    if (list == NULL)
2235
0
  return;
2236
2237
9.18M
    for (i = 0; i < list->number; i++) {
2238
8.69M
  obj = list->items[i];
2239
  /*
2240
  * Note that it is already assured that we don't need to
2241
  * look out for namespace nodes in the node-set.
2242
  */
2243
8.69M
  if (obj->nodesetval != NULL) {
2244
6.02M
      if (obj->nodesetval->nodeTab != NULL)
2245
4.22M
    xmlFree(obj->nodesetval->nodeTab);
2246
6.02M
      xmlFree(obj->nodesetval);
2247
6.02M
  }
2248
8.69M
  xmlFree(obj);
2249
#ifdef XP_DEBUG_OBJ_USAGE
2250
  xmlXPathDebugObjCounterAll--;
2251
#endif
2252
8.69M
    }
2253
496k
    xmlPointerListFree(list);
2254
496k
}
2255
2256
static void
2257
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2258
180k
{
2259
180k
    if (cache == NULL)
2260
0
  return;
2261
180k
    if (cache->nodesetObjs)
2262
138k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2263
180k
    if (cache->stringObjs)
2264
106k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2265
180k
    if (cache->booleanObjs)
2266
72.7k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2267
180k
    if (cache->numberObjs)
2268
90.7k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2269
180k
    if (cache->miscObjs)
2270
88.6k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2271
180k
    xmlFree(cache);
2272
180k
}
2273
2274
/**
2275
 * xmlXPathContextSetCache:
2276
 *
2277
 * @ctxt:  the XPath context
2278
 * @active: enables/disables (creates/frees) the cache
2279
 * @value: a value with semantics dependent on @options
2280
 * @options: options (currently only the value 0 is used)
2281
 *
2282
 * Creates/frees an object cache on the XPath context.
2283
 * If activates XPath objects (xmlXPathObject) will be cached internally
2284
 * to be reused.
2285
 * @options:
2286
 *   0: This will set the XPath object caching:
2287
 *      @value:
2288
 *        This will set the maximum number of XPath objects
2289
 *        to be cached per slot
2290
 *        There are 5 slots for: node-set, string, number, boolean, and
2291
 *        misc objects. Use <0 for the default number (100).
2292
 *   Other values for @options have currently no effect.
2293
 *
2294
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2295
 */
2296
int
2297
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2298
      int active,
2299
      int value,
2300
      int options)
2301
369k
{
2302
369k
    if (ctxt == NULL)
2303
0
  return(-1);
2304
369k
    if (active) {
2305
188k
  xmlXPathContextCachePtr cache;
2306
2307
188k
  if (ctxt->cache == NULL) {
2308
188k
      ctxt->cache = xmlXPathNewCache();
2309
188k
      if (ctxt->cache == NULL)
2310
0
    return(-1);
2311
188k
  }
2312
188k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2313
188k
  if (options == 0) {
2314
188k
      if (value < 0)
2315
188k
    value = 100;
2316
188k
      cache->maxNodeset = value;
2317
188k
      cache->maxString = value;
2318
188k
      cache->maxNumber = value;
2319
188k
      cache->maxBoolean = value;
2320
188k
      cache->maxMisc = value;
2321
188k
  }
2322
188k
    } else if (ctxt->cache != NULL) {
2323
180k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2324
180k
  ctxt->cache = NULL;
2325
180k
    }
2326
369k
    return(0);
2327
369k
}
2328
2329
/**
2330
 * xmlXPathCacheWrapNodeSet:
2331
 * @ctxt: the XPath context
2332
 * @val:  the NodePtr value
2333
 *
2334
 * This is the cached version of xmlXPathWrapNodeSet().
2335
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2336
 *
2337
 * Returns the created or reused object.
2338
 */
2339
static xmlXPathObjectPtr
2340
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2341
91.4M
{
2342
91.4M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2343
91.4M
  xmlXPathContextCachePtr cache =
2344
91.4M
      (xmlXPathContextCachePtr) ctxt->cache;
2345
2346
91.4M
  if ((cache->miscObjs != NULL) &&
2347
91.4M
      (cache->miscObjs->number != 0))
2348
75.8M
  {
2349
75.8M
      xmlXPathObjectPtr ret;
2350
2351
75.8M
      ret = (xmlXPathObjectPtr)
2352
75.8M
    cache->miscObjs->items[--cache->miscObjs->number];
2353
75.8M
      ret->type = XPATH_NODESET;
2354
75.8M
      ret->nodesetval = val;
2355
#ifdef XP_DEBUG_OBJ_USAGE
2356
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2357
#endif
2358
75.8M
      return(ret);
2359
75.8M
  }
2360
91.4M
    }
2361
2362
15.5M
    return(xmlXPathWrapNodeSet(val));
2363
2364
91.4M
}
2365
2366
/**
2367
 * xmlXPathCacheWrapString:
2368
 * @ctxt: the XPath context
2369
 * @val:  the xmlChar * value
2370
 *
2371
 * This is the cached version of xmlXPathWrapString().
2372
 * Wraps the @val string into an XPath object.
2373
 *
2374
 * Returns the created or reused object.
2375
 */
2376
static xmlXPathObjectPtr
2377
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2378
7.20M
{
2379
7.20M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2380
7.20M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2381
2382
7.20M
  if ((cache->stringObjs != NULL) &&
2383
7.20M
      (cache->stringObjs->number != 0))
2384
4.13M
  {
2385
2386
4.13M
      xmlXPathObjectPtr ret;
2387
2388
4.13M
      ret = (xmlXPathObjectPtr)
2389
4.13M
    cache->stringObjs->items[--cache->stringObjs->number];
2390
4.13M
      ret->type = XPATH_STRING;
2391
4.13M
      ret->stringval = val;
2392
#ifdef XP_DEBUG_OBJ_USAGE
2393
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394
#endif
2395
4.13M
      return(ret);
2396
4.13M
  } else if ((cache->miscObjs != NULL) &&
2397
3.06M
      (cache->miscObjs->number != 0))
2398
2.51M
  {
2399
2.51M
      xmlXPathObjectPtr ret;
2400
      /*
2401
      * Fallback to misc-cache.
2402
      */
2403
2.51M
      ret = (xmlXPathObjectPtr)
2404
2.51M
    cache->miscObjs->items[--cache->miscObjs->number];
2405
2406
2.51M
      ret->type = XPATH_STRING;
2407
2.51M
      ret->stringval = val;
2408
#ifdef XP_DEBUG_OBJ_USAGE
2409
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2410
#endif
2411
2.51M
      return(ret);
2412
2.51M
  }
2413
7.20M
    }
2414
551k
    return(xmlXPathWrapString(val));
2415
7.20M
}
2416
2417
/**
2418
 * xmlXPathCacheNewNodeSet:
2419
 * @ctxt: the XPath context
2420
 * @val:  the NodePtr value
2421
 *
2422
 * This is the cached version of xmlXPathNewNodeSet().
2423
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2424
 * it with the single Node @val
2425
 *
2426
 * Returns the created or reused object.
2427
 */
2428
static xmlXPathObjectPtr
2429
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2430
104M
{
2431
104M
    if ((ctxt != NULL) && (ctxt->cache)) {
2432
104M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2433
2434
104M
  if ((cache->nodesetObjs != NULL) &&
2435
104M
      (cache->nodesetObjs->number != 0))
2436
101M
  {
2437
101M
      xmlXPathObjectPtr ret;
2438
      /*
2439
      * Use the nodeset-cache.
2440
      */
2441
101M
      ret = (xmlXPathObjectPtr)
2442
101M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2443
101M
      ret->type = XPATH_NODESET;
2444
101M
      ret->boolval = 0;
2445
101M
      if (val) {
2446
100M
    if ((ret->nodesetval->nodeMax == 0) ||
2447
100M
        (val->type == XML_NAMESPACE_DECL))
2448
16.4M
    {
2449
                    /* TODO: Check memory error. */
2450
16.4M
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2451
84.0M
    } else {
2452
84.0M
        ret->nodesetval->nodeTab[0] = val;
2453
84.0M
        ret->nodesetval->nodeNr = 1;
2454
84.0M
    }
2455
100M
      }
2456
#ifdef XP_DEBUG_OBJ_USAGE
2457
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458
#endif
2459
101M
      return(ret);
2460
101M
  } else if ((cache->miscObjs != NULL) &&
2461
2.94M
      (cache->miscObjs->number != 0))
2462
578k
  {
2463
578k
      xmlXPathObjectPtr ret;
2464
      /*
2465
      * Fallback to misc-cache.
2466
      */
2467
2468
578k
      ret = (xmlXPathObjectPtr)
2469
578k
    cache->miscObjs->items[--cache->miscObjs->number];
2470
2471
578k
      ret->type = XPATH_NODESET;
2472
578k
      ret->boolval = 0;
2473
578k
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2474
578k
      if (ret->nodesetval == NULL) {
2475
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2476
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2477
0
    return(NULL);
2478
0
      }
2479
#ifdef XP_DEBUG_OBJ_USAGE
2480
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2481
#endif
2482
578k
      return(ret);
2483
578k
  }
2484
104M
    }
2485
2.36M
    return(xmlXPathNewNodeSet(val));
2486
104M
}
2487
2488
/**
2489
 * xmlXPathCacheNewCString:
2490
 * @ctxt: the XPath context
2491
 * @val:  the char * value
2492
 *
2493
 * This is the cached version of xmlXPathNewCString().
2494
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2495
 *
2496
 * Returns the created or reused object.
2497
 */
2498
static xmlXPathObjectPtr
2499
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2500
2.78M
{
2501
2.78M
    if ((ctxt != NULL) && (ctxt->cache)) {
2502
2.78M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504
2.78M
  if ((cache->stringObjs != NULL) &&
2505
2.78M
      (cache->stringObjs->number != 0))
2506
1.26M
  {
2507
1.26M
      xmlXPathObjectPtr ret;
2508
2509
1.26M
      ret = (xmlXPathObjectPtr)
2510
1.26M
    cache->stringObjs->items[--cache->stringObjs->number];
2511
2512
1.26M
      ret->type = XPATH_STRING;
2513
1.26M
      ret->stringval = xmlStrdup(BAD_CAST val);
2514
#ifdef XP_DEBUG_OBJ_USAGE
2515
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516
#endif
2517
1.26M
      return(ret);
2518
1.52M
  } else if ((cache->miscObjs != NULL) &&
2519
1.52M
      (cache->miscObjs->number != 0))
2520
1.28M
  {
2521
1.28M
      xmlXPathObjectPtr ret;
2522
2523
1.28M
      ret = (xmlXPathObjectPtr)
2524
1.28M
    cache->miscObjs->items[--cache->miscObjs->number];
2525
2526
1.28M
      ret->type = XPATH_STRING;
2527
1.28M
      ret->stringval = xmlStrdup(BAD_CAST val);
2528
#ifdef XP_DEBUG_OBJ_USAGE
2529
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2530
#endif
2531
1.28M
      return(ret);
2532
1.28M
  }
2533
2.78M
    }
2534
234k
    return(xmlXPathNewCString(val));
2535
2.78M
}
2536
2537
/**
2538
 * xmlXPathCacheNewString:
2539
 * @ctxt: the XPath context
2540
 * @val:  the xmlChar * value
2541
 *
2542
 * This is the cached version of xmlXPathNewString().
2543
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2544
 *
2545
 * Returns the created or reused object.
2546
 */
2547
static xmlXPathObjectPtr
2548
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2549
43.6M
{
2550
43.6M
    if ((ctxt != NULL) && (ctxt->cache)) {
2551
43.6M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2552
2553
43.6M
  if ((cache->stringObjs != NULL) &&
2554
43.6M
      (cache->stringObjs->number != 0))
2555
34.5M
  {
2556
34.5M
      xmlXPathObjectPtr ret;
2557
2558
34.5M
      ret = (xmlXPathObjectPtr)
2559
34.5M
    cache->stringObjs->items[--cache->stringObjs->number];
2560
34.5M
      ret->type = XPATH_STRING;
2561
34.5M
      if (val != NULL)
2562
34.4M
    ret->stringval = xmlStrdup(val);
2563
92.9k
      else
2564
92.9k
    ret->stringval = xmlStrdup((const xmlChar *)"");
2565
#ifdef XP_DEBUG_OBJ_USAGE
2566
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2567
#endif
2568
34.5M
      return(ret);
2569
34.5M
  } else if ((cache->miscObjs != NULL) &&
2570
9.09M
      (cache->miscObjs->number != 0))
2571
5.39M
  {
2572
5.39M
      xmlXPathObjectPtr ret;
2573
2574
5.39M
      ret = (xmlXPathObjectPtr)
2575
5.39M
    cache->miscObjs->items[--cache->miscObjs->number];
2576
2577
5.39M
      ret->type = XPATH_STRING;
2578
5.39M
      if (val != NULL)
2579
5.37M
    ret->stringval = xmlStrdup(val);
2580
17.6k
      else
2581
17.6k
    ret->stringval = xmlStrdup((const xmlChar *)"");
2582
#ifdef XP_DEBUG_OBJ_USAGE
2583
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2584
#endif
2585
5.39M
      return(ret);
2586
5.39M
  }
2587
43.6M
    }
2588
3.69M
    return(xmlXPathNewString(val));
2589
43.6M
}
2590
2591
/**
2592
 * xmlXPathCacheNewBoolean:
2593
 * @ctxt: the XPath context
2594
 * @val:  the boolean value
2595
 *
2596
 * This is the cached version of xmlXPathNewBoolean().
2597
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2598
 *
2599
 * Returns the created or reused object.
2600
 */
2601
static xmlXPathObjectPtr
2602
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2603
44.0M
{
2604
44.0M
    if ((ctxt != NULL) && (ctxt->cache)) {
2605
44.0M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607
44.0M
  if ((cache->booleanObjs != NULL) &&
2608
44.0M
      (cache->booleanObjs->number != 0))
2609
41.5M
  {
2610
41.5M
      xmlXPathObjectPtr ret;
2611
2612
41.5M
      ret = (xmlXPathObjectPtr)
2613
41.5M
    cache->booleanObjs->items[--cache->booleanObjs->number];
2614
41.5M
      ret->type = XPATH_BOOLEAN;
2615
41.5M
      ret->boolval = (val != 0);
2616
#ifdef XP_DEBUG_OBJ_USAGE
2617
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2618
#endif
2619
41.5M
      return(ret);
2620
41.5M
  } else if ((cache->miscObjs != NULL) &&
2621
2.58M
      (cache->miscObjs->number != 0))
2622
1.69M
  {
2623
1.69M
      xmlXPathObjectPtr ret;
2624
2625
1.69M
      ret = (xmlXPathObjectPtr)
2626
1.69M
    cache->miscObjs->items[--cache->miscObjs->number];
2627
2628
1.69M
      ret->type = XPATH_BOOLEAN;
2629
1.69M
      ret->boolval = (val != 0);
2630
#ifdef XP_DEBUG_OBJ_USAGE
2631
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2632
#endif
2633
1.69M
      return(ret);
2634
1.69M
  }
2635
44.0M
    }
2636
889k
    return(xmlXPathNewBoolean(val));
2637
44.0M
}
2638
2639
/**
2640
 * xmlXPathCacheNewFloat:
2641
 * @ctxt: the XPath context
2642
 * @val:  the double value
2643
 *
2644
 * This is the cached version of xmlXPathNewFloat().
2645
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2646
 *
2647
 * Returns the created or reused object.
2648
 */
2649
static xmlXPathObjectPtr
2650
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2651
64.5M
{
2652
64.5M
     if ((ctxt != NULL) && (ctxt->cache)) {
2653
64.5M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2654
2655
64.5M
  if ((cache->numberObjs != NULL) &&
2656
64.5M
      (cache->numberObjs->number != 0))
2657
56.6M
  {
2658
56.6M
      xmlXPathObjectPtr ret;
2659
2660
56.6M
      ret = (xmlXPathObjectPtr)
2661
56.6M
    cache->numberObjs->items[--cache->numberObjs->number];
2662
56.6M
      ret->type = XPATH_NUMBER;
2663
56.6M
      ret->floatval = val;
2664
#ifdef XP_DEBUG_OBJ_USAGE
2665
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2666
#endif
2667
56.6M
      return(ret);
2668
56.6M
  } else if ((cache->miscObjs != NULL) &&
2669
7.89M
      (cache->miscObjs->number != 0))
2670
4.97M
  {
2671
4.97M
      xmlXPathObjectPtr ret;
2672
2673
4.97M
      ret = (xmlXPathObjectPtr)
2674
4.97M
    cache->miscObjs->items[--cache->miscObjs->number];
2675
2676
4.97M
      ret->type = XPATH_NUMBER;
2677
4.97M
      ret->floatval = val;
2678
#ifdef XP_DEBUG_OBJ_USAGE
2679
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2680
#endif
2681
4.97M
      return(ret);
2682
4.97M
  }
2683
64.5M
    }
2684
2.92M
    return(xmlXPathNewFloat(val));
2685
64.5M
}
2686
2687
/**
2688
 * xmlXPathCacheConvertString:
2689
 * @ctxt: the XPath context
2690
 * @val:  an XPath object
2691
 *
2692
 * This is the cached version of xmlXPathConvertString().
2693
 * Converts an existing object to its string() equivalent
2694
 *
2695
 * Returns a created or reused object, the old one is freed (cached)
2696
 *         (or the operation is done directly on @val)
2697
 */
2698
2699
static xmlXPathObjectPtr
2700
19.0M
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2701
19.0M
    xmlChar *res = NULL;
2702
2703
19.0M
    if (val == NULL)
2704
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2705
2706
19.0M
    switch (val->type) {
2707
0
    case XPATH_UNDEFINED:
2708
#ifdef DEBUG_EXPR
2709
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2710
#endif
2711
0
  break;
2712
5.02M
    case XPATH_NODESET:
2713
5.02M
    case XPATH_XSLT_TREE:
2714
5.02M
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2715
5.02M
  break;
2716
13.3M
    case XPATH_STRING:
2717
13.3M
  return(val);
2718
188k
    case XPATH_BOOLEAN:
2719
188k
  res = xmlXPathCastBooleanToString(val->boolval);
2720
188k
  break;
2721
467k
    case XPATH_NUMBER:
2722
467k
  res = xmlXPathCastNumberToString(val->floatval);
2723
467k
  break;
2724
96
    case XPATH_USERS:
2725
#ifdef LIBXML_XPTR_LOCS_ENABLED
2726
    case XPATH_POINT:
2727
    case XPATH_RANGE:
2728
    case XPATH_LOCATIONSET:
2729
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2730
96
  TODO;
2731
96
  break;
2732
19.0M
    }
2733
5.68M
    xmlXPathReleaseObject(ctxt, val);
2734
5.68M
    if (res == NULL)
2735
96
  return(xmlXPathCacheNewCString(ctxt, ""));
2736
5.68M
    return(xmlXPathCacheWrapString(ctxt, res));
2737
5.68M
}
2738
2739
/**
2740
 * xmlXPathCacheObjectCopy:
2741
 * @ctxt: the XPath context
2742
 * @val:  the original object
2743
 *
2744
 * This is the cached version of xmlXPathObjectCopy().
2745
 * Acquire a copy of a given object
2746
 *
2747
 * Returns a created or reused created object.
2748
 */
2749
static xmlXPathObjectPtr
2750
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2751
55.8M
{
2752
55.8M
    if (val == NULL)
2753
14.8k
  return(NULL);
2754
2755
55.8M
    if (XP_HAS_CACHE(ctxt)) {
2756
55.8M
  switch (val->type) {
2757
0
      case XPATH_NODESET:
2758
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2759
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2760
35.5M
      case XPATH_STRING:
2761
35.5M
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2762
0
      case XPATH_BOOLEAN:
2763
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2764
20.2M
      case XPATH_NUMBER:
2765
20.2M
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2766
0
      default:
2767
0
    break;
2768
55.8M
  }
2769
55.8M
    }
2770
456
    return(xmlXPathObjectCopy(val));
2771
55.8M
}
2772
2773
/**
2774
 * xmlXPathCacheConvertBoolean:
2775
 * @ctxt: the XPath context
2776
 * @val:  an XPath object
2777
 *
2778
 * This is the cached version of xmlXPathConvertBoolean().
2779
 * Converts an existing object to its boolean() equivalent
2780
 *
2781
 * Returns a created or reused object, the old one is freed (or the operation
2782
 *         is done directly on @val)
2783
 */
2784
static xmlXPathObjectPtr
2785
7.66M
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2786
7.66M
    xmlXPathObjectPtr ret;
2787
2788
7.66M
    if (val == NULL)
2789
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2790
7.66M
    if (val->type == XPATH_BOOLEAN)
2791
1.58M
  return(val);
2792
6.07M
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2793
6.07M
    xmlXPathReleaseObject(ctxt, val);
2794
6.07M
    return(ret);
2795
7.66M
}
2796
2797
/**
2798
 * xmlXPathCacheConvertNumber:
2799
 * @ctxt: the XPath context
2800
 * @val:  an XPath object
2801
 *
2802
 * This is the cached version of xmlXPathConvertNumber().
2803
 * Converts an existing object to its number() equivalent
2804
 *
2805
 * Returns a created or reused object, the old one is freed (or the operation
2806
 *         is done directly on @val)
2807
 */
2808
static xmlXPathObjectPtr
2809
35.4M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2810
35.4M
    xmlXPathObjectPtr ret;
2811
2812
35.4M
    if (val == NULL)
2813
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2814
35.4M
    if (val->type == XPATH_NUMBER)
2815
6.58k
  return(val);
2816
35.4M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2817
35.4M
    xmlXPathReleaseObject(ctxt, val);
2818
35.4M
    return(ret);
2819
35.4M
}
2820
2821
/************************************************************************
2822
 *                  *
2823
 *    Parser stacks related functions and macros    *
2824
 *                  *
2825
 ************************************************************************/
2826
2827
/**
2828
 * xmlXPathSetFrame:
2829
 * @ctxt: an XPath parser context
2830
 *
2831
 * Set the callee evaluation frame
2832
 *
2833
 * Returns the previous frame value to be restored once done
2834
 */
2835
static int
2836
49.3M
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2837
49.3M
    int ret;
2838
2839
49.3M
    if (ctxt == NULL)
2840
0
        return(0);
2841
49.3M
    ret = ctxt->valueFrame;
2842
49.3M
    ctxt->valueFrame = ctxt->valueNr;
2843
49.3M
    return(ret);
2844
49.3M
}
2845
2846
/**
2847
 * xmlXPathPopFrame:
2848
 * @ctxt: an XPath parser context
2849
 * @frame: the previous frame value
2850
 *
2851
 * Remove the callee evaluation frame
2852
 */
2853
static void
2854
48.4M
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2855
48.4M
    if (ctxt == NULL)
2856
0
        return;
2857
48.4M
    if (ctxt->valueNr < ctxt->valueFrame) {
2858
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859
0
    }
2860
48.4M
    ctxt->valueFrame = frame;
2861
48.4M
}
2862
2863
/**
2864
 * valuePop:
2865
 * @ctxt: an XPath evaluation context
2866
 *
2867
 * Pops the top XPath object from the value stack
2868
 *
2869
 * Returns the XPath object just removed
2870
 */
2871
xmlXPathObjectPtr
2872
valuePop(xmlXPathParserContextPtr ctxt)
2873
437M
{
2874
437M
    xmlXPathObjectPtr ret;
2875
2876
437M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2877
108k
        return (NULL);
2878
2879
437M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2880
9
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2881
9
        return (NULL);
2882
9
    }
2883
2884
437M
    ctxt->valueNr--;
2885
437M
    if (ctxt->valueNr > 0)
2886
367M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2887
70.1M
    else
2888
70.1M
        ctxt->value = NULL;
2889
437M
    ret = ctxt->valueTab[ctxt->valueNr];
2890
437M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2891
437M
    return (ret);
2892
437M
}
2893
/**
2894
 * valuePush:
2895
 * @ctxt:  an XPath evaluation context
2896
 * @value:  the XPath object
2897
 *
2898
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2899
 * a memory error is recorded in the parser context.
2900
 *
2901
 * Returns the number of items on the value stack, or -1 in case of error.
2902
 */
2903
int
2904
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2905
442M
{
2906
442M
    if (ctxt == NULL) return(-1);
2907
442M
    if (value == NULL) {
2908
        /*
2909
         * A NULL value typically indicates that a memory allocation failed,
2910
         * so we set ctxt->error here to propagate the error.
2911
         */
2912
910
  ctxt->error = XPATH_MEMORY_ERROR;
2913
910
        return(-1);
2914
910
    }
2915
442M
    if (ctxt->valueNr >= ctxt->valueMax) {
2916
10.9k
        xmlXPathObjectPtr *tmp;
2917
2918
10.9k
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2919
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2920
0
            return (-1);
2921
0
        }
2922
10.9k
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2923
10.9k
                                             2 * ctxt->valueMax *
2924
10.9k
                                             sizeof(ctxt->valueTab[0]));
2925
10.9k
        if (tmp == NULL) {
2926
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2927
0
            return (-1);
2928
0
        }
2929
10.9k
        ctxt->valueMax *= 2;
2930
10.9k
  ctxt->valueTab = tmp;
2931
10.9k
    }
2932
442M
    ctxt->valueTab[ctxt->valueNr] = value;
2933
442M
    ctxt->value = value;
2934
442M
    return (ctxt->valueNr++);
2935
442M
}
2936
2937
/**
2938
 * xmlXPathPopBoolean:
2939
 * @ctxt:  an XPath parser context
2940
 *
2941
 * Pops a boolean from the stack, handling conversion if needed.
2942
 * Check error with #xmlXPathCheckError.
2943
 *
2944
 * Returns the boolean
2945
 */
2946
int
2947
727k
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2948
727k
    xmlXPathObjectPtr obj;
2949
727k
    int ret;
2950
2951
727k
    obj = valuePop(ctxt);
2952
727k
    if (obj == NULL) {
2953
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2954
0
  return(0);
2955
0
    }
2956
727k
    if (obj->type != XPATH_BOOLEAN)
2957
530k
  ret = xmlXPathCastToBoolean(obj);
2958
196k
    else
2959
196k
        ret = obj->boolval;
2960
727k
    xmlXPathReleaseObject(ctxt->context, obj);
2961
727k
    return(ret);
2962
727k
}
2963
2964
/**
2965
 * xmlXPathPopNumber:
2966
 * @ctxt:  an XPath parser context
2967
 *
2968
 * Pops a number from the stack, handling conversion if needed.
2969
 * Check error with #xmlXPathCheckError.
2970
 *
2971
 * Returns the number
2972
 */
2973
double
2974
683k
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2975
683k
    xmlXPathObjectPtr obj;
2976
683k
    double ret;
2977
2978
683k
    obj = valuePop(ctxt);
2979
683k
    if (obj == NULL) {
2980
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2981
0
  return(0);
2982
0
    }
2983
683k
    if (obj->type != XPATH_NUMBER)
2984
277k
  ret = xmlXPathCastToNumber(obj);
2985
405k
    else
2986
405k
        ret = obj->floatval;
2987
683k
    xmlXPathReleaseObject(ctxt->context, obj);
2988
683k
    return(ret);
2989
683k
}
2990
2991
/**
2992
 * xmlXPathPopString:
2993
 * @ctxt:  an XPath parser context
2994
 *
2995
 * Pops a string from the stack, handling conversion if needed.
2996
 * Check error with #xmlXPathCheckError.
2997
 *
2998
 * Returns the string
2999
 */
3000
xmlChar *
3001
20.8M
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
3002
20.8M
    xmlXPathObjectPtr obj;
3003
20.8M
    xmlChar * ret;
3004
3005
20.8M
    obj = valuePop(ctxt);
3006
20.8M
    if (obj == NULL) {
3007
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3008
0
  return(NULL);
3009
0
    }
3010
20.8M
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3011
    /* TODO: needs refactoring somewhere else */
3012
20.8M
    if (obj->stringval == ret)
3013
0
  obj->stringval = NULL;
3014
20.8M
    xmlXPathReleaseObject(ctxt->context, obj);
3015
20.8M
    return(ret);
3016
20.8M
}
3017
3018
/**
3019
 * xmlXPathPopNodeSet:
3020
 * @ctxt:  an XPath parser context
3021
 *
3022
 * Pops a node-set from the stack, handling conversion if needed.
3023
 * Check error with #xmlXPathCheckError.
3024
 *
3025
 * Returns the node-set
3026
 */
3027
xmlNodeSetPtr
3028
13.4M
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3029
13.4M
    xmlXPathObjectPtr obj;
3030
13.4M
    xmlNodeSetPtr ret;
3031
3032
13.4M
    if (ctxt == NULL) return(NULL);
3033
13.4M
    if (ctxt->value == NULL) {
3034
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3035
0
  return(NULL);
3036
0
    }
3037
13.4M
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3038
200k
  xmlXPathSetTypeError(ctxt);
3039
200k
  return(NULL);
3040
200k
    }
3041
13.2M
    obj = valuePop(ctxt);
3042
13.2M
    ret = obj->nodesetval;
3043
#if 0
3044
    /* to fix memory leak of not clearing obj->user */
3045
    if (obj->boolval && obj->user != NULL)
3046
        xmlFreeNodeList((xmlNodePtr) obj->user);
3047
#endif
3048
13.2M
    obj->nodesetval = NULL;
3049
13.2M
    xmlXPathReleaseObject(ctxt->context, obj);
3050
13.2M
    return(ret);
3051
13.4M
}
3052
3053
/**
3054
 * xmlXPathPopExternal:
3055
 * @ctxt:  an XPath parser context
3056
 *
3057
 * Pops an external object from the stack, handling conversion if needed.
3058
 * Check error with #xmlXPathCheckError.
3059
 *
3060
 * Returns the object
3061
 */
3062
void *
3063
10.6k
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3064
10.6k
    xmlXPathObjectPtr obj;
3065
10.6k
    void * ret;
3066
3067
10.6k
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3068
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3069
0
  return(NULL);
3070
0
    }
3071
10.6k
    if (ctxt->value->type != XPATH_USERS) {
3072
0
  xmlXPathSetTypeError(ctxt);
3073
0
  return(NULL);
3074
0
    }
3075
10.6k
    obj = valuePop(ctxt);
3076
10.6k
    ret = obj->user;
3077
10.6k
    obj->user = NULL;
3078
10.6k
    xmlXPathReleaseObject(ctxt->context, obj);
3079
10.6k
    return(ret);
3080
10.6k
}
3081
3082
/*
3083
 * Macros for accessing the content. Those should be used only by the parser,
3084
 * and not exported.
3085
 *
3086
 * Dirty macros, i.e. one need to make assumption on the context to use them
3087
 *
3088
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3089
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3090
 *           in ISO-Latin or UTF-8.
3091
 *           This should be used internally by the parser
3092
 *           only to compare to ASCII values otherwise it would break when
3093
 *           running with UTF-8 encoding.
3094
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3095
 *           to compare on ASCII based substring.
3096
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3097
 *           strings within the parser.
3098
 *   CURRENT Returns the current char value, with the full decoding of
3099
 *           UTF-8 if we are using this mode. It returns an int.
3100
 *   NEXT    Skip to the next character, this does the proper decoding
3101
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3102
 *           It returns the pointer to the current xmlChar.
3103
 */
3104
3105
930M
#define CUR (*ctxt->cur)
3106
4.58M
#define SKIP(val) ctxt->cur += (val)
3107
104M
#define NXT(val) ctxt->cur[(val)]
3108
944k
#define CUR_PTR ctxt->cur
3109
179M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3110
3111
#define COPY_BUF(l,b,i,v)                                              \
3112
71.4M
    if (l == 1) b[i++] = v;                                            \
3113
71.4M
    else i += xmlCopyChar(l,&b[i],v)
3114
3115
149M
#define NEXTL(l)  ctxt->cur += l
3116
3117
#define SKIP_BLANKS             \
3118
487M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3119
3120
#define CURRENT (*ctxt->cur)
3121
405M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3122
3123
3124
#ifndef DBL_DIG
3125
#define DBL_DIG 16
3126
#endif
3127
#ifndef DBL_EPSILON
3128
#define DBL_EPSILON 1E-9
3129
#endif
3130
3131
82.9k
#define UPPER_DOUBLE 1E9
3132
51.1k
#define LOWER_DOUBLE 1E-5
3133
#define LOWER_DOUBLE_EXP 5
3134
3135
#define INTEGER_DIGITS DBL_DIG
3136
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3137
34.1k
#define EXPONENT_DIGITS (3 + 2)
3138
3139
/**
3140
 * xmlXPathFormatNumber:
3141
 * @number:     number to format
3142
 * @buffer:     output buffer
3143
 * @buffersize: size of output buffer
3144
 *
3145
 * Convert the number into a string representation.
3146
 */
3147
static void
3148
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3149
684k
{
3150
684k
    switch (xmlXPathIsInf(number)) {
3151
0
    case 1:
3152
0
  if (buffersize > (int)sizeof("Infinity"))
3153
0
      snprintf(buffer, buffersize, "Infinity");
3154
0
  break;
3155
0
    case -1:
3156
0
  if (buffersize > (int)sizeof("-Infinity"))
3157
0
      snprintf(buffer, buffersize, "-Infinity");
3158
0
  break;
3159
684k
    default:
3160
684k
  if (xmlXPathIsNaN(number)) {
3161
0
      if (buffersize > (int)sizeof("NaN"))
3162
0
    snprintf(buffer, buffersize, "NaN");
3163
684k
  } else if (number == 0) {
3164
            /* Omit sign for negative zero. */
3165
0
      snprintf(buffer, buffersize, "0");
3166
684k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3167
684k
                   (number == (int) number)) {
3168
601k
      char work[30];
3169
601k
      char *ptr, *cur;
3170
601k
      int value = (int) number;
3171
3172
601k
            ptr = &buffer[0];
3173
601k
      if (value == 0) {
3174
0
    *ptr++ = '0';
3175
601k
      } else {
3176
601k
    snprintf(work, 29, "%d", value);
3177
601k
    cur = &work[0];
3178
1.38M
    while ((*cur) && (ptr - buffer < buffersize)) {
3179
782k
        *ptr++ = *cur++;
3180
782k
    }
3181
601k
      }
3182
601k
      if (ptr - buffer < buffersize) {
3183
601k
    *ptr = 0;
3184
601k
      } else if (buffersize > 0) {
3185
0
    ptr--;
3186
0
    *ptr = 0;
3187
0
      }
3188
601k
  } else {
3189
      /*
3190
        For the dimension of work,
3191
            DBL_DIG is number of significant digits
3192
      EXPONENT is only needed for "scientific notation"
3193
            3 is sign, decimal point, and terminating zero
3194
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3195
        Note that this dimension is slightly (a few characters)
3196
        larger than actually necessary.
3197
      */
3198
82.9k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3199
82.9k
      int integer_place, fraction_place;
3200
82.9k
      char *ptr;
3201
82.9k
      char *after_fraction;
3202
82.9k
      double absolute_value;
3203
82.9k
      int size;
3204
3205
82.9k
      absolute_value = fabs(number);
3206
3207
      /*
3208
       * First choose format - scientific or regular floating point.
3209
       * In either case, result is in work, and after_fraction points
3210
       * just past the fractional part.
3211
      */
3212
82.9k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3213
82.9k
      (absolute_value < LOWER_DOUBLE)) &&
3214
82.9k
     (absolute_value != 0.0) ) {
3215
    /* Use scientific notation */
3216
34.1k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3217
34.1k
    fraction_place = DBL_DIG - 1;
3218
34.1k
    size = snprintf(work, sizeof(work),"%*.*e",
3219
34.1k
       integer_place, fraction_place, number);
3220
171k
    while ((size > 0) && (work[size] != 'e')) size--;
3221
3222
34.1k
      }
3223
48.7k
      else {
3224
    /* Use regular notation */
3225
48.7k
    if (absolute_value > 0.0) {
3226
48.7k
        integer_place = (int)log10(absolute_value);
3227
48.7k
        if (integer_place > 0)
3228
17.2k
            fraction_place = DBL_DIG - integer_place - 1;
3229
31.5k
        else
3230
31.5k
            fraction_place = DBL_DIG - integer_place;
3231
48.7k
    } else {
3232
0
        fraction_place = 1;
3233
0
    }
3234
48.7k
    size = snprintf(work, sizeof(work), "%0.*f",
3235
48.7k
        fraction_place, number);
3236
48.7k
      }
3237
3238
      /* Remove leading spaces sometimes inserted by snprintf */
3239
112k
      while (work[0] == ' ') {
3240
625k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3241
29.8k
    size--;
3242
29.8k
      }
3243
3244
      /* Remove fractional trailing zeroes */
3245
82.9k
      after_fraction = work + size;
3246
82.9k
      ptr = after_fraction;
3247
595k
      while (*(--ptr) == '0')
3248
512k
    ;
3249
82.9k
      if (*ptr != '.')
3250
74.9k
          ptr++;
3251
219k
      while ((*ptr++ = *after_fraction++) != 0);
3252
3253
      /* Finally copy result back to caller */
3254
82.9k
      size = strlen(work) + 1;
3255
82.9k
      if (size > buffersize) {
3256
0
    work[buffersize - 1] = 0;
3257
0
    size = buffersize;
3258
0
      }
3259
82.9k
      memmove(buffer, work, size);
3260
82.9k
  }
3261
684k
  break;
3262
684k
    }
3263
684k
}
3264
3265
3266
/************************************************************************
3267
 *                  *
3268
 *      Routines to handle NodeSets     *
3269
 *                  *
3270
 ************************************************************************/
3271
3272
/**
3273
 * xmlXPathOrderDocElems:
3274
 * @doc:  an input document
3275
 *
3276
 * Call this routine to speed up XPath computation on static documents.
3277
 * This stamps all the element nodes with the document order
3278
 * Like for line information, the order is kept in the element->content
3279
 * field, the value stored is actually - the node number (starting at -1)
3280
 * to be able to differentiate from line numbers.
3281
 *
3282
 * Returns the number of elements found in the document or -1 in case
3283
 *    of error.
3284
 */
3285
long
3286
3.69k
xmlXPathOrderDocElems(xmlDocPtr doc) {
3287
3.69k
    ptrdiff_t count = 0;
3288
3.69k
    xmlNodePtr cur;
3289
3290
3.69k
    if (doc == NULL)
3291
0
  return(-1);
3292
3.69k
    cur = doc->children;
3293
147k
    while (cur != NULL) {
3294
144k
  if (cur->type == XML_ELEMENT_NODE) {
3295
44.3k
      cur->content = (void *) (-(++count));
3296
44.3k
      if (cur->children != NULL) {
3297
33.2k
    cur = cur->children;
3298
33.2k
    continue;
3299
33.2k
      }
3300
44.3k
  }
3301
110k
  if (cur->next != NULL) {
3302
77.6k
      cur = cur->next;
3303
77.6k
      continue;
3304
77.6k
  }
3305
36.9k
  do {
3306
36.9k
      cur = cur->parent;
3307
36.9k
      if (cur == NULL)
3308
0
    break;
3309
36.9k
      if (cur == (xmlNodePtr) doc) {
3310
3.69k
    cur = NULL;
3311
3.69k
    break;
3312
3.69k
      }
3313
33.2k
      if (cur->next != NULL) {
3314
29.5k
    cur = cur->next;
3315
29.5k
    break;
3316
29.5k
      }
3317
33.2k
  } while (cur != NULL);
3318
33.2k
    }
3319
3.69k
    return(count);
3320
3.69k
}
3321
3322
/**
3323
 * xmlXPathCmpNodes:
3324
 * @node1:  the first node
3325
 * @node2:  the second node
3326
 *
3327
 * Compare two nodes w.r.t document order
3328
 *
3329
 * Returns -2 in case of error 1 if first point < second point, 0 if
3330
 *         it's the same node, -1 otherwise
3331
 */
3332
int
3333
3.11M
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3334
3.11M
    int depth1, depth2;
3335
3.11M
    int attr1 = 0, attr2 = 0;
3336
3.11M
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3337
3.11M
    xmlNodePtr cur, root;
3338
3339
3.11M
    if ((node1 == NULL) || (node2 == NULL))
3340
0
  return(-2);
3341
    /*
3342
     * a couple of optimizations which will avoid computations in most cases
3343
     */
3344
3.11M
    if (node1 == node2)    /* trivial case */
3345
0
  return(0);
3346
3.11M
    if (node1->type == XML_ATTRIBUTE_NODE) {
3347
33.3k
  attr1 = 1;
3348
33.3k
  attrNode1 = node1;
3349
33.3k
  node1 = node1->parent;
3350
33.3k
    }
3351
3.11M
    if (node2->type == XML_ATTRIBUTE_NODE) {
3352
32.0k
  attr2 = 1;
3353
32.0k
  attrNode2 = node2;
3354
32.0k
  node2 = node2->parent;
3355
32.0k
    }
3356
3.11M
    if (node1 == node2) {
3357
6.44k
  if (attr1 == attr2) {
3358
      /* not required, but we keep attributes in order */
3359
4.84k
      if (attr1 != 0) {
3360
4.84k
          cur = attrNode2->prev;
3361
4.84k
    while (cur != NULL) {
3362
4.84k
        if (cur == attrNode1)
3363
4.84k
            return (1);
3364
0
        cur = cur->prev;
3365
0
    }
3366
0
    return (-1);
3367
4.84k
      }
3368
0
      return(0);
3369
4.84k
  }
3370
1.59k
  if (attr2 == 1)
3371
1.59k
      return(1);
3372
0
  return(-1);
3373
1.59k
    }
3374
3.10M
    if ((node1->type == XML_NAMESPACE_DECL) ||
3375
3.10M
        (node2->type == XML_NAMESPACE_DECL))
3376
118k
  return(1);
3377
2.98M
    if (node1 == node2->prev)
3378
32.2k
  return(1);
3379
2.95M
    if (node1 == node2->next)
3380
193
  return(-1);
3381
3382
    /*
3383
     * Speedup using document order if available.
3384
     */
3385
2.95M
    if ((node1->type == XML_ELEMENT_NODE) &&
3386
2.95M
  (node2->type == XML_ELEMENT_NODE) &&
3387
2.95M
  (0 > (ptrdiff_t) node1->content) &&
3388
2.95M
  (0 > (ptrdiff_t) node2->content) &&
3389
2.95M
  (node1->doc == node2->doc)) {
3390
69.4k
  ptrdiff_t l1, l2;
3391
3392
69.4k
  l1 = -((ptrdiff_t) node1->content);
3393
69.4k
  l2 = -((ptrdiff_t) node2->content);
3394
69.4k
  if (l1 < l2)
3395
69.2k
      return(1);
3396
212
  if (l1 > l2)
3397
212
      return(-1);
3398
212
    }
3399
3400
    /*
3401
     * compute depth to root
3402
     */
3403
6.67M
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3404
4.14M
  if (cur->parent == node1)
3405
363k
      return(1);
3406
3.78M
  depth2++;
3407
3.78M
    }
3408
2.52M
    root = cur;
3409
5.51M
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3410
2.99M
  if (cur->parent == node2)
3411
2.58k
      return(-1);
3412
2.99M
  depth1++;
3413
2.99M
    }
3414
    /*
3415
     * Distinct document (or distinct entities :-( ) case.
3416
     */
3417
2.52M
    if (root != cur) {
3418
389k
  return(-2);
3419
389k
    }
3420
    /*
3421
     * get the nearest common ancestor.
3422
     */
3423
2.16M
    while (depth1 > depth2) {
3424
36.9k
  depth1--;
3425
36.9k
  node1 = node1->parent;
3426
36.9k
    }
3427
2.67M
    while (depth2 > depth1) {
3428
540k
  depth2--;
3429
540k
  node2 = node2->parent;
3430
540k
    }
3431
2.22M
    while (node1->parent != node2->parent) {
3432
90.2k
  node1 = node1->parent;
3433
90.2k
  node2 = node2->parent;
3434
  /* should not happen but just in case ... */
3435
90.2k
  if ((node1 == NULL) || (node2 == NULL))
3436
0
      return(-2);
3437
90.2k
    }
3438
    /*
3439
     * Find who's first.
3440
     */
3441
2.13M
    if (node1 == node2->prev)
3442
215k
  return(1);
3443
1.91M
    if (node1 == node2->next)
3444
575
  return(-1);
3445
    /*
3446
     * Speedup using document order if available.
3447
     */
3448
1.91M
    if ((node1->type == XML_ELEMENT_NODE) &&
3449
1.91M
  (node2->type == XML_ELEMENT_NODE) &&
3450
1.91M
  (0 > (ptrdiff_t) node1->content) &&
3451
1.91M
  (0 > (ptrdiff_t) node2->content) &&
3452
1.91M
  (node1->doc == node2->doc)) {
3453
12.0k
  ptrdiff_t l1, l2;
3454
3455
12.0k
  l1 = -((ptrdiff_t) node1->content);
3456
12.0k
  l2 = -((ptrdiff_t) node2->content);
3457
12.0k
  if (l1 < l2)
3458
11.9k
      return(1);
3459
72
  if (l1 > l2)
3460
72
      return(-1);
3461
72
    }
3462
3463
102M
    for (cur = node1->next;cur != NULL;cur = cur->next)
3464
102M
  if (cur == node2)
3465
1.90M
      return(1);
3466
726
    return(-1); /* assume there is no sibling list corruption */
3467
1.90M
}
3468
3469
/**
3470
 * xmlXPathNodeSetSort:
3471
 * @set:  the node set
3472
 *
3473
 * Sort the node set in document order
3474
 */
3475
void
3476
9.18M
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3477
#ifndef WITH_TIM_SORT
3478
    int i, j, incr, len;
3479
    xmlNodePtr tmp;
3480
#endif
3481
3482
9.18M
    if (set == NULL)
3483
0
  return;
3484
3485
#ifndef WITH_TIM_SORT
3486
    /*
3487
     * Use the old Shell's sort implementation to sort the node-set
3488
     * Timsort ought to be quite faster
3489
     */
3490
    len = set->nodeNr;
3491
    for (incr = len / 2; incr > 0; incr /= 2) {
3492
  for (i = incr; i < len; i++) {
3493
      j = i - incr;
3494
      while (j >= 0) {
3495
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3496
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3497
      set->nodeTab[j + incr]) == -1)
3498
#else
3499
    if (xmlXPathCmpNodes(set->nodeTab[j],
3500
      set->nodeTab[j + incr]) == -1)
3501
#endif
3502
    {
3503
        tmp = set->nodeTab[j];
3504
        set->nodeTab[j] = set->nodeTab[j + incr];
3505
        set->nodeTab[j + incr] = tmp;
3506
        j -= incr;
3507
    } else
3508
        break;
3509
      }
3510
  }
3511
    }
3512
#else /* WITH_TIM_SORT */
3513
9.18M
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3514
9.18M
#endif /* WITH_TIM_SORT */
3515
9.18M
}
3516
3517
133M
#define XML_NODESET_DEFAULT 10
3518
/**
3519
 * xmlXPathNodeSetDupNs:
3520
 * @node:  the parent node of the namespace XPath node
3521
 * @ns:  the libxml namespace declaration node.
3522
 *
3523
 * Namespace node in libxml don't match the XPath semantic. In a node set
3524
 * the namespace nodes are duplicated and the next pointer is set to the
3525
 * parent node in the XPath semantic.
3526
 *
3527
 * Returns the newly created object.
3528
 */
3529
static xmlNodePtr
3530
13.0M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3531
13.0M
    xmlNsPtr cur;
3532
3533
13.0M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3534
0
  return(NULL);
3535
13.0M
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3536
0
  return((xmlNodePtr) ns);
3537
3538
    /*
3539
     * Allocate a new Namespace and fill the fields.
3540
     */
3541
13.0M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3542
13.0M
    if (cur == NULL) {
3543
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3544
0
  return(NULL);
3545
0
    }
3546
13.0M
    memset(cur, 0, sizeof(xmlNs));
3547
13.0M
    cur->type = XML_NAMESPACE_DECL;
3548
13.0M
    if (ns->href != NULL)
3549
13.0M
  cur->href = xmlStrdup(ns->href);
3550
13.0M
    if (ns->prefix != NULL)
3551
13.0M
  cur->prefix = xmlStrdup(ns->prefix);
3552
13.0M
    cur->next = (xmlNsPtr) node;
3553
13.0M
    return((xmlNodePtr) cur);
3554
13.0M
}
3555
3556
/**
3557
 * xmlXPathNodeSetFreeNs:
3558
 * @ns:  the XPath namespace node found in a nodeset.
3559
 *
3560
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3561
 * the namespace nodes are duplicated and the next pointer is set to the
3562
 * parent node in the XPath semantic. Check if such a node needs to be freed
3563
 */
3564
void
3565
13.0M
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3566
13.0M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3567
0
  return;
3568
3569
13.0M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3570
13.0M
  if (ns->href != NULL)
3571
13.0M
      xmlFree((xmlChar *)ns->href);
3572
13.0M
  if (ns->prefix != NULL)
3573
13.0M
      xmlFree((xmlChar *)ns->prefix);
3574
13.0M
  xmlFree(ns);
3575
13.0M
    }
3576
13.0M
}
3577
3578
/**
3579
 * xmlXPathNodeSetCreate:
3580
 * @val:  an initial xmlNodePtr, or NULL
3581
 *
3582
 * Create a new xmlNodeSetPtr of type double and of value @val
3583
 *
3584
 * Returns the newly created object.
3585
 */
3586
xmlNodeSetPtr
3587
118M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3588
118M
    xmlNodeSetPtr ret;
3589
3590
118M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3591
118M
    if (ret == NULL) {
3592
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
  return(NULL);
3594
0
    }
3595
118M
    memset(ret, 0 , sizeof(xmlNodeSet));
3596
118M
    if (val != NULL) {
3597
7.31M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3598
7.31M
               sizeof(xmlNodePtr));
3599
7.31M
  if (ret->nodeTab == NULL) {
3600
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3601
0
      xmlFree(ret);
3602
0
      return(NULL);
3603
0
  }
3604
7.31M
  memset(ret->nodeTab, 0 ,
3605
7.31M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3606
7.31M
        ret->nodeMax = XML_NODESET_DEFAULT;
3607
7.31M
  if (val->type == XML_NAMESPACE_DECL) {
3608
287k
      xmlNsPtr ns = (xmlNsPtr) val;
3609
3610
            /* TODO: Check memory error. */
3611
287k
      ret->nodeTab[ret->nodeNr++] =
3612
287k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3613
287k
  } else
3614
7.02M
      ret->nodeTab[ret->nodeNr++] = val;
3615
7.31M
    }
3616
118M
    return(ret);
3617
118M
}
3618
3619
/**
3620
 * xmlXPathNodeSetContains:
3621
 * @cur:  the node-set
3622
 * @val:  the node
3623
 *
3624
 * checks whether @cur contains @val
3625
 *
3626
 * Returns true (1) if @cur contains @val, false (0) otherwise
3627
 */
3628
int
3629
702k
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3630
702k
    int i;
3631
3632
702k
    if ((cur == NULL) || (val == NULL)) return(0);
3633
702k
    if (val->type == XML_NAMESPACE_DECL) {
3634
5.51M
  for (i = 0; i < cur->nodeNr; i++) {
3635
5.43M
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3636
55.4k
    xmlNsPtr ns1, ns2;
3637
3638
55.4k
    ns1 = (xmlNsPtr) val;
3639
55.4k
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3640
55.4k
    if (ns1 == ns2)
3641
0
        return(1);
3642
55.4k
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3643
55.4k
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3644
2.38k
        return(1);
3645
55.4k
      }
3646
5.43M
  }
3647
621k
    } else {
3648
11.8M
  for (i = 0; i < cur->nodeNr; i++) {
3649
11.4M
      if (cur->nodeTab[i] == val)
3650
190k
    return(1);
3651
11.4M
  }
3652
621k
    }
3653
509k
    return(0);
3654
702k
}
3655
3656
/**
3657
 * xmlXPathNodeSetAddNs:
3658
 * @cur:  the initial node set
3659
 * @node:  the hosting node
3660
 * @ns:  a the namespace node
3661
 *
3662
 * add a new namespace node to an existing NodeSet
3663
 *
3664
 * Returns 0 in case of success and -1 in case of error
3665
 */
3666
int
3667
5.59M
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3668
5.59M
    int i;
3669
3670
3671
5.59M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3672
5.59M
        (ns->type != XML_NAMESPACE_DECL) ||
3673
5.59M
  (node->type != XML_ELEMENT_NODE))
3674
0
  return(-1);
3675
3676
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3677
    /*
3678
     * prevent duplicates
3679
     */
3680
7.69M
    for (i = 0;i < cur->nodeNr;i++) {
3681
2.10M
        if ((cur->nodeTab[i] != NULL) &&
3682
2.10M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3683
2.10M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3684
2.10M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3685
0
      return(0);
3686
2.10M
    }
3687
3688
    /*
3689
     * grow the nodeTab if needed
3690
     */
3691
5.59M
    if (cur->nodeMax == 0) {
3692
494k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3693
494k
               sizeof(xmlNodePtr));
3694
494k
  if (cur->nodeTab == NULL) {
3695
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3696
0
      return(-1);
3697
0
  }
3698
494k
  memset(cur->nodeTab, 0 ,
3699
494k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3700
494k
        cur->nodeMax = XML_NODESET_DEFAULT;
3701
5.09M
    } else if (cur->nodeNr == cur->nodeMax) {
3702
0
        xmlNodePtr *temp;
3703
3704
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3705
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3706
0
            return(-1);
3707
0
        }
3708
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3709
0
              sizeof(xmlNodePtr));
3710
0
  if (temp == NULL) {
3711
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3712
0
      return(-1);
3713
0
  }
3714
0
        cur->nodeMax *= 2;
3715
0
  cur->nodeTab = temp;
3716
0
    }
3717
    /* TODO: Check memory error. */
3718
5.59M
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3719
5.59M
    return(0);
3720
5.59M
}
3721
3722
/**
3723
 * xmlXPathNodeSetAdd:
3724
 * @cur:  the initial node set
3725
 * @val:  a new xmlNodePtr
3726
 *
3727
 * add a new xmlNodePtr to an existing NodeSet
3728
 *
3729
 * Returns 0 in case of success, and -1 in case of error
3730
 */
3731
int
3732
7.35M
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3733
7.35M
    int i;
3734
3735
7.35M
    if ((cur == NULL) || (val == NULL)) return(-1);
3736
3737
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3738
    /*
3739
     * prevent duplicates
3740
     */
3741
605M
    for (i = 0;i < cur->nodeNr;i++)
3742
600M
        if (cur->nodeTab[i] == val) return(0);
3743
3744
    /*
3745
     * grow the nodeTab if needed
3746
     */
3747
5.25M
    if (cur->nodeMax == 0) {
3748
273k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3749
273k
               sizeof(xmlNodePtr));
3750
273k
  if (cur->nodeTab == NULL) {
3751
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3752
0
      return(-1);
3753
0
  }
3754
273k
  memset(cur->nodeTab, 0 ,
3755
273k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3756
273k
        cur->nodeMax = XML_NODESET_DEFAULT;
3757
4.98M
    } else if (cur->nodeNr == cur->nodeMax) {
3758
182k
        xmlNodePtr *temp;
3759
3760
182k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3761
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3762
0
            return(-1);
3763
0
        }
3764
182k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3765
182k
              sizeof(xmlNodePtr));
3766
182k
  if (temp == NULL) {
3767
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3768
0
      return(-1);
3769
0
  }
3770
182k
        cur->nodeMax *= 2;
3771
182k
  cur->nodeTab = temp;
3772
182k
    }
3773
5.25M
    if (val->type == XML_NAMESPACE_DECL) {
3774
690k
  xmlNsPtr ns = (xmlNsPtr) val;
3775
3776
        /* TODO: Check memory error. */
3777
690k
  cur->nodeTab[cur->nodeNr++] =
3778
690k
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3779
690k
    } else
3780
4.56M
  cur->nodeTab[cur->nodeNr++] = val;
3781
5.25M
    return(0);
3782
5.25M
}
3783
3784
/**
3785
 * xmlXPathNodeSetAddUnique:
3786
 * @cur:  the initial node set
3787
 * @val:  a new xmlNodePtr
3788
 *
3789
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3790
 * when we are sure the node is not already in the set.
3791
 *
3792
 * Returns 0 in case of success and -1 in case of failure
3793
 */
3794
int
3795
240M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3796
240M
    if ((cur == NULL) || (val == NULL)) return(-1);
3797
3798
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3799
    /*
3800
     * grow the nodeTab if needed
3801
     */
3802
240M
    if (cur->nodeMax == 0) {
3803
28.7M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3804
28.7M
               sizeof(xmlNodePtr));
3805
28.7M
  if (cur->nodeTab == NULL) {
3806
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3807
0
      return(-1);
3808
0
  }
3809
28.7M
  memset(cur->nodeTab, 0 ,
3810
28.7M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3811
28.7M
        cur->nodeMax = XML_NODESET_DEFAULT;
3812
211M
    } else if (cur->nodeNr == cur->nodeMax) {
3813
7.04M
        xmlNodePtr *temp;
3814
3815
7.04M
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3816
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3817
0
            return(-1);
3818
0
        }
3819
7.04M
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3820
7.04M
              sizeof(xmlNodePtr));
3821
7.04M
  if (temp == NULL) {
3822
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3823
0
      return(-1);
3824
0
  }
3825
7.04M
  cur->nodeTab = temp;
3826
7.04M
        cur->nodeMax *= 2;
3827
7.04M
    }
3828
240M
    if (val->type == XML_NAMESPACE_DECL) {
3829
5.01M
  xmlNsPtr ns = (xmlNsPtr) val;
3830
3831
        /* TODO: Check memory error. */
3832
5.01M
  cur->nodeTab[cur->nodeNr++] =
3833
5.01M
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3834
5.01M
    } else
3835
235M
  cur->nodeTab[cur->nodeNr++] = val;
3836
240M
    return(0);
3837
240M
}
3838
3839
/**
3840
 * xmlXPathNodeSetMerge:
3841
 * @val1:  the first NodeSet or NULL
3842
 * @val2:  the second NodeSet
3843
 *
3844
 * Merges two nodesets, all nodes from @val2 are added to @val1
3845
 * if @val1 is NULL, a new set is created and copied from @val2
3846
 *
3847
 * Returns @val1 once extended or NULL in case of error.
3848
 */
3849
xmlNodeSetPtr
3850
8.77M
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3851
8.77M
    int i, j, initNr, skip;
3852
8.77M
    xmlNodePtr n1, n2;
3853
3854
8.77M
    if (val2 == NULL) return(val1);
3855
8.46M
    if (val1 == NULL) {
3856
853k
  val1 = xmlXPathNodeSetCreate(NULL);
3857
853k
    if (val1 == NULL)
3858
0
        return (NULL);
3859
#if 0
3860
  /*
3861
  * TODO: The optimization won't work in every case, since
3862
  *  those nasty namespace nodes need to be added with
3863
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3864
  *  memcpy is not possible.
3865
  *  If there was a flag on the nodesetval, indicating that
3866
  *  some temporary nodes are in, that would be helpful.
3867
  */
3868
  /*
3869
  * Optimization: Create an equally sized node-set
3870
  * and memcpy the content.
3871
  */
3872
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3873
  if (val1 == NULL)
3874
      return(NULL);
3875
  if (val2->nodeNr != 0) {
3876
      if (val2->nodeNr == 1)
3877
    *(val1->nodeTab) = *(val2->nodeTab);
3878
      else {
3879
    memcpy(val1->nodeTab, val2->nodeTab,
3880
        val2->nodeNr * sizeof(xmlNodePtr));
3881
      }
3882
      val1->nodeNr = val2->nodeNr;
3883
  }
3884
  return(val1);
3885
#endif
3886
853k
    }
3887
3888
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3889
8.46M
    initNr = val1->nodeNr;
3890
3891
40.2M
    for (i = 0;i < val2->nodeNr;i++) {
3892
31.7M
  n2 = val2->nodeTab[i];
3893
  /*
3894
   * check against duplicates
3895
   */
3896
31.7M
  skip = 0;
3897
387M
  for (j = 0; j < initNr; j++) {
3898
358M
      n1 = val1->nodeTab[j];
3899
358M
      if (n1 == n2) {
3900
2.70M
    skip = 1;
3901
2.70M
    break;
3902
355M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3903
355M
           (n2->type == XML_NAMESPACE_DECL)) {
3904
2.33M
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3905
2.33M
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3906
66.3k
      ((xmlNsPtr) n2)->prefix)))
3907
48.0k
    {
3908
48.0k
        skip = 1;
3909
48.0k
        break;
3910
48.0k
    }
3911
2.33M
      }
3912
358M
  }
3913
31.7M
  if (skip)
3914
2.75M
      continue;
3915
3916
  /*
3917
   * grow the nodeTab if needed
3918
   */
3919
29.0M
  if (val1->nodeMax == 0) {
3920
2.43M
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3921
2.43M
                sizeof(xmlNodePtr));
3922
2.43M
      if (val1->nodeTab == NULL) {
3923
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3924
0
    return(NULL);
3925
0
      }
3926
2.43M
      memset(val1->nodeTab, 0 ,
3927
2.43M
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3928
2.43M
      val1->nodeMax = XML_NODESET_DEFAULT;
3929
26.6M
  } else if (val1->nodeNr == val1->nodeMax) {
3930
844k
      xmlNodePtr *temp;
3931
3932
844k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3933
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3934
0
                return(NULL);
3935
0
            }
3936
844k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3937
844k
               sizeof(xmlNodePtr));
3938
844k
      if (temp == NULL) {
3939
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3940
0
    return(NULL);
3941
0
      }
3942
844k
      val1->nodeTab = temp;
3943
844k
      val1->nodeMax *= 2;
3944
844k
  }
3945
29.0M
  if (n2->type == XML_NAMESPACE_DECL) {
3946
1.49M
      xmlNsPtr ns = (xmlNsPtr) n2;
3947
3948
            /* TODO: Check memory error. */
3949
1.49M
      val1->nodeTab[val1->nodeNr++] =
3950
1.49M
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3951
1.49M
  } else
3952
27.5M
      val1->nodeTab[val1->nodeNr++] = n2;
3953
29.0M
    }
3954
3955
8.46M
    return(val1);
3956
8.46M
}
3957
3958
3959
/**
3960
 * xmlXPathNodeSetMergeAndClear:
3961
 * @set1:  the first NodeSet or NULL
3962
 * @set2:  the second NodeSet
3963
 *
3964
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3965
 * Checks for duplicate nodes. Clears set2.
3966
 *
3967
 * Returns @set1 once extended or NULL in case of error.
3968
 */
3969
static xmlNodeSetPtr
3970
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3971
6.07M
{
3972
6.07M
    {
3973
6.07M
  int i, j, initNbSet1;
3974
6.07M
  xmlNodePtr n1, n2;
3975
3976
6.07M
  initNbSet1 = set1->nodeNr;
3977
22.4M
  for (i = 0;i < set2->nodeNr;i++) {
3978
16.3M
      n2 = set2->nodeTab[i];
3979
      /*
3980
      * Skip duplicates.
3981
      */
3982
3.28G
      for (j = 0; j < initNbSet1; j++) {
3983
3.27G
    n1 = set1->nodeTab[j];
3984
3.27G
    if (n1 == n2) {
3985
12.0M
        goto skip_node;
3986
3.26G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987
3.26G
        (n2->type == XML_NAMESPACE_DECL))
3988
39.2M
    {
3989
39.2M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990
39.2M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991
53.9k
      ((xmlNsPtr) n2)->prefix)))
3992
3.86k
        {
3993
      /*
3994
      * Free the namespace node.
3995
      */
3996
3.86k
      set2->nodeTab[i] = NULL;
3997
3.86k
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3998
3.86k
      goto skip_node;
3999
3.86k
        }
4000
39.2M
    }
4001
3.27G
      }
4002
      /*
4003
      * grow the nodeTab if needed
4004
      */
4005
4.30M
      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
        return(NULL);
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
4.30M
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
155k
    xmlNodePtr *temp;
4017
4018
155k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    return(NULL);
4021
0
                }
4022
155k
    temp = (xmlNodePtr *) xmlRealloc(
4023
155k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
155k
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        return(NULL);
4027
0
    }
4028
155k
    set1->nodeTab = temp;
4029
155k
    set1->nodeMax *= 2;
4030
155k
      }
4031
4.30M
      set1->nodeTab[set1->nodeNr++] = n2;
4032
16.3M
skip_node:
4033
16.3M
      {}
4034
16.3M
  }
4035
6.07M
    }
4036
6.07M
    set2->nodeNr = 0;
4037
6.07M
    return(set1);
4038
6.07M
}
4039
4040
/**
4041
 * xmlXPathNodeSetMergeAndClearNoDupls:
4042
 * @set1:  the first NodeSet or NULL
4043
 * @set2:  the second NodeSet
4044
 *
4045
 * Merges two nodesets, all nodes from @set2 are added to @set1.
4046
 * Doesn't check for duplicate nodes. Clears set2.
4047
 *
4048
 * Returns @set1 once extended or NULL in case of error.
4049
 */
4050
static xmlNodeSetPtr
4051
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4052
6.50M
{
4053
6.50M
    {
4054
6.50M
  int i;
4055
6.50M
  xmlNodePtr n2;
4056
4057
15.8M
  for (i = 0;i < set2->nodeNr;i++) {
4058
9.37M
      n2 = set2->nodeTab[i];
4059
9.37M
      if (set1->nodeMax == 0) {
4060
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4061
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4062
0
    if (set1->nodeTab == NULL) {
4063
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4064
0
        return(NULL);
4065
0
    }
4066
0
    memset(set1->nodeTab, 0,
4067
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4068
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4069
9.37M
      } else if (set1->nodeNr >= set1->nodeMax) {
4070
441k
    xmlNodePtr *temp;
4071
4072
441k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4073
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4074
0
                    return(NULL);
4075
0
                }
4076
441k
    temp = (xmlNodePtr *) xmlRealloc(
4077
441k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4078
441k
    if (temp == NULL) {
4079
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4080
0
        return(NULL);
4081
0
    }
4082
441k
    set1->nodeTab = temp;
4083
441k
    set1->nodeMax *= 2;
4084
441k
      }
4085
9.37M
      set1->nodeTab[set1->nodeNr++] = n2;
4086
9.37M
  }
4087
6.50M
    }
4088
6.50M
    set2->nodeNr = 0;
4089
6.50M
    return(set1);
4090
6.50M
}
4091
4092
/**
4093
 * xmlXPathNodeSetDel:
4094
 * @cur:  the initial node set
4095
 * @val:  an xmlNodePtr
4096
 *
4097
 * Removes an xmlNodePtr from an existing NodeSet
4098
 */
4099
void
4100
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4101
0
    int i;
4102
4103
0
    if (cur == NULL) return;
4104
0
    if (val == NULL) return;
4105
4106
    /*
4107
     * find node in nodeTab
4108
     */
4109
0
    for (i = 0;i < cur->nodeNr;i++)
4110
0
        if (cur->nodeTab[i] == val) break;
4111
4112
0
    if (i >= cur->nodeNr) { /* not found */
4113
#ifdef DEBUG
4114
        xmlGenericError(xmlGenericErrorContext,
4115
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4116
    val->name);
4117
#endif
4118
0
        return;
4119
0
    }
4120
0
    if ((cur->nodeTab[i] != NULL) &&
4121
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4122
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4123
0
    cur->nodeNr--;
4124
0
    for (;i < cur->nodeNr;i++)
4125
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4126
0
    cur->nodeTab[cur->nodeNr] = NULL;
4127
0
}
4128
4129
/**
4130
 * xmlXPathNodeSetRemove:
4131
 * @cur:  the initial node set
4132
 * @val:  the index to remove
4133
 *
4134
 * Removes an entry from an existing NodeSet list.
4135
 */
4136
void
4137
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4138
0
    if (cur == NULL) return;
4139
0
    if (val >= cur->nodeNr) return;
4140
0
    if ((cur->nodeTab[val] != NULL) &&
4141
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4142
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4143
0
    cur->nodeNr--;
4144
0
    for (;val < cur->nodeNr;val++)
4145
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4146
0
    cur->nodeTab[cur->nodeNr] = NULL;
4147
0
}
4148
4149
/**
4150
 * xmlXPathFreeNodeSet:
4151
 * @obj:  the xmlNodeSetPtr to free
4152
 *
4153
 * Free the NodeSet compound (not the actual nodes !).
4154
 */
4155
void
4156
112M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4157
112M
    if (obj == NULL) return;
4158
112M
    if (obj->nodeTab != NULL) {
4159
35.0M
  int i;
4160
4161
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4162
236M
  for (i = 0;i < obj->nodeNr;i++)
4163
201M
      if ((obj->nodeTab[i] != NULL) &&
4164
201M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4165
6.58M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4166
35.0M
  xmlFree(obj->nodeTab);
4167
35.0M
    }
4168
112M
    xmlFree(obj);
4169
112M
}
4170
4171
/**
4172
 * xmlXPathNodeSetClearFromPos:
4173
 * @set: the node set to be cleared
4174
 * @pos: the start position to clear from
4175
 *
4176
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4177
 * are feed) starting with the entry at @pos, but does *not* free the list
4178
 * itself. Sets the length of the list to @pos.
4179
 */
4180
static void
4181
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4182
165k
{
4183
165k
    if ((set == NULL) || (pos >= set->nodeNr))
4184
0
  return;
4185
165k
    else if ((hasNsNodes)) {
4186
157k
  int i;
4187
157k
  xmlNodePtr node;
4188
4189
1.81M
  for (i = pos; i < set->nodeNr; i++) {
4190
1.66M
      node = set->nodeTab[i];
4191
1.66M
      if ((node != NULL) &&
4192
1.66M
    (node->type == XML_NAMESPACE_DECL))
4193
120k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4194
1.66M
  }
4195
157k
    }
4196
165k
    set->nodeNr = pos;
4197
165k
}
4198
4199
/**
4200
 * xmlXPathNodeSetClear:
4201
 * @set:  the node set to clear
4202
 *
4203
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4204
 * are feed), but does *not* free the list itself. Sets the length of the
4205
 * list to 0.
4206
 */
4207
static void
4208
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4209
35.3k
{
4210
35.3k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4211
35.3k
}
4212
4213
/**
4214
 * xmlXPathNodeSetKeepLast:
4215
 * @set: the node set to be cleared
4216
 *
4217
 * Move the last node to the first position and clear temporary XPath objects
4218
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4219
 * to 1.
4220
 */
4221
static void
4222
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4223
135k
{
4224
135k
    int i;
4225
135k
    xmlNodePtr node;
4226
4227
135k
    if ((set == NULL) || (set->nodeNr <= 1))
4228
0
  return;
4229
1.67M
    for (i = 0; i < set->nodeNr - 1; i++) {
4230
1.53M
        node = set->nodeTab[i];
4231
1.53M
        if ((node != NULL) &&
4232
1.53M
            (node->type == XML_NAMESPACE_DECL))
4233
241k
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4234
1.53M
    }
4235
135k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4236
135k
    set->nodeNr = 1;
4237
135k
}
4238
4239
/**
4240
 * xmlXPathFreeValueTree:
4241
 * @obj:  the xmlNodeSetPtr to free
4242
 *
4243
 * Free the NodeSet compound and the actual tree, this is different
4244
 * from xmlXPathFreeNodeSet()
4245
 */
4246
static void
4247
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4248
0
    int i;
4249
4250
0
    if (obj == NULL) return;
4251
4252
0
    if (obj->nodeTab != NULL) {
4253
0
  for (i = 0;i < obj->nodeNr;i++) {
4254
0
      if (obj->nodeTab[i] != NULL) {
4255
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4256
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4257
0
    } else {
4258
0
        xmlFreeNodeList(obj->nodeTab[i]);
4259
0
    }
4260
0
      }
4261
0
  }
4262
0
  xmlFree(obj->nodeTab);
4263
0
    }
4264
0
    xmlFree(obj);
4265
0
}
4266
4267
#if defined(DEBUG) || defined(DEBUG_STEP)
4268
/**
4269
 * xmlGenericErrorContextNodeSet:
4270
 * @output:  a FILE * for the output
4271
 * @obj:  the xmlNodeSetPtr to display
4272
 *
4273
 * Quick display of a NodeSet
4274
 */
4275
void
4276
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4277
    int i;
4278
4279
    if (output == NULL) output = xmlGenericErrorContext;
4280
    if (obj == NULL)  {
4281
        fprintf(output, "NodeSet == NULL !\n");
4282
  return;
4283
    }
4284
    if (obj->nodeNr == 0) {
4285
        fprintf(output, "NodeSet is empty\n");
4286
  return;
4287
    }
4288
    if (obj->nodeTab == NULL) {
4289
  fprintf(output, " nodeTab == NULL !\n");
4290
  return;
4291
    }
4292
    for (i = 0; i < obj->nodeNr; i++) {
4293
        if (obj->nodeTab[i] == NULL) {
4294
      fprintf(output, " NULL !\n");
4295
      return;
4296
        }
4297
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4298
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4299
      fprintf(output, " /");
4300
  else if (obj->nodeTab[i]->name == NULL)
4301
      fprintf(output, " noname!");
4302
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4303
    }
4304
    fprintf(output, "\n");
4305
}
4306
#endif
4307
4308
/**
4309
 * xmlXPathNewNodeSet:
4310
 * @val:  the NodePtr value
4311
 *
4312
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4313
 * it with the single Node @val
4314
 *
4315
 * Returns the newly created object.
4316
 */
4317
xmlXPathObjectPtr
4318
34.9M
xmlXPathNewNodeSet(xmlNodePtr val) {
4319
34.9M
    xmlXPathObjectPtr ret;
4320
4321
34.9M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4322
34.9M
    if (ret == NULL) {
4323
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4324
0
  return(NULL);
4325
0
    }
4326
34.9M
    memset(ret, 0 , sizeof(xmlXPathObject));
4327
34.9M
    ret->type = XPATH_NODESET;
4328
34.9M
    ret->boolval = 0;
4329
    /* TODO: Check memory error. */
4330
34.9M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4331
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4332
#ifdef XP_DEBUG_OBJ_USAGE
4333
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4334
#endif
4335
34.9M
    return(ret);
4336
34.9M
}
4337
4338
/**
4339
 * xmlXPathNewValueTree:
4340
 * @val:  the NodePtr value
4341
 *
4342
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4343
 * it with the tree root @val
4344
 *
4345
 * Returns the newly created object.
4346
 */
4347
xmlXPathObjectPtr
4348
0
xmlXPathNewValueTree(xmlNodePtr val) {
4349
0
    xmlXPathObjectPtr ret;
4350
4351
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4352
0
    if (ret == NULL) {
4353
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4354
0
  return(NULL);
4355
0
    }
4356
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4357
0
    ret->type = XPATH_XSLT_TREE;
4358
0
    ret->boolval = 1;
4359
0
    ret->user = (void *) val;
4360
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4361
#ifdef XP_DEBUG_OBJ_USAGE
4362
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4363
#endif
4364
0
    return(ret);
4365
0
}
4366
4367
/**
4368
 * xmlXPathNewNodeSetList:
4369
 * @val:  an existing NodeSet
4370
 *
4371
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4372
 * it with the Nodeset @val
4373
 *
4374
 * Returns the newly created object.
4375
 */
4376
xmlXPathObjectPtr
4377
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4378
0
{
4379
0
    xmlXPathObjectPtr ret;
4380
0
    int i;
4381
4382
0
    if (val == NULL)
4383
0
        ret = NULL;
4384
0
    else if (val->nodeTab == NULL)
4385
0
        ret = xmlXPathNewNodeSet(NULL);
4386
0
    else {
4387
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4388
0
        if (ret) {
4389
0
            for (i = 1; i < val->nodeNr; ++i) {
4390
                /* TODO: Propagate memory error. */
4391
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4392
0
        < 0) break;
4393
0
      }
4394
0
  }
4395
0
    }
4396
4397
0
    return (ret);
4398
0
}
4399
4400
/**
4401
 * xmlXPathWrapNodeSet:
4402
 * @val:  the NodePtr value
4403
 *
4404
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4405
 *
4406
 * Returns the newly created object.
4407
 */
4408
xmlXPathObjectPtr
4409
17.0M
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4410
17.0M
    xmlXPathObjectPtr ret;
4411
4412
17.0M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4413
17.0M
    if (ret == NULL) {
4414
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4415
0
  return(NULL);
4416
0
    }
4417
17.0M
    memset(ret, 0 , sizeof(xmlXPathObject));
4418
17.0M
    ret->type = XPATH_NODESET;
4419
17.0M
    ret->nodesetval = val;
4420
#ifdef XP_DEBUG_OBJ_USAGE
4421
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4422
#endif
4423
17.0M
    return(ret);
4424
17.0M
}
4425
4426
/**
4427
 * xmlXPathFreeNodeSetList:
4428
 * @obj:  an existing NodeSetList object
4429
 *
4430
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4431
 * the list contrary to xmlXPathFreeObject().
4432
 */
4433
void
4434
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4435
0
    if (obj == NULL) return;
4436
#ifdef XP_DEBUG_OBJ_USAGE
4437
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4438
#endif
4439
0
    xmlFree(obj);
4440
0
}
4441
4442
/**
4443
 * xmlXPathDifference:
4444
 * @nodes1:  a node-set
4445
 * @nodes2:  a node-set
4446
 *
4447
 * Implements the EXSLT - Sets difference() function:
4448
 *    node-set set:difference (node-set, node-set)
4449
 *
4450
 * Returns the difference between the two node sets, or nodes1 if
4451
 *         nodes2 is empty
4452
 */
4453
xmlNodeSetPtr
4454
145k
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4455
145k
    xmlNodeSetPtr ret;
4456
145k
    int i, l1;
4457
145k
    xmlNodePtr cur;
4458
4459
145k
    if (xmlXPathNodeSetIsEmpty(nodes2))
4460
81.9k
  return(nodes1);
4461
4462
    /* TODO: Check memory error. */
4463
63.4k
    ret = xmlXPathNodeSetCreate(NULL);
4464
63.4k
    if (xmlXPathNodeSetIsEmpty(nodes1))
4465
42.9k
  return(ret);
4466
4467
20.5k
    l1 = xmlXPathNodeSetGetLength(nodes1);
4468
4469
121k
    for (i = 0; i < l1; i++) {
4470
101k
  cur = xmlXPathNodeSetItem(nodes1, i);
4471
101k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4472
            /* TODO: Propagate memory error. */
4473
73.2k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4474
0
          break;
4475
73.2k
  }
4476
101k
    }
4477
20.5k
    return(ret);
4478
63.4k
}
4479
4480
/**
4481
 * xmlXPathIntersection:
4482
 * @nodes1:  a node-set
4483
 * @nodes2:  a node-set
4484
 *
4485
 * Implements the EXSLT - Sets intersection() function:
4486
 *    node-set set:intersection (node-set, node-set)
4487
 *
4488
 * Returns a node set comprising the nodes that are within both the
4489
 *         node sets passed as arguments
4490
 */
4491
xmlNodeSetPtr
4492
162k
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4493
162k
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4494
162k
    int i, l1;
4495
162k
    xmlNodePtr cur;
4496
4497
162k
    if (ret == NULL)
4498
0
        return(ret);
4499
162k
    if (xmlXPathNodeSetIsEmpty(nodes1))
4500
99.7k
  return(ret);
4501
63.0k
    if (xmlXPathNodeSetIsEmpty(nodes2))
4502
39.3k
  return(ret);
4503
4504
23.7k
    l1 = xmlXPathNodeSetGetLength(nodes1);
4505
4506
427k
    for (i = 0; i < l1; i++) {
4507
403k
  cur = xmlXPathNodeSetItem(nodes1, i);
4508
403k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4509
            /* TODO: Propagate memory error. */
4510
103k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4511
0
          break;
4512
103k
  }
4513
403k
    }
4514
23.7k
    return(ret);
4515
63.0k
}
4516
4517
/**
4518
 * xmlXPathDistinctSorted:
4519
 * @nodes:  a node-set, sorted by document order
4520
 *
4521
 * Implements the EXSLT - Sets distinct() function:
4522
 *    node-set set:distinct (node-set)
4523
 *
4524
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4525
 *         it is empty
4526
 */
4527
xmlNodeSetPtr
4528
70.5k
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4529
70.5k
    xmlNodeSetPtr ret;
4530
70.5k
    xmlHashTablePtr hash;
4531
70.5k
    int i, l;
4532
70.5k
    xmlChar * strval;
4533
70.5k
    xmlNodePtr cur;
4534
4535
70.5k
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
35.4k
  return(nodes);
4537
4538
35.1k
    ret = xmlXPathNodeSetCreate(NULL);
4539
35.1k
    if (ret == NULL)
4540
0
        return(ret);
4541
35.1k
    l = xmlXPathNodeSetGetLength(nodes);
4542
35.1k
    hash = xmlHashCreate (l);
4543
1.39M
    for (i = 0; i < l; i++) {
4544
1.36M
  cur = xmlXPathNodeSetItem(nodes, i);
4545
1.36M
  strval = xmlXPathCastNodeToString(cur);
4546
1.36M
  if (xmlHashLookup(hash, strval) == NULL) {
4547
345k
      xmlHashAddEntry(hash, strval, strval);
4548
            /* TODO: Propagate memory error. */
4549
345k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4550
0
          break;
4551
1.01M
  } else {
4552
1.01M
      xmlFree(strval);
4553
1.01M
  }
4554
1.36M
    }
4555
35.1k
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4556
35.1k
    return(ret);
4557
35.1k
}
4558
4559
/**
4560
 * xmlXPathDistinct:
4561
 * @nodes:  a node-set
4562
 *
4563
 * Implements the EXSLT - Sets distinct() function:
4564
 *    node-set set:distinct (node-set)
4565
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4566
 * is called with the sorted node-set
4567
 *
4568
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4569
 *         it is empty
4570
 */
4571
xmlNodeSetPtr
4572
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4573
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4574
0
  return(nodes);
4575
4576
0
    xmlXPathNodeSetSort(nodes);
4577
0
    return(xmlXPathDistinctSorted(nodes));
4578
0
}
4579
4580
/**
4581
 * xmlXPathHasSameNodes:
4582
 * @nodes1:  a node-set
4583
 * @nodes2:  a node-set
4584
 *
4585
 * Implements the EXSLT - Sets has-same-nodes function:
4586
 *    boolean set:has-same-node(node-set, node-set)
4587
 *
4588
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4589
 *         otherwise
4590
 */
4591
int
4592
128k
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4593
128k
    int i, l;
4594
128k
    xmlNodePtr cur;
4595
4596
128k
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4597
128k
  xmlXPathNodeSetIsEmpty(nodes2))
4598
107k
  return(0);
4599
4600
21.0k
    l = xmlXPathNodeSetGetLength(nodes1);
4601
86.3k
    for (i = 0; i < l; i++) {
4602
74.9k
  cur = xmlXPathNodeSetItem(nodes1, i);
4603
74.9k
  if (xmlXPathNodeSetContains(nodes2, cur))
4604
9.74k
      return(1);
4605
74.9k
    }
4606
11.3k
    return(0);
4607
21.0k
}
4608
4609
/**
4610
 * xmlXPathNodeLeadingSorted:
4611
 * @nodes: a node-set, sorted by document order
4612
 * @node: a node
4613
 *
4614
 * Implements the EXSLT - Sets leading() function:
4615
 *    node-set set:leading (node-set, node-set)
4616
 *
4617
 * Returns the nodes in @nodes that precede @node in document order,
4618
 *         @nodes if @node is NULL or an empty node-set if @nodes
4619
 *         doesn't contain @node
4620
 */
4621
xmlNodeSetPtr
4622
101k
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4623
101k
    int i, l;
4624
101k
    xmlNodePtr cur;
4625
101k
    xmlNodeSetPtr ret;
4626
4627
101k
    if (node == NULL)
4628
0
  return(nodes);
4629
4630
101k
    ret = xmlXPathNodeSetCreate(NULL);
4631
101k
    if (ret == NULL)
4632
0
        return(ret);
4633
101k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4634
101k
  (!xmlXPathNodeSetContains(nodes, node)))
4635
79.9k
  return(ret);
4636
4637
21.4k
    l = xmlXPathNodeSetGetLength(nodes);
4638
155k
    for (i = 0; i < l; i++) {
4639
155k
  cur = xmlXPathNodeSetItem(nodes, i);
4640
155k
  if (cur == node)
4641
21.1k
      break;
4642
        /* TODO: Propagate memory error. */
4643
134k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4644
0
      break;
4645
134k
    }
4646
21.4k
    return(ret);
4647
101k
}
4648
4649
/**
4650
 * xmlXPathNodeLeading:
4651
 * @nodes:  a node-set
4652
 * @node:  a node
4653
 *
4654
 * Implements the EXSLT - Sets leading() function:
4655
 *    node-set set:leading (node-set, node-set)
4656
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4657
 * is called.
4658
 *
4659
 * Returns the nodes in @nodes that precede @node in document order,
4660
 *         @nodes if @node is NULL or an empty node-set if @nodes
4661
 *         doesn't contain @node
4662
 */
4663
xmlNodeSetPtr
4664
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4665
0
    xmlXPathNodeSetSort(nodes);
4666
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4667
0
}
4668
4669
/**
4670
 * xmlXPathLeadingSorted:
4671
 * @nodes1:  a node-set, sorted by document order
4672
 * @nodes2:  a node-set, sorted by document order
4673
 *
4674
 * Implements the EXSLT - Sets leading() function:
4675
 *    node-set set:leading (node-set, node-set)
4676
 *
4677
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4678
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4679
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4680
 */
4681
xmlNodeSetPtr
4682
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4684
0
  return(nodes1);
4685
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4686
0
             xmlXPathNodeSetItem(nodes2, 1)));
4687
0
}
4688
4689
/**
4690
 * xmlXPathLeading:
4691
 * @nodes1:  a node-set
4692
 * @nodes2:  a node-set
4693
 *
4694
 * Implements the EXSLT - Sets leading() function:
4695
 *    node-set set:leading (node-set, node-set)
4696
 * @nodes1 and @nodes2 are sorted by document order, then
4697
 * #exslSetsLeadingSorted is called.
4698
 *
4699
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4700
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4701
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4702
 */
4703
xmlNodeSetPtr
4704
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4705
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4706
0
  return(nodes1);
4707
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4708
0
  return(xmlXPathNodeSetCreate(NULL));
4709
0
    xmlXPathNodeSetSort(nodes1);
4710
0
    xmlXPathNodeSetSort(nodes2);
4711
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4712
0
             xmlXPathNodeSetItem(nodes2, 1)));
4713
0
}
4714
4715
/**
4716
 * xmlXPathNodeTrailingSorted:
4717
 * @nodes: a node-set, sorted by document order
4718
 * @node: a node
4719
 *
4720
 * Implements the EXSLT - Sets trailing() function:
4721
 *    node-set set:trailing (node-set, node-set)
4722
 *
4723
 * Returns the nodes in @nodes that follow @node in document order,
4724
 *         @nodes if @node is NULL or an empty node-set if @nodes
4725
 *         doesn't contain @node
4726
 */
4727
xmlNodeSetPtr
4728
95.7k
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4729
95.7k
    int i, l;
4730
95.7k
    xmlNodePtr cur;
4731
95.7k
    xmlNodeSetPtr ret;
4732
4733
95.7k
    if (node == NULL)
4734
0
  return(nodes);
4735
4736
95.7k
    ret = xmlXPathNodeSetCreate(NULL);
4737
95.7k
    if (ret == NULL)
4738
0
        return(ret);
4739
95.7k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4740
95.7k
  (!xmlXPathNodeSetContains(nodes, node)))
4741
65.5k
  return(ret);
4742
4743
30.1k
    l = xmlXPathNodeSetGetLength(nodes);
4744
912k
    for (i = l - 1; i >= 0; i--) {
4745
912k
  cur = xmlXPathNodeSetItem(nodes, i);
4746
912k
  if (cur == node)
4747
30.1k
      break;
4748
        /* TODO: Propagate memory error. */
4749
882k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4750
0
      break;
4751
882k
    }
4752
30.1k
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4753
30.1k
    return(ret);
4754
95.7k
}
4755
4756
/**
4757
 * xmlXPathNodeTrailing:
4758
 * @nodes:  a node-set
4759
 * @node:  a node
4760
 *
4761
 * Implements the EXSLT - Sets trailing() function:
4762
 *    node-set set:trailing (node-set, node-set)
4763
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4764
 * is called.
4765
 *
4766
 * Returns the nodes in @nodes that follow @node in document order,
4767
 *         @nodes if @node is NULL or an empty node-set if @nodes
4768
 *         doesn't contain @node
4769
 */
4770
xmlNodeSetPtr
4771
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4772
0
    xmlXPathNodeSetSort(nodes);
4773
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4774
0
}
4775
4776
/**
4777
 * xmlXPathTrailingSorted:
4778
 * @nodes1:  a node-set, sorted by document order
4779
 * @nodes2:  a node-set, sorted by document order
4780
 *
4781
 * Implements the EXSLT - Sets trailing() function:
4782
 *    node-set set:trailing (node-set, node-set)
4783
 *
4784
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4785
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4786
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4787
 */
4788
xmlNodeSetPtr
4789
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4790
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4791
0
  return(nodes1);
4792
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4793
0
              xmlXPathNodeSetItem(nodes2, 0)));
4794
0
}
4795
4796
/**
4797
 * xmlXPathTrailing:
4798
 * @nodes1:  a node-set
4799
 * @nodes2:  a node-set
4800
 *
4801
 * Implements the EXSLT - Sets trailing() function:
4802
 *    node-set set:trailing (node-set, node-set)
4803
 * @nodes1 and @nodes2 are sorted by document order, then
4804
 * #xmlXPathTrailingSorted is called.
4805
 *
4806
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4807
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4808
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4809
 */
4810
xmlNodeSetPtr
4811
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4812
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4813
0
  return(nodes1);
4814
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4815
0
  return(xmlXPathNodeSetCreate(NULL));
4816
0
    xmlXPathNodeSetSort(nodes1);
4817
0
    xmlXPathNodeSetSort(nodes2);
4818
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4819
0
              xmlXPathNodeSetItem(nodes2, 0)));
4820
0
}
4821
4822
/************************************************************************
4823
 *                  *
4824
 *    Routines to handle extra functions      *
4825
 *                  *
4826
 ************************************************************************/
4827
4828
/**
4829
 * xmlXPathRegisterFunc:
4830
 * @ctxt:  the XPath context
4831
 * @name:  the function name
4832
 * @f:  the function implementation or NULL
4833
 *
4834
 * Register a new function. If @f is NULL it unregisters the function
4835
 *
4836
 * Returns 0 in case of success, -1 in case of error
4837
 */
4838
int
4839
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4840
1.93M
         xmlXPathFunction f) {
4841
1.93M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4842
1.93M
}
4843
4844
/**
4845
 * xmlXPathRegisterFuncNS:
4846
 * @ctxt:  the XPath context
4847
 * @name:  the function name
4848
 * @ns_uri:  the function namespace URI
4849
 * @f:  the function implementation or NULL
4850
 *
4851
 * Register a new function. If @f is NULL it unregisters the function
4852
 *
4853
 * Returns 0 in case of success, -1 in case of error
4854
 */
4855
int
4856
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4857
2.00M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4858
2.00M
    if (ctxt == NULL)
4859
0
  return(-1);
4860
2.00M
    if (name == NULL)
4861
0
  return(-1);
4862
4863
2.00M
    if (ctxt->funcHash == NULL)
4864
0
  ctxt->funcHash = xmlHashCreate(0);
4865
2.00M
    if (ctxt->funcHash == NULL)
4866
0
  return(-1);
4867
2.00M
    if (f == NULL)
4868
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4869
2.00M
XML_IGNORE_FPTR_CAST_WARNINGS
4870
2.00M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4871
2.00M
XML_POP_WARNINGS
4872
2.00M
}
4873
4874
/**
4875
 * xmlXPathRegisterFuncLookup:
4876
 * @ctxt:  the XPath context
4877
 * @f:  the lookup function
4878
 * @funcCtxt:  the lookup data
4879
 *
4880
 * Registers an external mechanism to do function lookup.
4881
 */
4882
void
4883
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4884
          xmlXPathFuncLookupFunc f,
4885
3.69k
          void *funcCtxt) {
4886
3.69k
    if (ctxt == NULL)
4887
0
  return;
4888
3.69k
    ctxt->funcLookupFunc = f;
4889
3.69k
    ctxt->funcLookupData = funcCtxt;
4890
3.69k
}
4891
4892
/**
4893
 * xmlXPathFunctionLookup:
4894
 * @ctxt:  the XPath context
4895
 * @name:  the function name
4896
 *
4897
 * Search in the Function array of the context for the given
4898
 * function.
4899
 *
4900
 * Returns the xmlXPathFunction or NULL if not found
4901
 */
4902
xmlXPathFunction
4903
2.90M
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4904
2.90M
    if (ctxt == NULL)
4905
0
  return (NULL);
4906
4907
2.90M
    if (ctxt->funcLookupFunc != NULL) {
4908
2.90M
  xmlXPathFunction ret;
4909
2.90M
  xmlXPathFuncLookupFunc f;
4910
4911
2.90M
  f = ctxt->funcLookupFunc;
4912
2.90M
  ret = f(ctxt->funcLookupData, name, NULL);
4913
2.90M
  if (ret != NULL)
4914
0
      return(ret);
4915
2.90M
    }
4916
2.90M
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4917
2.90M
}
4918
4919
/**
4920
 * xmlXPathFunctionLookupNS:
4921
 * @ctxt:  the XPath context
4922
 * @name:  the function name
4923
 * @ns_uri:  the function namespace URI
4924
 *
4925
 * Search in the Function array of the context for the given
4926
 * function.
4927
 *
4928
 * Returns the xmlXPathFunction or NULL if not found
4929
 */
4930
xmlXPathFunction
4931
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4932
4.29M
       const xmlChar *ns_uri) {
4933
4.29M
    xmlXPathFunction ret;
4934
4935
4.29M
    if (ctxt == NULL)
4936
0
  return(NULL);
4937
4.29M
    if (name == NULL)
4938
0
  return(NULL);
4939
4940
4.29M
    if (ctxt->funcLookupFunc != NULL) {
4941
4.29M
  xmlXPathFuncLookupFunc f;
4942
4943
4.29M
  f = ctxt->funcLookupFunc;
4944
4.29M
  ret = f(ctxt->funcLookupData, name, ns_uri);
4945
4.29M
  if (ret != NULL)
4946
1.32M
      return(ret);
4947
4.29M
    }
4948
4949
2.97M
    if (ctxt->funcHash == NULL)
4950
0
  return(NULL);
4951
4952
2.97M
XML_IGNORE_FPTR_CAST_WARNINGS
4953
2.97M
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4954
2.97M
XML_POP_WARNINGS
4955
2.97M
    return(ret);
4956
2.97M
}
4957
4958
/**
4959
 * xmlXPathRegisteredFuncsCleanup:
4960
 * @ctxt:  the XPath context
4961
 *
4962
 * Cleanup the XPath context data associated to registered functions
4963
 */
4964
void
4965
62.9k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4966
62.9k
    if (ctxt == NULL)
4967
0
  return;
4968
4969
62.9k
    xmlHashFree(ctxt->funcHash, NULL);
4970
62.9k
    ctxt->funcHash = NULL;
4971
62.9k
}
4972
4973
/************************************************************************
4974
 *                  *
4975
 *      Routines to handle Variables      *
4976
 *                  *
4977
 ************************************************************************/
4978
4979
/**
4980
 * xmlXPathRegisterVariable:
4981
 * @ctxt:  the XPath context
4982
 * @name:  the variable name
4983
 * @value:  the variable value or NULL
4984
 *
4985
 * Register a new variable value. If @value is NULL it unregisters
4986
 * the variable
4987
 *
4988
 * Returns 0 in case of success, -1 in case of error
4989
 */
4990
int
4991
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4992
14.7k
       xmlXPathObjectPtr value) {
4993
14.7k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4994
14.7k
}
4995
4996
/**
4997
 * xmlXPathRegisterVariableNS:
4998
 * @ctxt:  the XPath context
4999
 * @name:  the variable name
5000
 * @ns_uri:  the variable namespace URI
5001
 * @value:  the variable value or NULL
5002
 *
5003
 * Register a new variable value. If @value is NULL it unregisters
5004
 * the variable
5005
 *
5006
 * Returns 0 in case of success, -1 in case of error
5007
 */
5008
int
5009
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5010
         const xmlChar *ns_uri,
5011
14.7k
         xmlXPathObjectPtr value) {
5012
14.7k
    if (ctxt == NULL)
5013
0
  return(-1);
5014
14.7k
    if (name == NULL)
5015
0
  return(-1);
5016
5017
14.7k
    if (ctxt->varHash == NULL)
5018
3.69k
  ctxt->varHash = xmlHashCreate(0);
5019
14.7k
    if (ctxt->varHash == NULL)
5020
0
  return(-1);
5021
14.7k
    if (value == NULL)
5022
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5023
0
                             xmlXPathFreeObjectEntry));
5024
14.7k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5025
14.7k
             (void *) value, xmlXPathFreeObjectEntry));
5026
14.7k
}
5027
5028
/**
5029
 * xmlXPathRegisterVariableLookup:
5030
 * @ctxt:  the XPath context
5031
 * @f:  the lookup function
5032
 * @data:  the lookup data
5033
 *
5034
 * register an external mechanism to do variable lookup
5035
 */
5036
void
5037
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5038
3.69k
   xmlXPathVariableLookupFunc f, void *data) {
5039
3.69k
    if (ctxt == NULL)
5040
0
  return;
5041
3.69k
    ctxt->varLookupFunc = f;
5042
3.69k
    ctxt->varLookupData = data;
5043
3.69k
}
5044
5045
/**
5046
 * xmlXPathVariableLookup:
5047
 * @ctxt:  the XPath context
5048
 * @name:  the variable name
5049
 *
5050
 * Search in the Variable array of the context for the given
5051
 * variable value.
5052
 *
5053
 * Returns a copy of the value or NULL if not found
5054
 */
5055
xmlXPathObjectPtr
5056
149k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5057
149k
    if (ctxt == NULL)
5058
0
  return(NULL);
5059
5060
149k
    if (ctxt->varLookupFunc != NULL) {
5061
149k
  xmlXPathObjectPtr ret;
5062
5063
149k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5064
149k
          (ctxt->varLookupData, name, NULL);
5065
149k
  return(ret);
5066
149k
    }
5067
396
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5068
149k
}
5069
5070
/**
5071
 * xmlXPathVariableLookupNS:
5072
 * @ctxt:  the XPath context
5073
 * @name:  the variable name
5074
 * @ns_uri:  the variable namespace URI
5075
 *
5076
 * Search in the Variable array of the context for the given
5077
 * variable value.
5078
 *
5079
 * Returns the a copy of the value or NULL if not found
5080
 */
5081
xmlXPathObjectPtr
5082
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5083
15.2k
       const xmlChar *ns_uri) {
5084
15.2k
    if (ctxt == NULL)
5085
0
  return(NULL);
5086
5087
15.2k
    if (ctxt->varLookupFunc != NULL) {
5088
14.8k
  xmlXPathObjectPtr ret;
5089
5090
14.8k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5091
14.8k
          (ctxt->varLookupData, name, ns_uri);
5092
14.8k
  if (ret != NULL) return(ret);
5093
14.8k
    }
5094
5095
15.2k
    if (ctxt->varHash == NULL)
5096
396
  return(NULL);
5097
14.8k
    if (name == NULL)
5098
0
  return(NULL);
5099
5100
14.8k
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5101
14.8k
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5102
14.8k
}
5103
5104
/**
5105
 * xmlXPathRegisteredVariablesCleanup:
5106
 * @ctxt:  the XPath context
5107
 *
5108
 * Cleanup the XPath context data associated to registered variables
5109
 */
5110
void
5111
62.9k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5112
62.9k
    if (ctxt == NULL)
5113
0
  return;
5114
5115
62.9k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5116
62.9k
    ctxt->varHash = NULL;
5117
62.9k
}
5118
5119
/**
5120
 * xmlXPathRegisterNs:
5121
 * @ctxt:  the XPath context
5122
 * @prefix:  the namespace prefix cannot be NULL or empty string
5123
 * @ns_uri:  the namespace name
5124
 *
5125
 * Register a new namespace. If @ns_uri is NULL it unregisters
5126
 * the namespace
5127
 *
5128
 * Returns 0 in case of success, -1 in case of error
5129
 */
5130
int
5131
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5132
40.7k
         const xmlChar *ns_uri) {
5133
40.7k
    if (ctxt == NULL)
5134
0
  return(-1);
5135
40.7k
    if (prefix == NULL)
5136
0
  return(-1);
5137
40.7k
    if (prefix[0] == 0)
5138
0
  return(-1);
5139
5140
40.7k
    if (ctxt->nsHash == NULL)
5141
3.75k
  ctxt->nsHash = xmlHashCreate(10);
5142
40.7k
    if (ctxt->nsHash == NULL)
5143
0
  return(-1);
5144
40.7k
    if (ns_uri == NULL)
5145
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5146
0
                            xmlHashDefaultDeallocator));
5147
40.7k
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5148
40.7k
            xmlHashDefaultDeallocator));
5149
40.7k
}
5150
5151
/**
5152
 * xmlXPathNsLookup:
5153
 * @ctxt:  the XPath context
5154
 * @prefix:  the namespace prefix value
5155
 *
5156
 * Search in the namespace declaration array of the context for the given
5157
 * namespace name associated to the given prefix
5158
 *
5159
 * Returns the value or NULL if not found
5160
 */
5161
const xmlChar *
5162
3.35M
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5163
3.35M
    if (ctxt == NULL)
5164
0
  return(NULL);
5165
3.35M
    if (prefix == NULL)
5166
0
  return(NULL);
5167
5168
3.35M
#ifdef XML_XML_NAMESPACE
5169
3.35M
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5170
24.9k
  return(XML_XML_NAMESPACE);
5171
3.32M
#endif
5172
5173
3.32M
    if (ctxt->namespaces != NULL) {
5174
0
  int i;
5175
5176
0
  for (i = 0;i < ctxt->nsNr;i++) {
5177
0
      if ((ctxt->namespaces[i] != NULL) &&
5178
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5179
0
    return(ctxt->namespaces[i]->href);
5180
0
  }
5181
0
    }
5182
5183
3.32M
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5184
3.32M
}
5185
5186
/**
5187
 * xmlXPathRegisteredNsCleanup:
5188
 * @ctxt:  the XPath context
5189
 *
5190
 * Cleanup the XPath context data associated to registered variables
5191
 */
5192
void
5193
62.9k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5194
62.9k
    if (ctxt == NULL)
5195
0
  return;
5196
5197
62.9k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5198
62.9k
    ctxt->nsHash = NULL;
5199
62.9k
}
5200
5201
/************************************************************************
5202
 *                  *
5203
 *      Routines to handle Values     *
5204
 *                  *
5205
 ************************************************************************/
5206
5207
/* Allocations are terrible, one needs to optimize all this !!! */
5208
5209
/**
5210
 * xmlXPathNewFloat:
5211
 * @val:  the double value
5212
 *
5213
 * Create a new xmlXPathObjectPtr of type double and of value @val
5214
 *
5215
 * Returns the newly created object.
5216
 */
5217
xmlXPathObjectPtr
5218
5.76M
xmlXPathNewFloat(double val) {
5219
5.76M
    xmlXPathObjectPtr ret;
5220
5221
5.76M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5222
5.76M
    if (ret == NULL) {
5223
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5224
0
  return(NULL);
5225
0
    }
5226
5.76M
    memset(ret, 0 , sizeof(xmlXPathObject));
5227
5.76M
    ret->type = XPATH_NUMBER;
5228
5.76M
    ret->floatval = val;
5229
#ifdef XP_DEBUG_OBJ_USAGE
5230
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5231
#endif
5232
5.76M
    return(ret);
5233
5.76M
}
5234
5235
/**
5236
 * xmlXPathNewBoolean:
5237
 * @val:  the boolean value
5238
 *
5239
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5240
 *
5241
 * Returns the newly created object.
5242
 */
5243
xmlXPathObjectPtr
5244
1.25M
xmlXPathNewBoolean(int val) {
5245
1.25M
    xmlXPathObjectPtr ret;
5246
5247
1.25M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248
1.25M
    if (ret == NULL) {
5249
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5250
0
  return(NULL);
5251
0
    }
5252
1.25M
    memset(ret, 0 , sizeof(xmlXPathObject));
5253
1.25M
    ret->type = XPATH_BOOLEAN;
5254
1.25M
    ret->boolval = (val != 0);
5255
#ifdef XP_DEBUG_OBJ_USAGE
5256
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5257
#endif
5258
1.25M
    return(ret);
5259
1.25M
}
5260
5261
/**
5262
 * xmlXPathNewString:
5263
 * @val:  the xmlChar * value
5264
 *
5265
 * Create a new xmlXPathObjectPtr of type string and of value @val
5266
 *
5267
 * Returns the newly created object.
5268
 */
5269
xmlXPathObjectPtr
5270
5.33M
xmlXPathNewString(const xmlChar *val) {
5271
5.33M
    xmlXPathObjectPtr ret;
5272
5273
5.33M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5274
5.33M
    if (ret == NULL) {
5275
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5276
0
  return(NULL);
5277
0
    }
5278
5.33M
    memset(ret, 0 , sizeof(xmlXPathObject));
5279
5.33M
    ret->type = XPATH_STRING;
5280
5.33M
    if (val != NULL)
5281
5.33M
  ret->stringval = xmlStrdup(val);
5282
8.15k
    else
5283
8.15k
  ret->stringval = xmlStrdup((const xmlChar *)"");
5284
#ifdef XP_DEBUG_OBJ_USAGE
5285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5286
#endif
5287
5.33M
    return(ret);
5288
5.33M
}
5289
5290
/**
5291
 * xmlXPathWrapString:
5292
 * @val:  the xmlChar * value
5293
 *
5294
 * Wraps the @val string into an XPath object.
5295
 *
5296
 * Returns the newly created object.
5297
 */
5298
xmlXPathObjectPtr
5299
2.33M
xmlXPathWrapString (xmlChar *val) {
5300
2.33M
    xmlXPathObjectPtr ret;
5301
5302
2.33M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5303
2.33M
    if (ret == NULL) {
5304
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5305
0
  return(NULL);
5306
0
    }
5307
2.33M
    memset(ret, 0 , sizeof(xmlXPathObject));
5308
2.33M
    ret->type = XPATH_STRING;
5309
2.33M
    ret->stringval = val;
5310
#ifdef XP_DEBUG_OBJ_USAGE
5311
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5312
#endif
5313
2.33M
    return(ret);
5314
2.33M
}
5315
5316
/**
5317
 * xmlXPathNewCString:
5318
 * @val:  the char * value
5319
 *
5320
 * Create a new xmlXPathObjectPtr of type string and of value @val
5321
 *
5322
 * Returns the newly created object.
5323
 */
5324
xmlXPathObjectPtr
5325
2.96M
xmlXPathNewCString(const char *val) {
5326
2.96M
    xmlXPathObjectPtr ret;
5327
5328
2.96M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5329
2.96M
    if (ret == NULL) {
5330
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5331
0
  return(NULL);
5332
0
    }
5333
2.96M
    memset(ret, 0 , sizeof(xmlXPathObject));
5334
2.96M
    ret->type = XPATH_STRING;
5335
2.96M
    ret->stringval = xmlStrdup(BAD_CAST val);
5336
#ifdef XP_DEBUG_OBJ_USAGE
5337
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5338
#endif
5339
2.96M
    return(ret);
5340
2.96M
}
5341
5342
/**
5343
 * xmlXPathWrapCString:
5344
 * @val:  the char * value
5345
 *
5346
 * Wraps a string into an XPath object.
5347
 *
5348
 * Returns the newly created object.
5349
 */
5350
xmlXPathObjectPtr
5351
0
xmlXPathWrapCString (char * val) {
5352
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5353
0
}
5354
5355
/**
5356
 * xmlXPathWrapExternal:
5357
 * @val:  the user data
5358
 *
5359
 * Wraps the @val data into an XPath object.
5360
 *
5361
 * Returns the newly created object.
5362
 */
5363
xmlXPathObjectPtr
5364
40.6k
xmlXPathWrapExternal (void *val) {
5365
40.6k
    xmlXPathObjectPtr ret;
5366
5367
40.6k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5368
40.6k
    if (ret == NULL) {
5369
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5370
0
  return(NULL);
5371
0
    }
5372
40.6k
    memset(ret, 0 , sizeof(xmlXPathObject));
5373
40.6k
    ret->type = XPATH_USERS;
5374
40.6k
    ret->user = val;
5375
#ifdef XP_DEBUG_OBJ_USAGE
5376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5377
#endif
5378
40.6k
    return(ret);
5379
40.6k
}
5380
5381
/**
5382
 * xmlXPathObjectCopy:
5383
 * @val:  the original object
5384
 *
5385
 * allocate a new copy of a given object
5386
 *
5387
 * Returns the newly created object.
5388
 */
5389
xmlXPathObjectPtr
5390
345k
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5391
345k
    xmlXPathObjectPtr ret;
5392
5393
345k
    if (val == NULL)
5394
0
  return(NULL);
5395
5396
345k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5397
345k
    if (ret == NULL) {
5398
0
        xmlXPathErrMemory(NULL, "copying object\n");
5399
0
  return(NULL);
5400
0
    }
5401
345k
    memcpy(ret, val , sizeof(xmlXPathObject));
5402
#ifdef XP_DEBUG_OBJ_USAGE
5403
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5404
#endif
5405
345k
    switch (val->type) {
5406
0
  case XPATH_BOOLEAN:
5407
456
  case XPATH_NUMBER:
5408
#ifdef LIBXML_XPTR_LOCS_ENABLED
5409
  case XPATH_POINT:
5410
  case XPATH_RANGE:
5411
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5412
456
      break;
5413
3.54k
  case XPATH_STRING:
5414
3.54k
      ret->stringval = xmlStrdup(val->stringval);
5415
3.54k
      break;
5416
0
  case XPATH_XSLT_TREE:
5417
#if 0
5418
/*
5419
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5420
  this previous handling is no longer correct, and can cause some serious
5421
  problems (ref. bug 145547)
5422
*/
5423
      if ((val->nodesetval != NULL) &&
5424
    (val->nodesetval->nodeTab != NULL)) {
5425
    xmlNodePtr cur, tmp;
5426
    xmlDocPtr top;
5427
5428
    ret->boolval = 1;
5429
    top =  xmlNewDoc(NULL);
5430
    top->name = (char *)
5431
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5432
    ret->user = top;
5433
    if (top != NULL) {
5434
        top->doc = top;
5435
        cur = val->nodesetval->nodeTab[0]->children;
5436
        while (cur != NULL) {
5437
      tmp = xmlDocCopyNode(cur, top, 1);
5438
      xmlAddChild((xmlNodePtr) top, tmp);
5439
      cur = cur->next;
5440
        }
5441
    }
5442
5443
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5444
      } else
5445
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5446
      /* Deallocate the copied tree value */
5447
      break;
5448
#endif
5449
341k
  case XPATH_NODESET:
5450
            /* TODO: Check memory error. */
5451
341k
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452
      /* Do not deallocate the copied tree value */
5453
341k
      ret->boolval = 0;
5454
341k
      break;
5455
#ifdef LIBXML_XPTR_LOCS_ENABLED
5456
  case XPATH_LOCATIONSET:
5457
  {
5458
      xmlLocationSetPtr loc = val->user;
5459
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460
      break;
5461
  }
5462
#endif
5463
0
        case XPATH_USERS:
5464
0
      ret->user = val->user;
5465
0
      break;
5466
0
        case XPATH_UNDEFINED:
5467
0
      xmlGenericError(xmlGenericErrorContext,
5468
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5469
0
        val->type);
5470
0
      break;
5471
345k
    }
5472
345k
    return(ret);
5473
345k
}
5474
5475
/**
5476
 * xmlXPathFreeObject:
5477
 * @obj:  the object to free
5478
 *
5479
 * Free up an xmlXPathObjectPtr object.
5480
 */
5481
void
5482
52.7M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483
52.7M
    if (obj == NULL) return;
5484
50.7M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485
24.1M
  if (obj->boolval) {
5486
#if 0
5487
      if (obj->user != NULL) {
5488
                xmlXPathFreeNodeSet(obj->nodesetval);
5489
    xmlFreeNodeList((xmlNodePtr) obj->user);
5490
      } else
5491
#endif
5492
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5493
0
      if (obj->nodesetval != NULL)
5494
0
    xmlXPathFreeValueTree(obj->nodesetval);
5495
24.1M
  } else {
5496
24.1M
      if (obj->nodesetval != NULL)
5497
22.7M
    xmlXPathFreeNodeSet(obj->nodesetval);
5498
24.1M
  }
5499
#ifdef LIBXML_XPTR_LOCS_ENABLED
5500
    } else if (obj->type == XPATH_LOCATIONSET) {
5501
  if (obj->user != NULL)
5502
      xmlXPtrFreeLocationSet(obj->user);
5503
#endif
5504
26.6M
    } else if (obj->type == XPATH_STRING) {
5505
15.8M
  if (obj->stringval != NULL)
5506
15.8M
      xmlFree(obj->stringval);
5507
15.8M
    }
5508
#ifdef XP_DEBUG_OBJ_USAGE
5509
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510
#endif
5511
50.7M
    xmlFree(obj);
5512
50.7M
}
5513
5514
static void
5515
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5516
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5517
0
}
5518
5519
/**
5520
 * xmlXPathReleaseObject:
5521
 * @obj:  the xmlXPathObjectPtr to free or to cache
5522
 *
5523
 * Depending on the state of the cache this frees the given
5524
 * XPath object or stores it in the cache.
5525
 */
5526
static void
5527
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5528
351M
{
5529
351M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5530
498k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5531
340M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5532
5533
431M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5534
5535
351M
    if (obj == NULL)
5536
0
  return;
5537
351M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5538
16.9k
   xmlXPathFreeObject(obj);
5539
351M
    } else {
5540
351M
  xmlXPathContextCachePtr cache =
5541
351M
      (xmlXPathContextCachePtr) ctxt->cache;
5542
5543
351M
  switch (obj->type) {
5544
206M
      case XPATH_NODESET:
5545
206M
      case XPATH_XSLT_TREE:
5546
206M
    if (obj->nodesetval != NULL) {
5547
183M
        if (obj->boolval) {
5548
      /*
5549
      * It looks like the @boolval is used for
5550
      * evaluation if this an XSLT Result Tree Fragment.
5551
      * TODO: Check if this assumption is correct.
5552
      */
5553
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5554
0
      xmlXPathFreeValueTree(obj->nodesetval);
5555
0
      obj->nodesetval = NULL;
5556
183M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5557
183M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5558
182M
          cache->maxNodeset)))
5559
107M
        {
5560
107M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5561
107M
      goto obj_cached;
5562
107M
        } else {
5563
75.7M
      xmlXPathFreeNodeSet(obj->nodesetval);
5564
75.7M
      obj->nodesetval = NULL;
5565
75.7M
        }
5566
183M
    }
5567
98.5M
    break;
5568
98.5M
      case XPATH_STRING:
5569
44.0M
    if (obj->stringval != NULL)
5570
44.0M
        xmlFree(obj->stringval);
5571
5572
44.0M
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5573
40.7M
        XP_CACHE_ADD(cache->stringObjs, obj);
5574
40.7M
        goto obj_cached;
5575
40.7M
    }
5576
3.22M
    break;
5577
41.9M
      case XPATH_BOOLEAN:
5578
41.9M
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5579
41.6M
        XP_CACHE_ADD(cache->booleanObjs, obj);
5580
41.6M
        goto obj_cached;
5581
41.6M
    }
5582
282k
    break;
5583
59.1M
      case XPATH_NUMBER:
5584
59.1M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5585
57.1M
        XP_CACHE_ADD(cache->numberObjs, obj);
5586
57.1M
        goto obj_cached;
5587
57.1M
    }
5588
1.97M
    break;
5589
#ifdef LIBXML_XPTR_LOCS_ENABLED
5590
      case XPATH_LOCATIONSET:
5591
    if (obj->user != NULL) {
5592
        xmlXPtrFreeLocationSet(obj->user);
5593
    }
5594
    goto free_obj;
5595
#endif
5596
1.97M
      default:
5597
40.6k
    goto free_obj;
5598
351M
  }
5599
5600
  /*
5601
  * Fallback to adding to the misc-objects slot.
5602
  */
5603
104M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5604
93.5M
      XP_CACHE_ADD(cache->miscObjs, obj);
5605
93.5M
  } else
5606
10.4M
      goto free_obj;
5607
5608
340M
obj_cached:
5609
5610
#ifdef XP_DEBUG_OBJ_USAGE
5611
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5612
#endif
5613
5614
340M
  if (obj->nodesetval != NULL) {
5615
107M
      xmlNodeSetPtr tmpset = obj->nodesetval;
5616
5617
      /*
5618
      * TODO: Due to those nasty ns-nodes, we need to traverse
5619
      *  the list and free the ns-nodes.
5620
      * URGENT TODO: Check if it's actually slowing things down.
5621
      *  Maybe we shouldn't try to preserve the list.
5622
      */
5623
107M
      if (tmpset->nodeNr > 1) {
5624
1.55M
    int i;
5625
1.55M
    xmlNodePtr node;
5626
5627
23.9M
    for (i = 0; i < tmpset->nodeNr; i++) {
5628
22.4M
        node = tmpset->nodeTab[i];
5629
22.4M
        if ((node != NULL) &&
5630
22.4M
      (node->type == XML_NAMESPACE_DECL))
5631
361k
        {
5632
361k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5633
361k
        }
5634
22.4M
    }
5635
105M
      } else if (tmpset->nodeNr == 1) {
5636
90.5M
    if ((tmpset->nodeTab[0] != NULL) &&
5637
90.5M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5638
4.14M
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5639
90.5M
      }
5640
107M
      tmpset->nodeNr = 0;
5641
107M
      memset(obj, 0, sizeof(xmlXPathObject));
5642
107M
      obj->nodesetval = tmpset;
5643
107M
  } else
5644
233M
      memset(obj, 0, sizeof(xmlXPathObject));
5645
5646
340M
  return;
5647
5648
10.5M
free_obj:
5649
  /*
5650
  * Cache is full; free the object.
5651
  */
5652
10.5M
  if (obj->nodesetval != NULL)
5653
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5654
#ifdef XP_DEBUG_OBJ_USAGE
5655
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5656
#endif
5657
10.5M
  xmlFree(obj);
5658
10.5M
    }
5659
10.5M
    return;
5660
351M
}
5661
5662
5663
/************************************************************************
5664
 *                  *
5665
 *      Type Casting Routines       *
5666
 *                  *
5667
 ************************************************************************/
5668
5669
/**
5670
 * xmlXPathCastBooleanToString:
5671
 * @val:  a boolean
5672
 *
5673
 * Converts a boolean to its string value.
5674
 *
5675
 * Returns a newly allocated string.
5676
 */
5677
xmlChar *
5678
594k
xmlXPathCastBooleanToString (int val) {
5679
594k
    xmlChar *ret;
5680
594k
    if (val)
5681
232k
  ret = xmlStrdup((const xmlChar *) "true");
5682
362k
    else
5683
362k
  ret = xmlStrdup((const xmlChar *) "false");
5684
594k
    return(ret);
5685
594k
}
5686
5687
/**
5688
 * xmlXPathCastNumberToString:
5689
 * @val:  a number
5690
 *
5691
 * Converts a number to its string value.
5692
 *
5693
 * Returns a newly allocated string.
5694
 */
5695
xmlChar *
5696
2.55M
xmlXPathCastNumberToString (double val) {
5697
2.55M
    xmlChar *ret;
5698
2.55M
    switch (xmlXPathIsInf(val)) {
5699
4.32k
    case 1:
5700
4.32k
  ret = xmlStrdup((const xmlChar *) "Infinity");
5701
4.32k
  break;
5702
8.04k
    case -1:
5703
8.04k
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5704
8.04k
  break;
5705
2.54M
    default:
5706
2.54M
  if (xmlXPathIsNaN(val)) {
5707
1.65M
      ret = xmlStrdup((const xmlChar *) "NaN");
5708
1.65M
  } else if (val == 0) {
5709
            /* Omit sign for negative zero. */
5710
206k
      ret = xmlStrdup((const xmlChar *) "0");
5711
684k
  } else {
5712
      /* could be improved */
5713
684k
      char buf[100];
5714
684k
      xmlXPathFormatNumber(val, buf, 99);
5715
684k
      buf[99] = 0;
5716
684k
      ret = xmlStrdup((const xmlChar *) buf);
5717
684k
  }
5718
2.55M
    }
5719
2.55M
    return(ret);
5720
2.55M
}
5721
5722
/**
5723
 * xmlXPathCastNodeToString:
5724
 * @node:  a node
5725
 *
5726
 * Converts a node to its string value.
5727
 *
5728
 * Returns a newly allocated string.
5729
 */
5730
xmlChar *
5731
28.5M
xmlXPathCastNodeToString (xmlNodePtr node) {
5732
28.5M
xmlChar *ret;
5733
28.5M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5734
0
  ret = xmlStrdup((const xmlChar *) "");
5735
28.5M
    return(ret);
5736
28.5M
}
5737
5738
/**
5739
 * xmlXPathCastNodeSetToString:
5740
 * @ns:  a node-set
5741
 *
5742
 * Converts a node-set to its string value.
5743
 *
5744
 * Returns a newly allocated string.
5745
 */
5746
xmlChar *
5747
40.4M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5748
40.4M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5749
29.9M
  return(xmlStrdup((const xmlChar *) ""));
5750
5751
10.4M
    if (ns->nodeNr > 1)
5752
1.62M
  xmlXPathNodeSetSort(ns);
5753
10.4M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5754
40.4M
}
5755
5756
/**
5757
 * xmlXPathCastToString:
5758
 * @val:  an XPath object
5759
 *
5760
 * Converts an existing object to its string() equivalent
5761
 *
5762
 * Returns the allocated string value of the object, NULL in case of error.
5763
 *         It's up to the caller to free the string memory with xmlFree().
5764
 */
5765
xmlChar *
5766
20.8M
xmlXPathCastToString(xmlXPathObjectPtr val) {
5767
20.8M
    xmlChar *ret = NULL;
5768
5769
20.8M
    if (val == NULL)
5770
0
  return(xmlStrdup((const xmlChar *) ""));
5771
20.8M
    switch (val->type) {
5772
0
  case XPATH_UNDEFINED:
5773
#ifdef DEBUG_EXPR
5774
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5775
#endif
5776
0
      ret = xmlStrdup((const xmlChar *) "");
5777
0
      break;
5778
1.12M
        case XPATH_NODESET:
5779
1.12M
        case XPATH_XSLT_TREE:
5780
1.12M
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5781
1.12M
      break;
5782
18.7M
  case XPATH_STRING:
5783
18.7M
      return(xmlStrdup(val->stringval));
5784
331k
        case XPATH_BOOLEAN:
5785
331k
      ret = xmlXPathCastBooleanToString(val->boolval);
5786
331k
      break;
5787
570k
  case XPATH_NUMBER: {
5788
570k
      ret = xmlXPathCastNumberToString(val->floatval);
5789
570k
      break;
5790
1.12M
  }
5791
2
  case XPATH_USERS:
5792
#ifdef LIBXML_XPTR_LOCS_ENABLED
5793
  case XPATH_POINT:
5794
  case XPATH_RANGE:
5795
  case XPATH_LOCATIONSET:
5796
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5797
2
      TODO
5798
2
      ret = xmlStrdup((const xmlChar *) "");
5799
2
      break;
5800
20.8M
    }
5801
2.02M
    return(ret);
5802
20.8M
}
5803
5804
/**
5805
 * xmlXPathConvertString:
5806
 * @val:  an XPath object
5807
 *
5808
 * Converts an existing object to its string() equivalent
5809
 *
5810
 * Returns the new object, the old one is freed (or the operation
5811
 *         is done directly on @val)
5812
 */
5813
xmlXPathObjectPtr
5814
190k
xmlXPathConvertString(xmlXPathObjectPtr val) {
5815
190k
    xmlChar *res = NULL;
5816
5817
190k
    if (val == NULL)
5818
0
  return(xmlXPathNewCString(""));
5819
5820
190k
    switch (val->type) {
5821
0
    case XPATH_UNDEFINED:
5822
#ifdef DEBUG_EXPR
5823
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5824
#endif
5825
0
  break;
5826
107k
    case XPATH_NODESET:
5827
107k
    case XPATH_XSLT_TREE:
5828
107k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5829
107k
  break;
5830
0
    case XPATH_STRING:
5831
0
  return(val);
5832
74.3k
    case XPATH_BOOLEAN:
5833
74.3k
  res = xmlXPathCastBooleanToString(val->boolval);
5834
74.3k
  break;
5835
8.22k
    case XPATH_NUMBER:
5836
8.22k
  res = xmlXPathCastNumberToString(val->floatval);
5837
8.22k
  break;
5838
0
    case XPATH_USERS:
5839
#ifdef LIBXML_XPTR_LOCS_ENABLED
5840
    case XPATH_POINT:
5841
    case XPATH_RANGE:
5842
    case XPATH_LOCATIONSET:
5843
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5844
0
  TODO;
5845
0
  break;
5846
190k
    }
5847
190k
    xmlXPathFreeObject(val);
5848
190k
    if (res == NULL)
5849
0
  return(xmlXPathNewCString(""));
5850
190k
    return(xmlXPathWrapString(res));
5851
190k
}
5852
5853
/**
5854
 * xmlXPathCastBooleanToNumber:
5855
 * @val:  a boolean
5856
 *
5857
 * Converts a boolean to its number value
5858
 *
5859
 * Returns the number value
5860
 */
5861
double
5862
8.80M
xmlXPathCastBooleanToNumber(int val) {
5863
8.80M
    if (val)
5864
569k
  return(1.0);
5865
8.23M
    return(0.0);
5866
8.80M
}
5867
5868
/**
5869
 * xmlXPathCastStringToNumber:
5870
 * @val:  a string
5871
 *
5872
 * Converts a string to its number value
5873
 *
5874
 * Returns the number value
5875
 */
5876
double
5877
55.0M
xmlXPathCastStringToNumber(const xmlChar * val) {
5878
55.0M
    return(xmlXPathStringEvalNumber(val));
5879
55.0M
}
5880
5881
/**
5882
 * xmlXPathCastNodeToNumber:
5883
 * @node:  a node
5884
 *
5885
 * Converts a node to its number value
5886
 *
5887
 * Returns the number value
5888
 */
5889
double
5890
7.62M
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5891
7.62M
    xmlChar *strval;
5892
7.62M
    double ret;
5893
5894
7.62M
    if (node == NULL)
5895
0
  return(xmlXPathNAN);
5896
7.62M
    strval = xmlXPathCastNodeToString(node);
5897
7.62M
    if (strval == NULL)
5898
0
  return(xmlXPathNAN);
5899
7.62M
    ret = xmlXPathCastStringToNumber(strval);
5900
7.62M
    xmlFree(strval);
5901
5902
7.62M
    return(ret);
5903
7.62M
}
5904
5905
/**
5906
 * xmlXPathCastNodeSetToNumber:
5907
 * @ns:  a node-set
5908
 *
5909
 * Converts a node-set to its number value
5910
 *
5911
 * Returns the number value
5912
 */
5913
double
5914
36.8M
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5915
36.8M
    xmlChar *str;
5916
36.8M
    double ret;
5917
5918
36.8M
    if (ns == NULL)
5919
2.65M
  return(xmlXPathNAN);
5920
34.1M
    str = xmlXPathCastNodeSetToString(ns);
5921
34.1M
    ret = xmlXPathCastStringToNumber(str);
5922
34.1M
    xmlFree(str);
5923
34.1M
    return(ret);
5924
36.8M
}
5925
5926
/**
5927
 * xmlXPathCastToNumber:
5928
 * @val:  an XPath object
5929
 *
5930
 * Converts an XPath object to its number value
5931
 *
5932
 * Returns the number value
5933
 */
5934
double
5935
64.7M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5936
64.7M
    double ret = 0.0;
5937
5938
64.7M
    if (val == NULL)
5939
0
  return(xmlXPathNAN);
5940
64.7M
    switch (val->type) {
5941
0
    case XPATH_UNDEFINED:
5942
#ifdef DEBUG_EXPR
5943
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5944
#endif
5945
0
  ret = xmlXPathNAN;
5946
0
  break;
5947
36.8M
    case XPATH_NODESET:
5948
36.8M
    case XPATH_XSLT_TREE:
5949
36.8M
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5950
36.8M
  break;
5951
12.9M
    case XPATH_STRING:
5952
12.9M
  ret = xmlXPathCastStringToNumber(val->stringval);
5953
12.9M
  break;
5954
6.13M
    case XPATH_NUMBER:
5955
6.13M
  ret = val->floatval;
5956
6.13M
  break;
5957
8.80M
    case XPATH_BOOLEAN:
5958
8.80M
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5959
8.80M
  break;
5960
14.6k
    case XPATH_USERS:
5961
#ifdef LIBXML_XPTR_LOCS_ENABLED
5962
    case XPATH_POINT:
5963
    case XPATH_RANGE:
5964
    case XPATH_LOCATIONSET:
5965
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5966
14.6k
  TODO;
5967
14.6k
  ret = xmlXPathNAN;
5968
14.6k
  break;
5969
64.7M
    }
5970
64.7M
    return(ret);
5971
64.7M
}
5972
5973
/**
5974
 * xmlXPathConvertNumber:
5975
 * @val:  an XPath object
5976
 *
5977
 * Converts an existing object to its number() equivalent
5978
 *
5979
 * Returns the new object, the old one is freed (or the operation
5980
 *         is done directly on @val)
5981
 */
5982
xmlXPathObjectPtr
5983
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5984
0
    xmlXPathObjectPtr ret;
5985
5986
0
    if (val == NULL)
5987
0
  return(xmlXPathNewFloat(0.0));
5988
0
    if (val->type == XPATH_NUMBER)
5989
0
  return(val);
5990
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5991
0
    xmlXPathFreeObject(val);
5992
0
    return(ret);
5993
0
}
5994
5995
/**
5996
 * xmlXPathCastNumberToBoolean:
5997
 * @val:  a number
5998
 *
5999
 * Converts a number to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
3.07M
xmlXPathCastNumberToBoolean (double val) {
6005
3.07M
     if (xmlXPathIsNaN(val) || (val == 0.0))
6006
1.99M
   return(0);
6007
1.08M
     return(1);
6008
3.07M
}
6009
6010
/**
6011
 * xmlXPathCastStringToBoolean:
6012
 * @val:  a string
6013
 *
6014
 * Converts a string to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
52.4k
xmlXPathCastStringToBoolean (const xmlChar *val) {
6020
52.4k
    if ((val == NULL) || (xmlStrlen(val) == 0))
6021
36.7k
  return(0);
6022
15.6k
    return(1);
6023
52.4k
}
6024
6025
/**
6026
 * xmlXPathCastNodeSetToBoolean:
6027
 * @ns:  a node-set
6028
 *
6029
 * Converts a node-set to its boolean value
6030
 *
6031
 * Returns the boolean value
6032
 */
6033
int
6034
4.84M
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6035
4.84M
    if ((ns == NULL) || (ns->nodeNr == 0))
6036
4.36M
  return(0);
6037
477k
    return(1);
6038
4.84M
}
6039
6040
/**
6041
 * xmlXPathCastToBoolean:
6042
 * @val:  an XPath object
6043
 *
6044
 * Converts an XPath object to its boolean value
6045
 *
6046
 * Returns the boolean value
6047
 */
6048
int
6049
6.61M
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6050
6.61M
    int ret = 0;
6051
6052
6.61M
    if (val == NULL)
6053
0
  return(0);
6054
6.61M
    switch (val->type) {
6055
0
    case XPATH_UNDEFINED:
6056
#ifdef DEBUG_EXPR
6057
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6058
#endif
6059
0
  ret = 0;
6060
0
  break;
6061
4.84M
    case XPATH_NODESET:
6062
4.84M
    case XPATH_XSLT_TREE:
6063
4.84M
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6064
4.84M
  break;
6065
52.4k
    case XPATH_STRING:
6066
52.4k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6067
52.4k
  break;
6068
1.71M
    case XPATH_NUMBER:
6069
1.71M
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6070
1.71M
  break;
6071
0
    case XPATH_BOOLEAN:
6072
0
  ret = val->boolval;
6073
0
  break;
6074
303
    case XPATH_USERS:
6075
#ifdef LIBXML_XPTR_LOCS_ENABLED
6076
    case XPATH_POINT:
6077
    case XPATH_RANGE:
6078
    case XPATH_LOCATIONSET:
6079
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6080
303
  TODO;
6081
303
  ret = 0;
6082
303
  break;
6083
6.61M
    }
6084
6.61M
    return(ret);
6085
6.61M
}
6086
6087
6088
/**
6089
 * xmlXPathConvertBoolean:
6090
 * @val:  an XPath object
6091
 *
6092
 * Converts an existing object to its boolean() equivalent
6093
 *
6094
 * Returns the new object, the old one is freed (or the operation
6095
 *         is done directly on @val)
6096
 */
6097
xmlXPathObjectPtr
6098
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6099
0
    xmlXPathObjectPtr ret;
6100
6101
0
    if (val == NULL)
6102
0
  return(xmlXPathNewBoolean(0));
6103
0
    if (val->type == XPATH_BOOLEAN)
6104
0
  return(val);
6105
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6106
0
    xmlXPathFreeObject(val);
6107
0
    return(ret);
6108
0
}
6109
6110
/************************************************************************
6111
 *                  *
6112
 *    Routines to handle XPath contexts     *
6113
 *                  *
6114
 ************************************************************************/
6115
6116
/**
6117
 * xmlXPathNewContext:
6118
 * @doc:  the XML document
6119
 *
6120
 * Create a new xmlXPathContext
6121
 *
6122
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6123
 */
6124
xmlXPathContextPtr
6125
70.3k
xmlXPathNewContext(xmlDocPtr doc) {
6126
70.3k
    xmlXPathContextPtr ret;
6127
6128
70.3k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6129
70.3k
    if (ret == NULL) {
6130
0
        xmlXPathErrMemory(NULL, "creating context\n");
6131
0
  return(NULL);
6132
0
    }
6133
70.3k
    memset(ret, 0 , sizeof(xmlXPathContext));
6134
70.3k
    ret->doc = doc;
6135
70.3k
    ret->node = NULL;
6136
6137
70.3k
    ret->varHash = NULL;
6138
6139
70.3k
    ret->nb_types = 0;
6140
70.3k
    ret->max_types = 0;
6141
70.3k
    ret->types = NULL;
6142
6143
70.3k
    ret->funcHash = xmlHashCreate(0);
6144
6145
70.3k
    ret->nb_axis = 0;
6146
70.3k
    ret->max_axis = 0;
6147
70.3k
    ret->axis = NULL;
6148
6149
70.3k
    ret->nsHash = NULL;
6150
70.3k
    ret->user = NULL;
6151
6152
70.3k
    ret->contextSize = -1;
6153
70.3k
    ret->proximityPosition = -1;
6154
6155
#ifdef XP_DEFAULT_CACHE_ON
6156
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6157
  xmlXPathFreeContext(ret);
6158
  return(NULL);
6159
    }
6160
#endif
6161
6162
70.3k
    xmlXPathRegisterAllFunctions(ret);
6163
6164
70.3k
    return(ret);
6165
70.3k
}
6166
6167
/**
6168
 * xmlXPathFreeContext:
6169
 * @ctxt:  the context to free
6170
 *
6171
 * Free up an xmlXPathContext
6172
 */
6173
void
6174
62.9k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175
62.9k
    if (ctxt == NULL) return;
6176
6177
62.9k
    if (ctxt->cache != NULL)
6178
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179
62.9k
    xmlXPathRegisteredNsCleanup(ctxt);
6180
62.9k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6181
62.9k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6182
62.9k
    xmlResetError(&ctxt->lastError);
6183
62.9k
    xmlFree(ctxt);
6184
62.9k
}
6185
6186
/************************************************************************
6187
 *                  *
6188
 *    Routines to handle XPath parser contexts    *
6189
 *                  *
6190
 ************************************************************************/
6191
6192
#define CHECK_CTXT(ctxt)            \
6193
998k
    if (ctxt == NULL) {           \
6194
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6195
0
    NULL, NULL, XML_FROM_XPATH,       \
6196
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6197
0
    __FILE__, __LINE__,         \
6198
0
    NULL, NULL, NULL, 0, 0,         \
6199
0
    "NULL context pointer\n");        \
6200
0
  return(NULL);             \
6201
0
    }                  \
6202
6203
#define CHECK_CTXT_NEG(ctxt)            \
6204
11.8M
    if (ctxt == NULL) {           \
6205
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6206
0
    NULL, NULL, XML_FROM_XPATH,       \
6207
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6208
0
    __FILE__, __LINE__,         \
6209
0
    NULL, NULL, NULL, 0, 0,         \
6210
0
    "NULL context pointer\n");        \
6211
0
  return(-1);             \
6212
0
    }                  \
6213
6214
6215
#define CHECK_CONTEXT(ctxt)           \
6216
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6217
        (ctxt->doc->children == NULL)) {        \
6218
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6219
  return(NULL);             \
6220
    }
6221
6222
6223
/**
6224
 * xmlXPathNewParserContext:
6225
 * @str:  the XPath expression
6226
 * @ctxt:  the XPath context
6227
 *
6228
 * Create a new xmlXPathParserContext
6229
 *
6230
 * Returns the xmlXPathParserContext just allocated.
6231
 */
6232
xmlXPathParserContextPtr
6233
9.37M
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234
9.37M
    xmlXPathParserContextPtr ret;
6235
6236
9.37M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6237
9.37M
    if (ret == NULL) {
6238
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6239
0
  return(NULL);
6240
0
    }
6241
9.37M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6242
9.37M
    ret->cur = ret->base = str;
6243
9.37M
    ret->context = ctxt;
6244
6245
9.37M
    ret->comp = xmlXPathNewCompExpr();
6246
9.37M
    if (ret->comp == NULL) {
6247
0
  xmlFree(ret->valueTab);
6248
0
  xmlFree(ret);
6249
0
  return(NULL);
6250
0
    }
6251
9.37M
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252
0
        ret->comp->dict = ctxt->dict;
6253
0
  xmlDictReference(ret->comp->dict);
6254
0
    }
6255
6256
9.37M
    return(ret);
6257
9.37M
}
6258
6259
/**
6260
 * xmlXPathCompParserContext:
6261
 * @comp:  the XPath compiled expression
6262
 * @ctxt:  the XPath context
6263
 *
6264
 * Create a new xmlXPathParserContext when processing a compiled expression
6265
 *
6266
 * Returns the xmlXPathParserContext just allocated.
6267
 */
6268
static xmlXPathParserContextPtr
6269
11.8M
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270
11.8M
    xmlXPathParserContextPtr ret;
6271
6272
11.8M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6273
11.8M
    if (ret == NULL) {
6274
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6275
0
  return(NULL);
6276
0
    }
6277
11.8M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6278
6279
    /* Allocate the value stack */
6280
11.8M
    ret->valueTab = (xmlXPathObjectPtr *)
6281
11.8M
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282
11.8M
    if (ret->valueTab == NULL) {
6283
0
  xmlFree(ret);
6284
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285
0
  return(NULL);
6286
0
    }
6287
11.8M
    ret->valueNr = 0;
6288
11.8M
    ret->valueMax = 10;
6289
11.8M
    ret->value = NULL;
6290
11.8M
    ret->valueFrame = 0;
6291
6292
11.8M
    ret->context = ctxt;
6293
11.8M
    ret->comp = comp;
6294
6295
11.8M
    return(ret);
6296
11.8M
}
6297
6298
/**
6299
 * xmlXPathFreeParserContext:
6300
 * @ctxt:  the context to free
6301
 *
6302
 * Free up an xmlXPathParserContext
6303
 */
6304
void
6305
21.1M
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6306
21.1M
    int i;
6307
6308
21.1M
    if (ctxt->valueTab != NULL) {
6309
17.4M
        for (i = 0; i < ctxt->valueNr; i++) {
6310
4.88M
            if (ctxt->context)
6311
4.88M
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6312
0
            else
6313
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6314
4.88M
        }
6315
12.5M
        xmlFree(ctxt->valueTab);
6316
12.5M
    }
6317
21.1M
    if (ctxt->comp != NULL) {
6318
4.02M
#ifdef XPATH_STREAMING
6319
4.02M
  if (ctxt->comp->stream != NULL) {
6320
162k
      xmlFreePatternList(ctxt->comp->stream);
6321
162k
      ctxt->comp->stream = NULL;
6322
162k
  }
6323
4.02M
#endif
6324
4.02M
  xmlXPathFreeCompExpr(ctxt->comp);
6325
4.02M
    }
6326
21.1M
    xmlFree(ctxt);
6327
21.1M
}
6328
6329
/************************************************************************
6330
 *                  *
6331
 *    The implicit core function library      *
6332
 *                  *
6333
 ************************************************************************/
6334
6335
/**
6336
 * xmlXPathNodeValHash:
6337
 * @node:  a node pointer
6338
 *
6339
 * Function computing the beginning of the string value of the node,
6340
 * used to speed up comparisons
6341
 *
6342
 * Returns an int usable as a hash
6343
 */
6344
static unsigned int
6345
4.33M
xmlXPathNodeValHash(xmlNodePtr node) {
6346
4.33M
    int len = 2;
6347
4.33M
    const xmlChar * string = NULL;
6348
4.33M
    xmlNodePtr tmp = NULL;
6349
4.33M
    unsigned int ret = 0;
6350
6351
4.33M
    if (node == NULL)
6352
0
  return(0);
6353
6354
4.33M
    if (node->type == XML_DOCUMENT_NODE) {
6355
662k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6356
662k
  if (tmp == NULL)
6357
39.4k
      node = node->children;
6358
622k
  else
6359
622k
      node = tmp;
6360
6361
662k
  if (node == NULL)
6362
24.4k
      return(0);
6363
662k
    }
6364
6365
4.30M
    switch (node->type) {
6366
54.5k
  case XML_COMMENT_NODE:
6367
134k
  case XML_PI_NODE:
6368
179k
  case XML_CDATA_SECTION_NODE:
6369
1.74M
  case XML_TEXT_NODE:
6370
1.74M
      string = node->content;
6371
1.74M
      if (string == NULL)
6372
0
    return(0);
6373
1.74M
      if (string[0] == 0)
6374
62.9k
    return(0);
6375
1.68M
      return(string[0] + (string[1] << 8));
6376
70.8k
  case XML_NAMESPACE_DECL:
6377
70.8k
      string = ((xmlNsPtr)node)->href;
6378
70.8k
      if (string == NULL)
6379
0
    return(0);
6380
70.8k
      if (string[0] == 0)
6381
0
    return(0);
6382
70.8k
      return(string[0] + (string[1] << 8));
6383
11.0k
  case XML_ATTRIBUTE_NODE:
6384
11.0k
      tmp = ((xmlAttrPtr) node)->children;
6385
11.0k
      break;
6386
2.47M
  case XML_ELEMENT_NODE:
6387
2.47M
      tmp = node->children;
6388
2.47M
      break;
6389
0
  default:
6390
0
      return(0);
6391
4.30M
    }
6392
3.78M
    while (tmp != NULL) {
6393
2.32M
  switch (tmp->type) {
6394
53.9k
      case XML_CDATA_SECTION_NODE:
6395
2.32M
      case XML_TEXT_NODE:
6396
2.32M
    string = tmp->content;
6397
2.32M
    break;
6398
0
      default:
6399
0
                string = NULL;
6400
0
    break;
6401
2.32M
  }
6402
2.32M
  if ((string != NULL) && (string[0] != 0)) {
6403
2.21M
      if (len == 1) {
6404
0
    return(ret + (string[0] << 8));
6405
0
      }
6406
2.21M
      if (string[1] == 0) {
6407
1.18M
    len = 1;
6408
1.18M
    ret = string[0];
6409
1.18M
      } else {
6410
1.03M
    return(string[0] + (string[1] << 8));
6411
1.03M
      }
6412
2.21M
  }
6413
  /*
6414
   * Skip to next node
6415
   */
6416
1.28M
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6417
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6418
0
    tmp = tmp->children;
6419
0
    continue;
6420
0
      }
6421
0
  }
6422
1.28M
  if (tmp == node)
6423
0
      break;
6424
6425
1.28M
  if (tmp->next != NULL) {
6426
0
      tmp = tmp->next;
6427
0
      continue;
6428
0
  }
6429
6430
1.28M
  do {
6431
1.28M
      tmp = tmp->parent;
6432
1.28M
      if (tmp == NULL)
6433
0
    break;
6434
1.28M
      if (tmp == node) {
6435
1.28M
    tmp = NULL;
6436
1.28M
    break;
6437
1.28M
      }
6438
0
      if (tmp->next != NULL) {
6439
0
    tmp = tmp->next;
6440
0
    break;
6441
0
      }
6442
0
  } while (tmp != NULL);
6443
1.28M
    }
6444
1.45M
    return(ret);
6445
2.49M
}
6446
6447
/**
6448
 * xmlXPathStringHash:
6449
 * @string:  a string
6450
 *
6451
 * Function computing the beginning of the string value of the node,
6452
 * used to speed up comparisons
6453
 *
6454
 * Returns an int usable as a hash
6455
 */
6456
static unsigned int
6457
1.09M
xmlXPathStringHash(const xmlChar * string) {
6458
1.09M
    if (string == NULL)
6459
0
  return(0);
6460
1.09M
    if (string[0] == 0)
6461
740k
  return(0);
6462
355k
    return(string[0] + (string[1] << 8));
6463
1.09M
}
6464
6465
/**
6466
 * xmlXPathCompareNodeSetFloat:
6467
 * @ctxt:  the XPath Parser context
6468
 * @inf:  less than (1) or greater than (0)
6469
 * @strict:  is the comparison strict
6470
 * @arg:  the node set
6471
 * @f:  the value
6472
 *
6473
 * Implement the compare operation between a nodeset and a number
6474
 *     @ns < @val    (1, 1, ...
6475
 *     @ns <= @val   (1, 0, ...
6476
 *     @ns > @val    (0, 1, ...
6477
 *     @ns >= @val   (0, 0, ...
6478
 *
6479
 * If one object to be compared is a node-set and the other is a number,
6480
 * then the comparison will be true if and only if there is a node in the
6481
 * node-set such that the result of performing the comparison on the number
6482
 * to be compared and on the result of converting the string-value of that
6483
 * node to a number using the number function is true.
6484
 *
6485
 * Returns 0 or 1 depending on the results of the test.
6486
 */
6487
static int
6488
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6489
5.69M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6490
5.69M
    int i, ret = 0;
6491
5.69M
    xmlNodeSetPtr ns;
6492
5.69M
    xmlChar *str2;
6493
6494
5.69M
    if ((f == NULL) || (arg == NULL) ||
6495
5.69M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6496
0
  xmlXPathReleaseObject(ctxt->context, arg);
6497
0
  xmlXPathReleaseObject(ctxt->context, f);
6498
0
        return(0);
6499
0
    }
6500
5.69M
    ns = arg->nodesetval;
6501
5.69M
    if (ns != NULL) {
6502
9.15M
  for (i = 0;i < ns->nodeNr;i++) {
6503
3.72M
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6504
3.72M
       if (str2 != NULL) {
6505
3.72M
     valuePush(ctxt,
6506
3.72M
         xmlXPathCacheNewString(ctxt->context, str2));
6507
3.72M
     xmlFree(str2);
6508
3.72M
     xmlXPathNumberFunction(ctxt, 1);
6509
3.72M
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6510
3.72M
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6511
3.72M
     if (ret)
6512
64.1k
         break;
6513
3.72M
       }
6514
3.72M
  }
6515
5.49M
    }
6516
5.69M
    xmlXPathReleaseObject(ctxt->context, arg);
6517
5.69M
    xmlXPathReleaseObject(ctxt->context, f);
6518
5.69M
    return(ret);
6519
5.69M
}
6520
6521
/**
6522
 * xmlXPathCompareNodeSetString:
6523
 * @ctxt:  the XPath Parser context
6524
 * @inf:  less than (1) or greater than (0)
6525
 * @strict:  is the comparison strict
6526
 * @arg:  the node set
6527
 * @s:  the value
6528
 *
6529
 * Implement the compare operation between a nodeset and a string
6530
 *     @ns < @val    (1, 1, ...
6531
 *     @ns <= @val   (1, 0, ...
6532
 *     @ns > @val    (0, 1, ...
6533
 *     @ns >= @val   (0, 0, ...
6534
 *
6535
 * If one object to be compared is a node-set and the other is a string,
6536
 * then the comparison will be true if and only if there is a node in
6537
 * the node-set such that the result of performing the comparison on the
6538
 * string-value of the node and the other string is true.
6539
 *
6540
 * Returns 0 or 1 depending on the results of the test.
6541
 */
6542
static int
6543
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6544
1.35M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6545
1.35M
    int i, ret = 0;
6546
1.35M
    xmlNodeSetPtr ns;
6547
1.35M
    xmlChar *str2;
6548
6549
1.35M
    if ((s == NULL) || (arg == NULL) ||
6550
1.35M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6551
0
  xmlXPathReleaseObject(ctxt->context, arg);
6552
0
  xmlXPathReleaseObject(ctxt->context, s);
6553
0
        return(0);
6554
0
    }
6555
1.35M
    ns = arg->nodesetval;
6556
1.35M
    if (ns != NULL) {
6557
1.39M
  for (i = 0;i < ns->nodeNr;i++) {
6558
312k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6559
312k
       if (str2 != NULL) {
6560
312k
     valuePush(ctxt,
6561
312k
         xmlXPathCacheNewString(ctxt->context, str2));
6562
312k
     xmlFree(str2);
6563
312k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6564
312k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6565
312k
     if (ret)
6566
49.4k
         break;
6567
312k
       }
6568
312k
  }
6569
1.12M
    }
6570
1.35M
    xmlXPathReleaseObject(ctxt->context, arg);
6571
1.35M
    xmlXPathReleaseObject(ctxt->context, s);
6572
1.35M
    return(ret);
6573
1.35M
}
6574
6575
/**
6576
 * xmlXPathCompareNodeSets:
6577
 * @inf:  less than (1) or greater than (0)
6578
 * @strict:  is the comparison strict
6579
 * @arg1:  the first node set object
6580
 * @arg2:  the second node set object
6581
 *
6582
 * Implement the compare operation on nodesets:
6583
 *
6584
 * If both objects to be compared are node-sets, then the comparison
6585
 * will be true if and only if there is a node in the first node-set
6586
 * and a node in the second node-set such that the result of performing
6587
 * the comparison on the string-values of the two nodes is true.
6588
 * ....
6589
 * When neither object to be compared is a node-set and the operator
6590
 * is <=, <, >= or >, then the objects are compared by converting both
6591
 * objects to numbers and comparing the numbers according to IEEE 754.
6592
 * ....
6593
 * The number function converts its argument to a number as follows:
6594
 *  - a string that consists of optional whitespace followed by an
6595
 *    optional minus sign followed by a Number followed by whitespace
6596
 *    is converted to the IEEE 754 number that is nearest (according
6597
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6598
 *    represented by the string; any other string is converted to NaN
6599
 *
6600
 * Conclusion all nodes need to be converted first to their string value
6601
 * and then the comparison must be done when possible
6602
 */
6603
static int
6604
xmlXPathCompareNodeSets(int inf, int strict,
6605
6.55M
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6606
6.55M
    int i, j, init = 0;
6607
6.55M
    double val1;
6608
6.55M
    double *values2;
6609
6.55M
    int ret = 0;
6610
6.55M
    xmlNodeSetPtr ns1;
6611
6.55M
    xmlNodeSetPtr ns2;
6612
6613
6.55M
    if ((arg1 == NULL) ||
6614
6.55M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6615
0
  xmlXPathFreeObject(arg2);
6616
0
        return(0);
6617
0
    }
6618
6.55M
    if ((arg2 == NULL) ||
6619
6.55M
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6620
0
  xmlXPathFreeObject(arg1);
6621
0
  xmlXPathFreeObject(arg2);
6622
0
        return(0);
6623
0
    }
6624
6625
6.55M
    ns1 = arg1->nodesetval;
6626
6.55M
    ns2 = arg2->nodesetval;
6627
6628
6.55M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6629
4.76M
  xmlXPathFreeObject(arg1);
6630
4.76M
  xmlXPathFreeObject(arg2);
6631
4.76M
  return(0);
6632
4.76M
    }
6633
1.78M
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6634
1.18M
  xmlXPathFreeObject(arg1);
6635
1.18M
  xmlXPathFreeObject(arg2);
6636
1.18M
  return(0);
6637
1.18M
    }
6638
6639
600k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6640
600k
    if (values2 == NULL) {
6641
        /* TODO: Propagate memory error. */
6642
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6643
0
  xmlXPathFreeObject(arg1);
6644
0
  xmlXPathFreeObject(arg2);
6645
0
  return(0);
6646
0
    }
6647
5.25M
    for (i = 0;i < ns1->nodeNr;i++) {
6648
4.73M
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6649
4.73M
  if (xmlXPathIsNaN(val1))
6650
4.36M
      continue;
6651
4.55M
  for (j = 0;j < ns2->nodeNr;j++) {
6652
4.25M
      if (init == 0) {
6653
1.76M
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6654
1.76M
      }
6655
4.25M
      if (xmlXPathIsNaN(values2[j]))
6656
3.61M
    continue;
6657
646k
      if (inf && strict)
6658
264k
    ret = (val1 < values2[j]);
6659
381k
      else if (inf && !strict)
6660
65.1k
    ret = (val1 <= values2[j]);
6661
316k
      else if (!inf && strict)
6662
203k
    ret = (val1 > values2[j]);
6663
112k
      else if (!inf && !strict)
6664
112k
    ret = (val1 >= values2[j]);
6665
646k
      if (ret)
6666
81.3k
    break;
6667
646k
  }
6668
375k
  if (ret)
6669
81.3k
      break;
6670
294k
  init = 1;
6671
294k
    }
6672
600k
    xmlFree(values2);
6673
600k
    xmlXPathFreeObject(arg1);
6674
600k
    xmlXPathFreeObject(arg2);
6675
600k
    return(ret);
6676
600k
}
6677
6678
/**
6679
 * xmlXPathCompareNodeSetValue:
6680
 * @ctxt:  the XPath Parser context
6681
 * @inf:  less than (1) or greater than (0)
6682
 * @strict:  is the comparison strict
6683
 * @arg:  the node set
6684
 * @val:  the value
6685
 *
6686
 * Implement the compare operation between a nodeset and a value
6687
 *     @ns < @val    (1, 1, ...
6688
 *     @ns <= @val   (1, 0, ...
6689
 *     @ns > @val    (0, 1, ...
6690
 *     @ns >= @val   (0, 0, ...
6691
 *
6692
 * If one object to be compared is a node-set and the other is a boolean,
6693
 * then the comparison will be true if and only if the result of performing
6694
 * the comparison on the boolean and on the result of converting
6695
 * the node-set to a boolean using the boolean function is true.
6696
 *
6697
 * Returns 0 or 1 depending on the results of the test.
6698
 */
6699
static int
6700
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6701
10.5M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6702
10.5M
    if ((val == NULL) || (arg == NULL) ||
6703
10.5M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6704
0
        return(0);
6705
6706
10.5M
    switch(val->type) {
6707
5.69M
        case XPATH_NUMBER:
6708
5.69M
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6709
0
        case XPATH_NODESET:
6710
0
        case XPATH_XSLT_TREE:
6711
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6712
1.35M
        case XPATH_STRING:
6713
1.35M
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6714
3.48M
        case XPATH_BOOLEAN:
6715
3.48M
      valuePush(ctxt, arg);
6716
3.48M
      xmlXPathBooleanFunction(ctxt, 1);
6717
3.48M
      valuePush(ctxt, val);
6718
3.48M
      return(xmlXPathCompareValues(ctxt, inf, strict));
6719
586
  default:
6720
586
            xmlGenericError(xmlGenericErrorContext,
6721
586
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6722
586
                    "and object of type %d\n",
6723
586
                    val->type);
6724
586
            xmlXPathReleaseObject(ctxt->context, arg);
6725
586
            xmlXPathReleaseObject(ctxt->context, val);
6726
586
            XP_ERROR0(XPATH_INVALID_TYPE);
6727
10.5M
    }
6728
0
    return(0);
6729
10.5M
}
6730
6731
/**
6732
 * xmlXPathEqualNodeSetString:
6733
 * @arg:  the nodeset object argument
6734
 * @str:  the string to compare to.
6735
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6736
 *
6737
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6738
 * If one object to be compared is a node-set and the other is a string,
6739
 * then the comparison will be true if and only if there is a node in
6740
 * the node-set such that the result of performing the comparison on the
6741
 * string-value of the node and the other string is true.
6742
 *
6743
 * Returns 0 or 1 depending on the results of the test.
6744
 */
6745
static int
6746
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6747
1.70M
{
6748
1.70M
    int i;
6749
1.70M
    xmlNodeSetPtr ns;
6750
1.70M
    xmlChar *str2;
6751
1.70M
    unsigned int hash;
6752
6753
1.70M
    if ((str == NULL) || (arg == NULL) ||
6754
1.70M
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6755
0
        return (0);
6756
1.70M
    ns = arg->nodesetval;
6757
    /*
6758
     * A NULL nodeset compared with a string is always false
6759
     * (since there is no node equal, and no node not equal)
6760
     */
6761
1.70M
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6762
606k
        return (0);
6763
1.09M
    hash = xmlXPathStringHash(str);
6764
3.05M
    for (i = 0; i < ns->nodeNr; i++) {
6765
2.17M
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6766
169k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6767
169k
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6768
138k
                xmlFree(str2);
6769
138k
    if (neq)
6770
39.2k
        continue;
6771
98.8k
                return (1);
6772
138k
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6773
0
    if (neq)
6774
0
        continue;
6775
0
                return (1);
6776
31.3k
            } else if (neq) {
6777
4.49k
    if (str2 != NULL)
6778
4.49k
        xmlFree(str2);
6779
4.49k
    return (1);
6780
4.49k
      }
6781
26.8k
            if (str2 != NULL)
6782
26.8k
                xmlFree(str2);
6783
2.00M
        } else if (neq)
6784
113k
      return (1);
6785
2.17M
    }
6786
879k
    return (0);
6787
1.09M
}
6788
6789
/**
6790
 * xmlXPathEqualNodeSetFloat:
6791
 * @arg:  the nodeset object argument
6792
 * @f:  the float to compare to
6793
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6794
 *
6795
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6796
 * If one object to be compared is a node-set and the other is a number,
6797
 * then the comparison will be true if and only if there is a node in
6798
 * the node-set such that the result of performing the comparison on the
6799
 * number to be compared and on the result of converting the string-value
6800
 * of that node to a number using the number function is true.
6801
 *
6802
 * Returns 0 or 1 depending on the results of the test.
6803
 */
6804
static int
6805
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6806
3.89M
    xmlXPathObjectPtr arg, double f, int neq) {
6807
3.89M
  int i, ret=0;
6808
3.89M
  xmlNodeSetPtr ns;
6809
3.89M
  xmlChar *str2;
6810
3.89M
  xmlXPathObjectPtr val;
6811
3.89M
  double v;
6812
6813
3.89M
    if ((arg == NULL) ||
6814
3.89M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6815
0
        return(0);
6816
6817
3.89M
    ns = arg->nodesetval;
6818
3.89M
    if (ns != NULL) {
6819
5.42M
  for (i=0;i<ns->nodeNr;i++) {
6820
1.98M
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6821
1.98M
      if (str2 != NULL) {
6822
1.98M
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6823
1.98M
    xmlFree(str2);
6824
1.98M
    xmlXPathNumberFunction(ctxt, 1);
6825
1.98M
    val = valuePop(ctxt);
6826
1.98M
    v = val->floatval;
6827
1.98M
    xmlXPathReleaseObject(ctxt->context, val);
6828
1.98M
    if (!xmlXPathIsNaN(v)) {
6829
112k
        if ((!neq) && (v==f)) {
6830
8.62k
      ret = 1;
6831
8.62k
      break;
6832
103k
        } else if ((neq) && (v!=f)) {
6833
5.97k
      ret = 1;
6834
5.97k
      break;
6835
5.97k
        }
6836
1.87M
    } else { /* NaN is unequal to any value */
6837
1.87M
        if (neq)
6838
591k
      ret = 1;
6839
1.87M
    }
6840
1.98M
      }
6841
1.98M
  }
6842
3.45M
    }
6843
6844
3.89M
    return(ret);
6845
3.89M
}
6846
6847
6848
/**
6849
 * xmlXPathEqualNodeSets:
6850
 * @arg1:  first nodeset object argument
6851
 * @arg2:  second nodeset object argument
6852
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6853
 *
6854
 * Implement the equal / not equal operation on XPath nodesets:
6855
 * @arg1 == @arg2  or  @arg1 != @arg2
6856
 * If both objects to be compared are node-sets, then the comparison
6857
 * will be true if and only if there is a node in the first node-set and
6858
 * a node in the second node-set such that the result of performing the
6859
 * comparison on the string-values of the two nodes is true.
6860
 *
6861
 * (needless to say, this is a costly operation)
6862
 *
6863
 * Returns 0 or 1 depending on the results of the test.
6864
 */
6865
static int
6866
2.42M
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6867
2.42M
    int i, j;
6868
2.42M
    unsigned int *hashs1;
6869
2.42M
    unsigned int *hashs2;
6870
2.42M
    xmlChar **values1;
6871
2.42M
    xmlChar **values2;
6872
2.42M
    int ret = 0;
6873
2.42M
    xmlNodeSetPtr ns1;
6874
2.42M
    xmlNodeSetPtr ns2;
6875
6876
2.42M
    if ((arg1 == NULL) ||
6877
2.42M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6878
0
        return(0);
6879
2.42M
    if ((arg2 == NULL) ||
6880
2.42M
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6881
0
        return(0);
6882
6883
2.42M
    ns1 = arg1->nodesetval;
6884
2.42M
    ns2 = arg2->nodesetval;
6885
6886
2.42M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6887
1.39M
  return(0);
6888
1.03M
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6889
337k
  return(0);
6890
6891
    /*
6892
     * for equal, check if there is a node pertaining to both sets
6893
     */
6894
694k
    if (neq == 0)
6895
1.73M
  for (i = 0;i < ns1->nodeNr;i++)
6896
4.68M
      for (j = 0;j < ns2->nodeNr;j++)
6897
3.44M
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6898
21.8k
        return(1);
6899
6900
672k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6901
672k
    if (values1 == NULL) {
6902
        /* TODO: Propagate memory error. */
6903
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6904
0
  return(0);
6905
0
    }
6906
672k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6907
672k
    if (hashs1 == NULL) {
6908
        /* TODO: Propagate memory error. */
6909
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910
0
  xmlFree(values1);
6911
0
  return(0);
6912
0
    }
6913
672k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6914
672k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6915
672k
    if (values2 == NULL) {
6916
        /* TODO: Propagate memory error. */
6917
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918
0
  xmlFree(hashs1);
6919
0
  xmlFree(values1);
6920
0
  return(0);
6921
0
    }
6922
672k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6923
672k
    if (hashs2 == NULL) {
6924
        /* TODO: Propagate memory error. */
6925
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926
0
  xmlFree(hashs1);
6927
0
  xmlFree(values1);
6928
0
  xmlFree(values2);
6929
0
  return(0);
6930
0
    }
6931
672k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932
1.36M
    for (i = 0;i < ns1->nodeNr;i++) {
6933
1.10M
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934
3.38M
  for (j = 0;j < ns2->nodeNr;j++) {
6935
2.69M
      if (i == 0)
6936
1.04M
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937
2.69M
      if (hashs1[i] != hashs2[j]) {
6938
1.60M
    if (neq) {
6939
81.3k
        ret = 1;
6940
81.3k
        break;
6941
81.3k
    }
6942
1.60M
      }
6943
1.08M
      else {
6944
1.08M
    if (values1[i] == NULL)
6945
617k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946
1.08M
    if (values2[j] == NULL)
6947
652k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948
1.08M
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949
1.08M
    if (ret)
6950
325k
        break;
6951
1.08M
      }
6952
2.69M
  }
6953
1.10M
  if (ret)
6954
406k
      break;
6955
1.10M
    }
6956
2.62M
    for (i = 0;i < ns1->nodeNr;i++)
6957
1.94M
  if (values1[i] != NULL)
6958
617k
      xmlFree(values1[i]);
6959
1.87M
    for (j = 0;j < ns2->nodeNr;j++)
6960
1.20M
  if (values2[j] != NULL)
6961
652k
      xmlFree(values2[j]);
6962
672k
    xmlFree(values1);
6963
672k
    xmlFree(values2);
6964
672k
    xmlFree(hashs1);
6965
672k
    xmlFree(hashs2);
6966
672k
    return(ret);
6967
672k
}
6968
6969
static int
6970
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971
4.38M
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972
4.38M
    int ret = 0;
6973
    /*
6974
     *At this point we are assured neither arg1 nor arg2
6975
     *is a nodeset, so we can just pick the appropriate routine.
6976
     */
6977
4.38M
    switch (arg1->type) {
6978
0
        case XPATH_UNDEFINED:
6979
#ifdef DEBUG_EXPR
6980
      xmlGenericError(xmlGenericErrorContext,
6981
        "Equal: undefined\n");
6982
#endif
6983
0
      break;
6984
2.01M
        case XPATH_BOOLEAN:
6985
2.01M
      switch (arg2->type) {
6986
0
          case XPATH_UNDEFINED:
6987
#ifdef DEBUG_EXPR
6988
        xmlGenericError(xmlGenericErrorContext,
6989
          "Equal: undefined\n");
6990
#endif
6991
0
        break;
6992
715k
    case XPATH_BOOLEAN:
6993
#ifdef DEBUG_EXPR
6994
        xmlGenericError(xmlGenericErrorContext,
6995
          "Equal: %d boolean %d \n",
6996
          arg1->boolval, arg2->boolval);
6997
#endif
6998
715k
        ret = (arg1->boolval == arg2->boolval);
6999
715k
        break;
7000
1.04M
    case XPATH_NUMBER:
7001
1.04M
        ret = (arg1->boolval ==
7002
1.04M
         xmlXPathCastNumberToBoolean(arg2->floatval));
7003
1.04M
        break;
7004
251k
    case XPATH_STRING:
7005
251k
        if ((arg2->stringval == NULL) ||
7006
251k
      (arg2->stringval[0] == 0)) ret = 0;
7007
49.2k
        else
7008
49.2k
      ret = 1;
7009
251k
        ret = (arg1->boolval == ret);
7010
251k
        break;
7011
5.63k
    case XPATH_USERS:
7012
#ifdef LIBXML_XPTR_LOCS_ENABLED
7013
    case XPATH_POINT:
7014
    case XPATH_RANGE:
7015
    case XPATH_LOCATIONSET:
7016
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7017
5.63k
        TODO
7018
5.63k
        break;
7019
0
    case XPATH_NODESET:
7020
0
    case XPATH_XSLT_TREE:
7021
0
        break;
7022
2.01M
      }
7023
2.01M
      break;
7024
2.01M
        case XPATH_NUMBER:
7025
1.80M
      switch (arg2->type) {
7026
0
          case XPATH_UNDEFINED:
7027
#ifdef DEBUG_EXPR
7028
        xmlGenericError(xmlGenericErrorContext,
7029
          "Equal: undefined\n");
7030
#endif
7031
0
        break;
7032
314k
    case XPATH_BOOLEAN:
7033
314k
        ret = (arg2->boolval==
7034
314k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7035
314k
        break;
7036
98.2k
    case XPATH_STRING:
7037
98.2k
        valuePush(ctxt, arg2);
7038
98.2k
        xmlXPathNumberFunction(ctxt, 1);
7039
98.2k
        arg2 = valuePop(ctxt);
7040
                    /* Falls through. */
7041
1.48M
    case XPATH_NUMBER:
7042
        /* Hand check NaN and Infinity equalities */
7043
1.48M
        if (xmlXPathIsNaN(arg1->floatval) ||
7044
1.48M
          xmlXPathIsNaN(arg2->floatval)) {
7045
1.05M
            ret = 0;
7046
1.05M
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047
4.48k
            if (xmlXPathIsInf(arg2->floatval) == 1)
7048
42
          ret = 1;
7049
4.44k
      else
7050
4.44k
          ret = 0;
7051
432k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052
76.6k
      if (xmlXPathIsInf(arg2->floatval) == -1)
7053
1
          ret = 1;
7054
76.6k
      else
7055
76.6k
          ret = 0;
7056
355k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057
9.89k
      if (xmlXPathIsInf(arg1->floatval) == 1)
7058
0
          ret = 1;
7059
9.89k
      else
7060
9.89k
          ret = 0;
7061
345k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062
27.2k
      if (xmlXPathIsInf(arg1->floatval) == -1)
7063
0
          ret = 1;
7064
27.2k
      else
7065
27.2k
          ret = 0;
7066
318k
        } else {
7067
318k
            ret = (arg1->floatval == arg2->floatval);
7068
318k
        }
7069
1.48M
        break;
7070
3.80k
    case XPATH_USERS:
7071
#ifdef LIBXML_XPTR_LOCS_ENABLED
7072
    case XPATH_POINT:
7073
    case XPATH_RANGE:
7074
    case XPATH_LOCATIONSET:
7075
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7076
3.80k
        TODO
7077
3.80k
        break;
7078
0
    case XPATH_NODESET:
7079
0
    case XPATH_XSLT_TREE:
7080
0
        break;
7081
1.80M
      }
7082
1.80M
      break;
7083
1.80M
        case XPATH_STRING:
7084
554k
      switch (arg2->type) {
7085
0
          case XPATH_UNDEFINED:
7086
#ifdef DEBUG_EXPR
7087
        xmlGenericError(xmlGenericErrorContext,
7088
          "Equal: undefined\n");
7089
#endif
7090
0
        break;
7091
192k
    case XPATH_BOOLEAN:
7092
192k
        if ((arg1->stringval == NULL) ||
7093
192k
      (arg1->stringval[0] == 0)) ret = 0;
7094
116k
        else
7095
116k
      ret = 1;
7096
192k
        ret = (arg2->boolval == ret);
7097
192k
        break;
7098
89.9k
    case XPATH_STRING:
7099
89.9k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7100
89.9k
        break;
7101
271k
    case XPATH_NUMBER:
7102
271k
        valuePush(ctxt, arg1);
7103
271k
        xmlXPathNumberFunction(ctxt, 1);
7104
271k
        arg1 = valuePop(ctxt);
7105
        /* Hand check NaN and Infinity equalities */
7106
271k
        if (xmlXPathIsNaN(arg1->floatval) ||
7107
271k
          xmlXPathIsNaN(arg2->floatval)) {
7108
259k
            ret = 0;
7109
259k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7110
566
      if (xmlXPathIsInf(arg2->floatval) == 1)
7111
0
          ret = 1;
7112
566
      else
7113
566
          ret = 0;
7114
11.2k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7115
558
      if (xmlXPathIsInf(arg2->floatval) == -1)
7116
0
          ret = 1;
7117
558
      else
7118
558
          ret = 0;
7119
10.6k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7120
816
      if (xmlXPathIsInf(arg1->floatval) == 1)
7121
0
          ret = 1;
7122
816
      else
7123
816
          ret = 0;
7124
9.85k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7125
286
      if (xmlXPathIsInf(arg1->floatval) == -1)
7126
0
          ret = 1;
7127
286
      else
7128
286
          ret = 0;
7129
9.56k
        } else {
7130
9.56k
            ret = (arg1->floatval == arg2->floatval);
7131
9.56k
        }
7132
271k
        break;
7133
813
    case XPATH_USERS:
7134
#ifdef LIBXML_XPTR_LOCS_ENABLED
7135
    case XPATH_POINT:
7136
    case XPATH_RANGE:
7137
    case XPATH_LOCATIONSET:
7138
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7139
813
        TODO
7140
813
        break;
7141
0
    case XPATH_NODESET:
7142
0
    case XPATH_XSLT_TREE:
7143
0
        break;
7144
554k
      }
7145
554k
      break;
7146
554k
        case XPATH_USERS:
7147
#ifdef LIBXML_XPTR_LOCS_ENABLED
7148
  case XPATH_POINT:
7149
  case XPATH_RANGE:
7150
  case XPATH_LOCATIONSET:
7151
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7152
489
      TODO
7153
489
      break;
7154
0
  case XPATH_NODESET:
7155
0
  case XPATH_XSLT_TREE:
7156
0
      break;
7157
4.38M
    }
7158
4.38M
    xmlXPathReleaseObject(ctxt->context, arg1);
7159
4.38M
    xmlXPathReleaseObject(ctxt->context, arg2);
7160
4.38M
    return(ret);
7161
4.38M
}
7162
7163
/**
7164
 * xmlXPathEqualValues:
7165
 * @ctxt:  the XPath Parser context
7166
 *
7167
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7168
 *
7169
 * Returns 0 or 1 depending on the results of the test.
7170
 */
7171
int
7172
15.8M
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7173
15.8M
    xmlXPathObjectPtr arg1, arg2, argtmp;
7174
15.8M
    int ret = 0;
7175
7176
15.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7177
15.8M
    arg2 = valuePop(ctxt);
7178
15.8M
    arg1 = valuePop(ctxt);
7179
15.8M
    if ((arg1 == NULL) || (arg2 == NULL)) {
7180
0
  if (arg1 != NULL)
7181
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7182
0
  else
7183
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7184
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7185
0
    }
7186
7187
15.8M
    if (arg1 == arg2) {
7188
#ifdef DEBUG_EXPR
7189
        xmlGenericError(xmlGenericErrorContext,
7190
    "Equal: by pointer\n");
7191
#endif
7192
0
  xmlXPathFreeObject(arg1);
7193
0
        return(1);
7194
0
    }
7195
7196
    /*
7197
     *If either argument is a nodeset, it's a 'special case'
7198
     */
7199
15.8M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7200
15.8M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7201
  /*
7202
   *Hack it to assure arg1 is the nodeset
7203
   */
7204
11.5M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7205
5.54M
    argtmp = arg2;
7206
5.54M
    arg2 = arg1;
7207
5.54M
    arg1 = argtmp;
7208
5.54M
  }
7209
11.5M
  switch (arg2->type) {
7210
0
      case XPATH_UNDEFINED:
7211
#ifdef DEBUG_EXPR
7212
    xmlGenericError(xmlGenericErrorContext,
7213
      "Equal: undefined\n");
7214
#endif
7215
0
    break;
7216
2.17M
      case XPATH_NODESET:
7217
2.17M
      case XPATH_XSLT_TREE:
7218
2.17M
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7219
2.17M
    break;
7220
4.78M
      case XPATH_BOOLEAN:
7221
4.78M
    if ((arg1->nodesetval == NULL) ||
7222
4.78M
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7223
503k
    else
7224
503k
        ret = 1;
7225
4.78M
    ret = (ret == arg2->boolval);
7226
4.78M
    break;
7227
3.06M
      case XPATH_NUMBER:
7228
3.06M
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7229
3.06M
    break;
7230
1.48M
      case XPATH_STRING:
7231
1.48M
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7232
1.48M
    break;
7233
2.94k
      case XPATH_USERS:
7234
#ifdef LIBXML_XPTR_LOCS_ENABLED
7235
      case XPATH_POINT:
7236
      case XPATH_RANGE:
7237
      case XPATH_LOCATIONSET:
7238
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7239
2.94k
    TODO
7240
2.94k
    break;
7241
11.5M
  }
7242
11.5M
  xmlXPathReleaseObject(ctxt->context, arg1);
7243
11.5M
  xmlXPathReleaseObject(ctxt->context, arg2);
7244
11.5M
  return(ret);
7245
11.5M
    }
7246
7247
4.32M
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248
15.8M
}
7249
7250
/**
7251
 * xmlXPathNotEqualValues:
7252
 * @ctxt:  the XPath Parser context
7253
 *
7254
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7255
 *
7256
 * Returns 0 or 1 depending on the results of the test.
7257
 */
7258
int
7259
1.42M
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260
1.42M
    xmlXPathObjectPtr arg1, arg2, argtmp;
7261
1.42M
    int ret = 0;
7262
7263
1.42M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264
1.42M
    arg2 = valuePop(ctxt);
7265
1.42M
    arg1 = valuePop(ctxt);
7266
1.42M
    if ((arg1 == NULL) || (arg2 == NULL)) {
7267
0
  if (arg1 != NULL)
7268
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7269
0
  else
7270
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7271
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7272
0
    }
7273
7274
1.42M
    if (arg1 == arg2) {
7275
#ifdef DEBUG_EXPR
7276
        xmlGenericError(xmlGenericErrorContext,
7277
    "NotEqual: by pointer\n");
7278
#endif
7279
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7280
0
        return(0);
7281
0
    }
7282
7283
    /*
7284
     *If either argument is a nodeset, it's a 'special case'
7285
     */
7286
1.42M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287
1.42M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288
  /*
7289
   *Hack it to assure arg1 is the nodeset
7290
   */
7291
1.37M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292
106k
    argtmp = arg2;
7293
106k
    arg2 = arg1;
7294
106k
    arg1 = argtmp;
7295
106k
  }
7296
1.37M
  switch (arg2->type) {
7297
0
      case XPATH_UNDEFINED:
7298
#ifdef DEBUG_EXPR
7299
    xmlGenericError(xmlGenericErrorContext,
7300
      "NotEqual: undefined\n");
7301
#endif
7302
0
    break;
7303
250k
      case XPATH_NODESET:
7304
250k
      case XPATH_XSLT_TREE:
7305
250k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306
250k
    break;
7307
76.8k
      case XPATH_BOOLEAN:
7308
76.8k
    if ((arg1->nodesetval == NULL) ||
7309
76.8k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7310
13.7k
    else
7311
13.7k
        ret = 1;
7312
76.8k
    ret = (ret != arg2->boolval);
7313
76.8k
    break;
7314
829k
      case XPATH_NUMBER:
7315
829k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316
829k
    break;
7317
216k
      case XPATH_STRING:
7318
216k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319
216k
    break;
7320
31
      case XPATH_USERS:
7321
#ifdef LIBXML_XPTR_LOCS_ENABLED
7322
      case XPATH_POINT:
7323
      case XPATH_RANGE:
7324
      case XPATH_LOCATIONSET:
7325
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7326
31
    TODO
7327
31
    break;
7328
1.37M
  }
7329
1.37M
  xmlXPathReleaseObject(ctxt->context, arg1);
7330
1.37M
  xmlXPathReleaseObject(ctxt->context, arg2);
7331
1.37M
  return(ret);
7332
1.37M
    }
7333
7334
54.7k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7335
1.42M
}
7336
7337
/**
7338
 * xmlXPathCompareValues:
7339
 * @ctxt:  the XPath Parser context
7340
 * @inf:  less than (1) or greater than (0)
7341
 * @strict:  is the comparison strict
7342
 *
7343
 * Implement the compare operation on XPath objects:
7344
 *     @arg1 < @arg2    (1, 1, ...
7345
 *     @arg1 <= @arg2   (1, 0, ...
7346
 *     @arg1 > @arg2    (0, 1, ...
7347
 *     @arg1 >= @arg2   (0, 0, ...
7348
 *
7349
 * When neither object to be compared is a node-set and the operator is
7350
 * <=, <, >=, >, then the objects are compared by converted both objects
7351
 * to numbers and comparing the numbers according to IEEE 754. The <
7352
 * comparison will be true if and only if the first number is less than the
7353
 * second number. The <= comparison will be true if and only if the first
7354
 * number is less than or equal to the second number. The > comparison
7355
 * will be true if and only if the first number is greater than the second
7356
 * number. The >= comparison will be true if and only if the first number
7357
 * is greater than or equal to the second number.
7358
 *
7359
 * Returns 1 if the comparison succeeded, 0 if it failed
7360
 */
7361
int
7362
27.5M
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7363
27.5M
    int ret = 0, arg1i = 0, arg2i = 0;
7364
27.5M
    xmlXPathObjectPtr arg1, arg2;
7365
7366
27.5M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7367
27.5M
    arg2 = valuePop(ctxt);
7368
27.5M
    arg1 = valuePop(ctxt);
7369
27.5M
    if ((arg1 == NULL) || (arg2 == NULL)) {
7370
0
  if (arg1 != NULL)
7371
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7372
0
  else
7373
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7374
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7375
0
    }
7376
7377
27.5M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7378
27.5M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7379
  /*
7380
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7381
   * are not freed from within this routine; they will be freed from the
7382
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7383
   */
7384
17.0M
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7385
17.0M
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7386
6.55M
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7387
10.5M
  } else {
7388
10.5M
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7389
4.31M
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7390
4.31M
                                arg1, arg2);
7391
6.22M
      } else {
7392
6.22M
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7393
6.22M
                                arg2, arg1);
7394
6.22M
      }
7395
10.5M
  }
7396
17.0M
  return(ret);
7397
17.0M
    }
7398
7399
10.4M
    if (arg1->type != XPATH_NUMBER) {
7400
5.02M
  valuePush(ctxt, arg1);
7401
5.02M
  xmlXPathNumberFunction(ctxt, 1);
7402
5.02M
  arg1 = valuePop(ctxt);
7403
5.02M
    }
7404
10.4M
    if (arg1->type != XPATH_NUMBER) {
7405
0
  xmlXPathFreeObject(arg1);
7406
0
  xmlXPathFreeObject(arg2);
7407
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7408
0
    }
7409
10.4M
    if (arg2->type != XPATH_NUMBER) {
7410
4.89M
  valuePush(ctxt, arg2);
7411
4.89M
  xmlXPathNumberFunction(ctxt, 1);
7412
4.89M
  arg2 = valuePop(ctxt);
7413
4.89M
    }
7414
10.4M
    if (arg2->type != XPATH_NUMBER) {
7415
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7416
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7417
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7418
0
    }
7419
    /*
7420
     * Add tests for infinity and nan
7421
     * => feedback on 3.4 for Inf and NaN
7422
     */
7423
    /* Hand check NaN and Infinity comparisons */
7424
10.4M
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7425
6.10M
  ret=0;
7426
6.10M
    } else {
7427
4.32M
  arg1i=xmlXPathIsInf(arg1->floatval);
7428
4.32M
  arg2i=xmlXPathIsInf(arg2->floatval);
7429
4.32M
  if (inf && strict) {
7430
2.10M
      if ((arg1i == -1 && arg2i != -1) ||
7431
2.10M
    (arg2i == 1 && arg1i != 1)) {
7432
14.8k
    ret = 1;
7433
2.08M
      } else if (arg1i == 0 && arg2i == 0) {
7434
2.08M
    ret = (arg1->floatval < arg2->floatval);
7435
2.08M
      } else {
7436
195
    ret = 0;
7437
195
      }
7438
2.10M
  }
7439
2.22M
  else if (inf && !strict) {
7440
70.8k
      if (arg1i == -1 || arg2i == 1) {
7441
5.97k
    ret = 1;
7442
64.8k
      } else if (arg1i == 0 && arg2i == 0) {
7443
64.8k
    ret = (arg1->floatval <= arg2->floatval);
7444
64.8k
      } else {
7445
0
    ret = 0;
7446
0
      }
7447
70.8k
  }
7448
2.15M
  else if (!inf && strict) {
7449
2.13M
      if ((arg1i == 1 && arg2i != 1) ||
7450
2.13M
    (arg2i == -1 && arg1i != -1)) {
7451
14.3k
    ret = 1;
7452
2.11M
      } else if (arg1i == 0 && arg2i == 0) {
7453
2.11M
    ret = (arg1->floatval > arg2->floatval);
7454
2.11M
      } else {
7455
352
    ret = 0;
7456
352
      }
7457
2.13M
  }
7458
21.1k
  else if (!inf && !strict) {
7459
21.1k
      if (arg1i == 1 || arg2i == -1) {
7460
5.62k
    ret = 1;
7461
15.4k
      } else if (arg1i == 0 && arg2i == 0) {
7462
15.4k
    ret = (arg1->floatval >= arg2->floatval);
7463
15.4k
      } else {
7464
1
    ret = 0;
7465
1
      }
7466
21.1k
  }
7467
4.32M
    }
7468
10.4M
    xmlXPathReleaseObject(ctxt->context, arg1);
7469
10.4M
    xmlXPathReleaseObject(ctxt->context, arg2);
7470
10.4M
    return(ret);
7471
10.4M
}
7472
7473
/**
7474
 * xmlXPathValueFlipSign:
7475
 * @ctxt:  the XPath Parser context
7476
 *
7477
 * Implement the unary - operation on an XPath object
7478
 * The numeric operators convert their operands to numbers as if
7479
 * by calling the number function.
7480
 */
7481
void
7482
1.05M
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7483
1.05M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7484
1.05M
    CAST_TO_NUMBER;
7485
1.05M
    CHECK_TYPE(XPATH_NUMBER);
7486
1.05M
    ctxt->value->floatval = -ctxt->value->floatval;
7487
1.05M
}
7488
7489
/**
7490
 * xmlXPathAddValues:
7491
 * @ctxt:  the XPath Parser context
7492
 *
7493
 * Implement the add operation on XPath objects:
7494
 * The numeric operators convert their operands to numbers as if
7495
 * by calling the number function.
7496
 */
7497
void
7498
5.42M
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7499
5.42M
    xmlXPathObjectPtr arg;
7500
5.42M
    double val;
7501
7502
5.42M
    arg = valuePop(ctxt);
7503
5.42M
    if (arg == NULL)
7504
5.42M
  XP_ERROR(XPATH_INVALID_OPERAND);
7505
5.42M
    val = xmlXPathCastToNumber(arg);
7506
5.42M
    xmlXPathReleaseObject(ctxt->context, arg);
7507
5.42M
    CAST_TO_NUMBER;
7508
5.42M
    CHECK_TYPE(XPATH_NUMBER);
7509
5.42M
    ctxt->value->floatval += val;
7510
5.42M
}
7511
7512
/**
7513
 * xmlXPathSubValues:
7514
 * @ctxt:  the XPath Parser context
7515
 *
7516
 * Implement the subtraction operation on XPath objects:
7517
 * The numeric operators convert their operands to numbers as if
7518
 * by calling the number function.
7519
 */
7520
void
7521
5.15M
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7522
5.15M
    xmlXPathObjectPtr arg;
7523
5.15M
    double val;
7524
7525
5.15M
    arg = valuePop(ctxt);
7526
5.15M
    if (arg == NULL)
7527
5.15M
  XP_ERROR(XPATH_INVALID_OPERAND);
7528
5.15M
    val = xmlXPathCastToNumber(arg);
7529
5.15M
    xmlXPathReleaseObject(ctxt->context, arg);
7530
5.15M
    CAST_TO_NUMBER;
7531
5.15M
    CHECK_TYPE(XPATH_NUMBER);
7532
5.15M
    ctxt->value->floatval -= val;
7533
5.15M
}
7534
7535
/**
7536
 * xmlXPathMultValues:
7537
 * @ctxt:  the XPath Parser context
7538
 *
7539
 * Implement the multiply operation on XPath objects:
7540
 * The numeric operators convert their operands to numbers as if
7541
 * by calling the number function.
7542
 */
7543
void
7544
17.6M
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7545
17.6M
    xmlXPathObjectPtr arg;
7546
17.6M
    double val;
7547
7548
17.6M
    arg = valuePop(ctxt);
7549
17.6M
    if (arg == NULL)
7550
17.6M
  XP_ERROR(XPATH_INVALID_OPERAND);
7551
17.6M
    val = xmlXPathCastToNumber(arg);
7552
17.6M
    xmlXPathReleaseObject(ctxt->context, arg);
7553
17.6M
    CAST_TO_NUMBER;
7554
17.6M
    CHECK_TYPE(XPATH_NUMBER);
7555
17.6M
    ctxt->value->floatval *= val;
7556
17.6M
}
7557
7558
/**
7559
 * xmlXPathDivValues:
7560
 * @ctxt:  the XPath Parser context
7561
 *
7562
 * Implement the div operation on XPath objects @arg1 / @arg2:
7563
 * The numeric operators convert their operands to numbers as if
7564
 * by calling the number function.
7565
 */
7566
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7567
void
7568
459k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7569
459k
    xmlXPathObjectPtr arg;
7570
459k
    double val;
7571
7572
459k
    arg = valuePop(ctxt);
7573
459k
    if (arg == NULL)
7574
459k
  XP_ERROR(XPATH_INVALID_OPERAND);
7575
459k
    val = xmlXPathCastToNumber(arg);
7576
459k
    xmlXPathReleaseObject(ctxt->context, arg);
7577
459k
    CAST_TO_NUMBER;
7578
459k
    CHECK_TYPE(XPATH_NUMBER);
7579
459k
    ctxt->value->floatval /= val;
7580
459k
}
7581
7582
/**
7583
 * xmlXPathModValues:
7584
 * @ctxt:  the XPath Parser context
7585
 *
7586
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7587
 * The numeric operators convert their operands to numbers as if
7588
 * by calling the number function.
7589
 */
7590
void
7591
317k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7592
317k
    xmlXPathObjectPtr arg;
7593
317k
    double arg1, arg2;
7594
7595
317k
    arg = valuePop(ctxt);
7596
317k
    if (arg == NULL)
7597
317k
  XP_ERROR(XPATH_INVALID_OPERAND);
7598
317k
    arg2 = xmlXPathCastToNumber(arg);
7599
317k
    xmlXPathReleaseObject(ctxt->context, arg);
7600
317k
    CAST_TO_NUMBER;
7601
317k
    CHECK_TYPE(XPATH_NUMBER);
7602
317k
    arg1 = ctxt->value->floatval;
7603
317k
    if (arg2 == 0)
7604
45.8k
  ctxt->value->floatval = xmlXPathNAN;
7605
271k
    else {
7606
271k
  ctxt->value->floatval = fmod(arg1, arg2);
7607
271k
    }
7608
317k
}
7609
7610
/************************************************************************
7611
 *                  *
7612
 *    The traversal functions         *
7613
 *                  *
7614
 ************************************************************************/
7615
7616
/*
7617
 * A traversal function enumerates nodes along an axis.
7618
 * Initially it must be called with NULL, and it indicates
7619
 * termination on the axis by returning NULL.
7620
 */
7621
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7622
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7623
7624
/*
7625
 * xmlXPathTraversalFunctionExt:
7626
 * A traversal function enumerates nodes along an axis.
7627
 * Initially it must be called with NULL, and it indicates
7628
 * termination on the axis by returning NULL.
7629
 * The context node of the traversal is specified via @contextNode.
7630
 */
7631
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7632
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7633
7634
/*
7635
 * xmlXPathNodeSetMergeFunction:
7636
 * Used for merging node sets in xmlXPathCollectAndTest().
7637
 */
7638
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7639
        (xmlNodeSetPtr, xmlNodeSetPtr);
7640
7641
7642
/**
7643
 * xmlXPathNextSelf:
7644
 * @ctxt:  the XPath Parser context
7645
 * @cur:  the current node in the traversal
7646
 *
7647
 * Traversal function for the "self" direction
7648
 * The self axis contains just the context node itself
7649
 *
7650
 * Returns the next element following that axis
7651
 */
7652
xmlNodePtr
7653
578k
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7654
578k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7655
578k
    if (cur == NULL)
7656
290k
        return(ctxt->context->node);
7657
287k
    return(NULL);
7658
578k
}
7659
7660
/**
7661
 * xmlXPathNextChild:
7662
 * @ctxt:  the XPath Parser context
7663
 * @cur:  the current node in the traversal
7664
 *
7665
 * Traversal function for the "child" direction
7666
 * The child axis contains the children of the context node in document order.
7667
 *
7668
 * Returns the next element following that axis
7669
 */
7670
xmlNodePtr
7671
61.9M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7672
61.9M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7673
61.9M
    if (cur == NULL) {
7674
29.6M
  if (ctxt->context->node == NULL) return(NULL);
7675
29.6M
  switch (ctxt->context->node->type) {
7676
10.2M
            case XML_ELEMENT_NODE:
7677
25.2M
            case XML_TEXT_NODE:
7678
25.7M
            case XML_CDATA_SECTION_NODE:
7679
25.7M
            case XML_ENTITY_REF_NODE:
7680
25.7M
            case XML_ENTITY_NODE:
7681
26.9M
            case XML_PI_NODE:
7682
28.0M
            case XML_COMMENT_NODE:
7683
28.0M
            case XML_NOTATION_NODE:
7684
28.0M
            case XML_DTD_NODE:
7685
28.0M
    return(ctxt->context->node->children);
7686
1.22M
            case XML_DOCUMENT_NODE:
7687
1.22M
            case XML_DOCUMENT_TYPE_NODE:
7688
1.22M
            case XML_DOCUMENT_FRAG_NODE:
7689
1.22M
            case XML_HTML_DOCUMENT_NODE:
7690
1.22M
    return(((xmlDocPtr) ctxt->context->node)->children);
7691
0
      case XML_ELEMENT_DECL:
7692
0
      case XML_ATTRIBUTE_DECL:
7693
0
      case XML_ENTITY_DECL:
7694
4.66k
            case XML_ATTRIBUTE_NODE:
7695
361k
      case XML_NAMESPACE_DECL:
7696
361k
      case XML_XINCLUDE_START:
7697
361k
      case XML_XINCLUDE_END:
7698
361k
    return(NULL);
7699
29.6M
  }
7700
0
  return(NULL);
7701
29.6M
    }
7702
32.2M
    if ((cur->type == XML_DOCUMENT_NODE) ||
7703
32.2M
        (cur->type == XML_HTML_DOCUMENT_NODE))
7704
0
  return(NULL);
7705
32.2M
    return(cur->next);
7706
32.2M
}
7707
7708
/**
7709
 * xmlXPathNextChildElement:
7710
 * @ctxt:  the XPath Parser context
7711
 * @cur:  the current node in the traversal
7712
 *
7713
 * Traversal function for the "child" direction and nodes of type element.
7714
 * The child axis contains the children of the context node in document order.
7715
 *
7716
 * Returns the next element following that axis
7717
 */
7718
static xmlNodePtr
7719
131M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7720
131M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7721
131M
    if (cur == NULL) {
7722
78.1M
  cur = ctxt->context->node;
7723
78.1M
  if (cur == NULL) return(NULL);
7724
  /*
7725
  * Get the first element child.
7726
  */
7727
78.1M
  switch (cur->type) {
7728
31.5M
            case XML_ELEMENT_NODE:
7729
31.5M
      case XML_DOCUMENT_FRAG_NODE:
7730
31.5M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7731
31.5M
            case XML_ENTITY_NODE:
7732
31.5M
    cur = cur->children;
7733
31.5M
    if (cur != NULL) {
7734
26.5M
        if (cur->type == XML_ELEMENT_NODE)
7735
0
      return(cur);
7736
26.5M
        do {
7737
26.5M
      cur = cur->next;
7738
26.5M
        } while ((cur != NULL) &&
7739
26.5M
      (cur->type != XML_ELEMENT_NODE));
7740
26.5M
        return(cur);
7741
26.5M
    }
7742
4.97M
    return(NULL);
7743
5.98M
            case XML_DOCUMENT_NODE:
7744
5.98M
            case XML_HTML_DOCUMENT_NODE:
7745
5.98M
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7746
40.6M
      default:
7747
40.6M
    return(NULL);
7748
78.1M
  }
7749
0
  return(NULL);
7750
78.1M
    }
7751
    /*
7752
    * Get the next sibling element node.
7753
    */
7754
52.9M
    switch (cur->type) {
7755
52.9M
  case XML_ELEMENT_NODE:
7756
52.9M
  case XML_TEXT_NODE:
7757
52.9M
  case XML_ENTITY_REF_NODE:
7758
52.9M
  case XML_ENTITY_NODE:
7759
52.9M
  case XML_CDATA_SECTION_NODE:
7760
52.9M
  case XML_PI_NODE:
7761
52.9M
  case XML_COMMENT_NODE:
7762
52.9M
  case XML_XINCLUDE_END:
7763
52.9M
      break;
7764
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7765
0
  default:
7766
0
      return(NULL);
7767
52.9M
    }
7768
52.9M
    if (cur->next != NULL) {
7769
49.4M
  if (cur->next->type == XML_ELEMENT_NODE)
7770
23.9M
      return(cur->next);
7771
25.5M
  cur = cur->next;
7772
40.7M
  do {
7773
40.7M
      cur = cur->next;
7774
40.7M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7775
25.5M
  return(cur);
7776
49.4M
    }
7777
3.49M
    return(NULL);
7778
52.9M
}
7779
7780
#if 0
7781
/**
7782
 * xmlXPathNextDescendantOrSelfElemParent:
7783
 * @ctxt:  the XPath Parser context
7784
 * @cur:  the current node in the traversal
7785
 *
7786
 * Traversal function for the "descendant-or-self" axis.
7787
 * Additionally it returns only nodes which can be parents of
7788
 * element nodes.
7789
 *
7790
 *
7791
 * Returns the next element following that axis
7792
 */
7793
static xmlNodePtr
7794
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7795
               xmlNodePtr contextNode)
7796
{
7797
    if (cur == NULL) {
7798
  if (contextNode == NULL)
7799
      return(NULL);
7800
  switch (contextNode->type) {
7801
      case XML_ELEMENT_NODE:
7802
      case XML_XINCLUDE_START:
7803
      case XML_DOCUMENT_FRAG_NODE:
7804
      case XML_DOCUMENT_NODE:
7805
      case XML_HTML_DOCUMENT_NODE:
7806
    return(contextNode);
7807
      default:
7808
    return(NULL);
7809
  }
7810
  return(NULL);
7811
    } else {
7812
  xmlNodePtr start = cur;
7813
7814
  while (cur != NULL) {
7815
      switch (cur->type) {
7816
    case XML_ELEMENT_NODE:
7817
    /* TODO: OK to have XInclude here? */
7818
    case XML_XINCLUDE_START:
7819
    case XML_DOCUMENT_FRAG_NODE:
7820
        if (cur != start)
7821
      return(cur);
7822
        if (cur->children != NULL) {
7823
      cur = cur->children;
7824
      continue;
7825
        }
7826
        break;
7827
    /* Not sure if we need those here. */
7828
    case XML_DOCUMENT_NODE:
7829
    case XML_HTML_DOCUMENT_NODE:
7830
        if (cur != start)
7831
      return(cur);
7832
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7833
    default:
7834
        break;
7835
      }
7836
7837
next_sibling:
7838
      if ((cur == NULL) || (cur == contextNode))
7839
    return(NULL);
7840
      if (cur->next != NULL) {
7841
    cur = cur->next;
7842
      } else {
7843
    cur = cur->parent;
7844
    goto next_sibling;
7845
      }
7846
  }
7847
    }
7848
    return(NULL);
7849
}
7850
#endif
7851
7852
/**
7853
 * xmlXPathNextDescendant:
7854
 * @ctxt:  the XPath Parser context
7855
 * @cur:  the current node in the traversal
7856
 *
7857
 * Traversal function for the "descendant" direction
7858
 * the descendant axis contains the descendants of the context node in document
7859
 * order; a descendant is a child or a child of a child and so on.
7860
 *
7861
 * Returns the next element following that axis
7862
 */
7863
xmlNodePtr
7864
173M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865
173M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866
173M
    if (cur == NULL) {
7867
3.85M
  if (ctxt->context->node == NULL)
7868
0
      return(NULL);
7869
3.85M
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870
3.85M
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871
71.1k
      return(NULL);
7872
7873
3.78M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874
1.52M
      return(ctxt->context->doc->children);
7875
2.25M
        return(ctxt->context->node->children);
7876
3.78M
    }
7877
7878
169M
    if (cur->type == XML_NAMESPACE_DECL)
7879
0
        return(NULL);
7880
169M
    if (cur->children != NULL) {
7881
  /*
7882
   * Do not descend on entities declarations
7883
   */
7884
51.8M
  if (cur->children->type != XML_ENTITY_DECL) {
7885
51.8M
      cur = cur->children;
7886
      /*
7887
       * Skip DTDs
7888
       */
7889
51.8M
      if (cur->type != XML_DTD_NODE)
7890
51.8M
    return(cur);
7891
51.8M
  }
7892
51.8M
    }
7893
7894
117M
    if (cur == ctxt->context->node) return(NULL);
7895
7896
116M
    while (cur->next != NULL) {
7897
66.6M
  cur = cur->next;
7898
66.6M
  if ((cur->type != XML_ENTITY_DECL) &&
7899
66.6M
      (cur->type != XML_DTD_NODE))
7900
66.6M
      return(cur);
7901
66.6M
    }
7902
7903
53.4M
    do {
7904
53.4M
        cur = cur->parent;
7905
53.4M
  if (cur == NULL) break;
7906
53.4M
  if (cur == ctxt->context->node) return(NULL);
7907
48.5M
  if (cur->next != NULL) {
7908
45.1M
      cur = cur->next;
7909
45.1M
      return(cur);
7910
45.1M
  }
7911
48.5M
    } while (cur != NULL);
7912
0
    return(cur);
7913
50.1M
}
7914
7915
/**
7916
 * xmlXPathNextDescendantOrSelf:
7917
 * @ctxt:  the XPath Parser context
7918
 * @cur:  the current node in the traversal
7919
 *
7920
 * Traversal function for the "descendant-or-self" direction
7921
 * the descendant-or-self axis contains the context node and the descendants
7922
 * of the context node in document order; thus the context node is the first
7923
 * node on the axis, and the first child of the context node is the second node
7924
 * on the axis
7925
 *
7926
 * Returns the next element following that axis
7927
 */
7928
xmlNodePtr
7929
112M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930
112M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931
112M
    if (cur == NULL)
7932
4.11M
        return(ctxt->context->node);
7933
7934
108M
    if (ctxt->context->node == NULL)
7935
0
        return(NULL);
7936
108M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7937
108M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7938
235k
        return(NULL);
7939
7940
107M
    return(xmlXPathNextDescendant(ctxt, cur));
7941
108M
}
7942
7943
/**
7944
 * xmlXPathNextParent:
7945
 * @ctxt:  the XPath Parser context
7946
 * @cur:  the current node in the traversal
7947
 *
7948
 * Traversal function for the "parent" direction
7949
 * The parent axis contains the parent of the context node, if there is one.
7950
 *
7951
 * Returns the next element following that axis
7952
 */
7953
xmlNodePtr
7954
5.79M
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955
5.79M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7956
    /*
7957
     * the parent of an attribute or namespace node is the element
7958
     * to which the attribute or namespace node is attached
7959
     * Namespace handling !!!
7960
     */
7961
5.79M
    if (cur == NULL) {
7962
3.02M
  if (ctxt->context->node == NULL) return(NULL);
7963
3.02M
  switch (ctxt->context->node->type) {
7964
1.09M
            case XML_ELEMENT_NODE:
7965
2.59M
            case XML_TEXT_NODE:
7966
2.63M
            case XML_CDATA_SECTION_NODE:
7967
2.63M
            case XML_ENTITY_REF_NODE:
7968
2.63M
            case XML_ENTITY_NODE:
7969
2.72M
            case XML_PI_NODE:
7970
2.81M
            case XML_COMMENT_NODE:
7971
2.81M
            case XML_NOTATION_NODE:
7972
2.81M
            case XML_DTD_NODE:
7973
2.81M
      case XML_ELEMENT_DECL:
7974
2.81M
      case XML_ATTRIBUTE_DECL:
7975
2.81M
      case XML_XINCLUDE_START:
7976
2.81M
      case XML_XINCLUDE_END:
7977
2.81M
      case XML_ENTITY_DECL:
7978
2.81M
    if (ctxt->context->node->parent == NULL)
7979
0
        return((xmlNodePtr) ctxt->context->doc);
7980
2.81M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981
2.81M
        ((ctxt->context->node->parent->name[0] == ' ') ||
7982
2.18M
         (xmlStrEqual(ctxt->context->node->parent->name,
7983
2.18M
         BAD_CAST "fake node libxslt"))))
7984
0
        return(NULL);
7985
2.81M
    return(ctxt->context->node->parent);
7986
29.4k
            case XML_ATTRIBUTE_NODE: {
7987
29.4k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989
29.4k
    return(att->parent);
7990
2.81M
      }
7991
83.8k
            case XML_DOCUMENT_NODE:
7992
83.8k
            case XML_DOCUMENT_TYPE_NODE:
7993
83.8k
            case XML_DOCUMENT_FRAG_NODE:
7994
83.8k
            case XML_HTML_DOCUMENT_NODE:
7995
83.8k
                return(NULL);
7996
94.7k
      case XML_NAMESPACE_DECL: {
7997
94.7k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7998
7999
94.7k
    if ((ns->next != NULL) &&
8000
94.7k
        (ns->next->type != XML_NAMESPACE_DECL))
8001
94.7k
        return((xmlNodePtr) ns->next);
8002
0
                return(NULL);
8003
94.7k
      }
8004
3.02M
  }
8005
3.02M
    }
8006
2.77M
    return(NULL);
8007
5.79M
}
8008
8009
/**
8010
 * xmlXPathNextAncestor:
8011
 * @ctxt:  the XPath Parser context
8012
 * @cur:  the current node in the traversal
8013
 *
8014
 * Traversal function for the "ancestor" direction
8015
 * the ancestor axis contains the ancestors of the context node; the ancestors
8016
 * of the context node consist of the parent of context node and the parent's
8017
 * parent and so on; the nodes are ordered in reverse document order; thus the
8018
 * parent is the first node on the axis, and the parent's parent is the second
8019
 * node on the axis
8020
 *
8021
 * Returns the next element following that axis
8022
 */
8023
xmlNodePtr
8024
18.7M
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8025
18.7M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8026
    /*
8027
     * the parent of an attribute or namespace node is the element
8028
     * to which the attribute or namespace node is attached
8029
     * !!!!!!!!!!!!!
8030
     */
8031
18.7M
    if (cur == NULL) {
8032
3.03M
  if (ctxt->context->node == NULL) return(NULL);
8033
3.03M
  switch (ctxt->context->node->type) {
8034
1.14M
            case XML_ELEMENT_NODE:
8035
2.58M
            case XML_TEXT_NODE:
8036
2.61M
            case XML_CDATA_SECTION_NODE:
8037
2.61M
            case XML_ENTITY_REF_NODE:
8038
2.61M
            case XML_ENTITY_NODE:
8039
2.66M
            case XML_PI_NODE:
8040
2.72M
            case XML_COMMENT_NODE:
8041
2.72M
      case XML_DTD_NODE:
8042
2.72M
      case XML_ELEMENT_DECL:
8043
2.72M
      case XML_ATTRIBUTE_DECL:
8044
2.72M
      case XML_ENTITY_DECL:
8045
2.72M
            case XML_NOTATION_NODE:
8046
2.72M
      case XML_XINCLUDE_START:
8047
2.72M
      case XML_XINCLUDE_END:
8048
2.72M
    if (ctxt->context->node->parent == NULL)
8049
0
        return((xmlNodePtr) ctxt->context->doc);
8050
2.72M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8051
2.72M
        ((ctxt->context->node->parent->name[0] == ' ') ||
8052
1.85M
         (xmlStrEqual(ctxt->context->node->parent->name,
8053
1.85M
         BAD_CAST "fake node libxslt"))))
8054
0
        return(NULL);
8055
2.72M
    return(ctxt->context->node->parent);
8056
14.2k
            case XML_ATTRIBUTE_NODE: {
8057
14.2k
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8058
8059
14.2k
    return(tmp->parent);
8060
2.72M
      }
8061
120k
            case XML_DOCUMENT_NODE:
8062
120k
            case XML_DOCUMENT_TYPE_NODE:
8063
120k
            case XML_DOCUMENT_FRAG_NODE:
8064
120k
            case XML_HTML_DOCUMENT_NODE:
8065
120k
                return(NULL);
8066
175k
      case XML_NAMESPACE_DECL: {
8067
175k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8068
8069
175k
    if ((ns->next != NULL) &&
8070
175k
        (ns->next->type != XML_NAMESPACE_DECL))
8071
175k
        return((xmlNodePtr) ns->next);
8072
    /* Bad, how did that namespace end up here ? */
8073
0
                return(NULL);
8074
175k
      }
8075
3.03M
  }
8076
0
  return(NULL);
8077
3.03M
    }
8078
15.6M
    if (cur == ctxt->context->doc->children)
8079
77.7k
  return((xmlNodePtr) ctxt->context->doc);
8080
15.6M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8081
5.80M
  return(NULL);
8082
9.81M
    switch (cur->type) {
8083
7.79M
  case XML_ELEMENT_NODE:
8084
9.28M
  case XML_TEXT_NODE:
8085
9.33M
  case XML_CDATA_SECTION_NODE:
8086
9.33M
  case XML_ENTITY_REF_NODE:
8087
9.33M
  case XML_ENTITY_NODE:
8088
9.37M
  case XML_PI_NODE:
8089
9.45M
  case XML_COMMENT_NODE:
8090
9.45M
  case XML_NOTATION_NODE:
8091
9.45M
  case XML_DTD_NODE:
8092
9.45M
        case XML_ELEMENT_DECL:
8093
9.45M
        case XML_ATTRIBUTE_DECL:
8094
9.45M
        case XML_ENTITY_DECL:
8095
9.45M
  case XML_XINCLUDE_START:
8096
9.45M
  case XML_XINCLUDE_END:
8097
9.45M
      if (cur->parent == NULL)
8098
0
    return(NULL);
8099
9.45M
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8100
9.45M
    ((cur->parent->name[0] == ' ') ||
8101
4.48M
     (xmlStrEqual(cur->parent->name,
8102
4.48M
            BAD_CAST "fake node libxslt"))))
8103
0
    return(NULL);
8104
9.45M
      return(cur->parent);
8105
37.2k
  case XML_ATTRIBUTE_NODE: {
8106
37.2k
      xmlAttrPtr att = (xmlAttrPtr) cur;
8107
8108
37.2k
      return(att->parent);
8109
9.45M
  }
8110
142k
  case XML_NAMESPACE_DECL: {
8111
142k
      xmlNsPtr ns = (xmlNsPtr) cur;
8112
8113
142k
      if ((ns->next != NULL) &&
8114
142k
          (ns->next->type != XML_NAMESPACE_DECL))
8115
142k
          return((xmlNodePtr) ns->next);
8116
      /* Bad, how did that namespace end up here ? */
8117
0
            return(NULL);
8118
142k
  }
8119
179k
  case XML_DOCUMENT_NODE:
8120
179k
  case XML_DOCUMENT_TYPE_NODE:
8121
179k
  case XML_DOCUMENT_FRAG_NODE:
8122
179k
  case XML_HTML_DOCUMENT_NODE:
8123
179k
      return(NULL);
8124
9.81M
    }
8125
0
    return(NULL);
8126
9.81M
}
8127
8128
/**
8129
 * xmlXPathNextAncestorOrSelf:
8130
 * @ctxt:  the XPath Parser context
8131
 * @cur:  the current node in the traversal
8132
 *
8133
 * Traversal function for the "ancestor-or-self" direction
8134
 * he ancestor-or-self axis contains the context node and ancestors of
8135
 * the context node in reverse document order; thus the context node is
8136
 * the first node on the axis, and the context node's parent the second;
8137
 * parent here is defined the same as with the parent axis.
8138
 *
8139
 * Returns the next element following that axis
8140
 */
8141
xmlNodePtr
8142
12.9M
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8143
12.9M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8144
12.9M
    if (cur == NULL)
8145
3.13M
        return(ctxt->context->node);
8146
9.81M
    return(xmlXPathNextAncestor(ctxt, cur));
8147
12.9M
}
8148
8149
/**
8150
 * xmlXPathNextFollowingSibling:
8151
 * @ctxt:  the XPath Parser context
8152
 * @cur:  the current node in the traversal
8153
 *
8154
 * Traversal function for the "following-sibling" direction
8155
 * The following-sibling axis contains the following siblings of the context
8156
 * node in document order.
8157
 *
8158
 * Returns the next element following that axis
8159
 */
8160
xmlNodePtr
8161
3.16M
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8162
3.16M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163
3.16M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8164
3.16M
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8165
63.5k
  return(NULL);
8166
3.10M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8167
0
        return(NULL);
8168
3.10M
    if (cur == NULL)
8169
320k
        return(ctxt->context->node->next);
8170
2.78M
    return(cur->next);
8171
3.10M
}
8172
8173
/**
8174
 * xmlXPathNextPrecedingSibling:
8175
 * @ctxt:  the XPath Parser context
8176
 * @cur:  the current node in the traversal
8177
 *
8178
 * Traversal function for the "preceding-sibling" direction
8179
 * The preceding-sibling axis contains the preceding siblings of the context
8180
 * node in reverse document order; the first preceding sibling is first on the
8181
 * axis; the sibling preceding that node is the second on the axis and so on.
8182
 *
8183
 * Returns the next element following that axis
8184
 */
8185
xmlNodePtr
8186
10.8M
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8187
10.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8188
10.8M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8189
10.8M
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8190
64.3k
  return(NULL);
8191
10.7M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8192
0
        return(NULL);
8193
10.7M
    if (cur == NULL)
8194
1.35M
        return(ctxt->context->node->prev);
8195
9.42M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8196
0
  cur = cur->prev;
8197
0
  if (cur == NULL)
8198
0
      return(ctxt->context->node->prev);
8199
0
    }
8200
9.42M
    return(cur->prev);
8201
9.42M
}
8202
8203
/**
8204
 * xmlXPathNextFollowing:
8205
 * @ctxt:  the XPath Parser context
8206
 * @cur:  the current node in the traversal
8207
 *
8208
 * Traversal function for the "following" direction
8209
 * The following axis contains all nodes in the same document as the context
8210
 * node that are after the context node in document order, excluding any
8211
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8212
 * are ordered in document order
8213
 *
8214
 * Returns the next element following that axis
8215
 */
8216
xmlNodePtr
8217
19.7M
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8218
19.7M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219
19.7M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8220
19.7M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8221
6.25M
        return(cur->children);
8222
8223
13.4M
    if (cur == NULL) {
8224
638k
        cur = ctxt->context->node;
8225
638k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8226
16.0k
            cur = cur->parent;
8227
622k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8228
48.0k
            xmlNsPtr ns = (xmlNsPtr) cur;
8229
8230
48.0k
            if ((ns->next == NULL) ||
8231
48.0k
                (ns->next->type == XML_NAMESPACE_DECL))
8232
0
                return (NULL);
8233
48.0k
            cur = (xmlNodePtr) ns->next;
8234
48.0k
        }
8235
638k
    }
8236
13.4M
    if (cur == NULL) return(NULL) ; /* ERROR */
8237
13.4M
    if (cur->next != NULL) return(cur->next) ;
8238
7.81M
    do {
8239
7.81M
        cur = cur->parent;
8240
7.81M
        if (cur == NULL) break;
8241
7.77M
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8242
7.18M
        if (cur->next != NULL) return(cur->next);
8243
7.18M
    } while (cur != NULL);
8244
34.9k
    return(cur);
8245
6.99M
}
8246
8247
/*
8248
 * xmlXPathIsAncestor:
8249
 * @ancestor:  the ancestor node
8250
 * @node:  the current node
8251
 *
8252
 * Check that @ancestor is a @node's ancestor
8253
 *
8254
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8255
 */
8256
static int
8257
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8258
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8259
0
    if (node->type == XML_NAMESPACE_DECL)
8260
0
        return(0);
8261
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8262
0
        return(0);
8263
    /* nodes need to be in the same document */
8264
0
    if (ancestor->doc != node->doc) return(0);
8265
    /* avoid searching if ancestor or node is the root node */
8266
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8267
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8268
0
    while (node->parent != NULL) {
8269
0
        if (node->parent == ancestor)
8270
0
            return(1);
8271
0
  node = node->parent;
8272
0
    }
8273
0
    return(0);
8274
0
}
8275
8276
/**
8277
 * xmlXPathNextPreceding:
8278
 * @ctxt:  the XPath Parser context
8279
 * @cur:  the current node in the traversal
8280
 *
8281
 * Traversal function for the "preceding" direction
8282
 * the preceding axis contains all nodes in the same document as the context
8283
 * node that are before the context node in document order, excluding any
8284
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8285
 * ordered in reverse document order
8286
 *
8287
 * Returns the next element following that axis
8288
 */
8289
xmlNodePtr
8290
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8291
0
{
8292
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8293
0
    if (cur == NULL) {
8294
0
        cur = ctxt->context->node;
8295
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8296
0
            cur = cur->parent;
8297
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8298
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8299
8300
0
            if ((ns->next == NULL) ||
8301
0
                (ns->next->type == XML_NAMESPACE_DECL))
8302
0
                return (NULL);
8303
0
            cur = (xmlNodePtr) ns->next;
8304
0
        }
8305
0
    }
8306
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8307
0
  return (NULL);
8308
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8309
0
  cur = cur->prev;
8310
0
    do {
8311
0
        if (cur->prev != NULL) {
8312
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8313
0
            return (cur);
8314
0
        }
8315
8316
0
        cur = cur->parent;
8317
0
        if (cur == NULL)
8318
0
            return (NULL);
8319
0
        if (cur == ctxt->context->doc->children)
8320
0
            return (NULL);
8321
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8322
0
    return (cur);
8323
0
}
8324
8325
/**
8326
 * xmlXPathNextPrecedingInternal:
8327
 * @ctxt:  the XPath Parser context
8328
 * @cur:  the current node in the traversal
8329
 *
8330
 * Traversal function for the "preceding" direction
8331
 * the preceding axis contains all nodes in the same document as the context
8332
 * node that are before the context node in document order, excluding any
8333
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8334
 * ordered in reverse document order
8335
 * This is a faster implementation but internal only since it requires a
8336
 * state kept in the parser context: ctxt->ancestor.
8337
 *
8338
 * Returns the next element following that axis
8339
 */
8340
static xmlNodePtr
8341
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8342
                              xmlNodePtr cur)
8343
29.9M
{
8344
29.9M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8345
29.9M
    if (cur == NULL) {
8346
788k
        cur = ctxt->context->node;
8347
788k
        if (cur == NULL)
8348
0
            return (NULL);
8349
788k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8350
26.2k
            cur = cur->parent;
8351
762k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8352
40.2k
            xmlNsPtr ns = (xmlNsPtr) cur;
8353
8354
40.2k
            if ((ns->next == NULL) ||
8355
40.2k
                (ns->next->type == XML_NAMESPACE_DECL))
8356
0
                return (NULL);
8357
40.2k
            cur = (xmlNodePtr) ns->next;
8358
40.2k
        }
8359
788k
        ctxt->ancestor = cur->parent;
8360
788k
    }
8361
29.9M
    if (cur->type == XML_NAMESPACE_DECL)
8362
0
        return(NULL);
8363
29.9M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8364
0
  cur = cur->prev;
8365
31.6M
    while (cur->prev == NULL) {
8366
13.2M
        cur = cur->parent;
8367
13.2M
        if (cur == NULL)
8368
660k
            return (NULL);
8369
12.6M
        if (cur == ctxt->context->doc->children)
8370
95.2k
            return (NULL);
8371
12.5M
        if (cur != ctxt->ancestor)
8372
10.8M
            return (cur);
8373
1.73M
        ctxt->ancestor = cur->parent;
8374
1.73M
    }
8375
18.3M
    cur = cur->prev;
8376
29.2M
    while (cur->last != NULL)
8377
10.9M
        cur = cur->last;
8378
18.3M
    return (cur);
8379
29.9M
}
8380
8381
/**
8382
 * xmlXPathNextNamespace:
8383
 * @ctxt:  the XPath Parser context
8384
 * @cur:  the current attribute in the traversal
8385
 *
8386
 * Traversal function for the "namespace" direction
8387
 * the namespace axis contains the namespace nodes of the context node;
8388
 * the order of nodes on this axis is implementation-defined; the axis will
8389
 * be empty unless the context node is an element
8390
 *
8391
 * We keep the XML namespace node at the end of the list.
8392
 *
8393
 * Returns the next element following that axis
8394
 */
8395
xmlNodePtr
8396
20.0M
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8397
20.0M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8398
20.0M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8399
13.1M
    if (cur == NULL) {
8400
4.81M
        if (ctxt->context->tmpNsList != NULL)
8401
79.6k
      xmlFree(ctxt->context->tmpNsList);
8402
4.81M
  ctxt->context->tmpNsList =
8403
4.81M
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8404
4.81M
  ctxt->context->tmpNsNr = 0;
8405
4.81M
  if (ctxt->context->tmpNsList != NULL) {
8406
6.01M
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8407
3.77M
    ctxt->context->tmpNsNr++;
8408
3.77M
      }
8409
2.24M
  }
8410
4.81M
  return((xmlNodePtr) xmlXPathXMLNamespace);
8411
4.81M
    }
8412
8.29M
    if (ctxt->context->tmpNsNr > 0) {
8413
3.64M
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8414
4.65M
    } else {
8415
4.65M
  if (ctxt->context->tmpNsList != NULL)
8416
2.13M
      xmlFree(ctxt->context->tmpNsList);
8417
4.65M
  ctxt->context->tmpNsList = NULL;
8418
4.65M
  return(NULL);
8419
4.65M
    }
8420
8.29M
}
8421
8422
/**
8423
 * xmlXPathNextAttribute:
8424
 * @ctxt:  the XPath Parser context
8425
 * @cur:  the current attribute in the traversal
8426
 *
8427
 * Traversal function for the "attribute" direction
8428
 * TODO: support DTD inherited default attributes
8429
 *
8430
 * Returns the next element following that axis
8431
 */
8432
xmlNodePtr
8433
19.0M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8434
19.0M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8435
19.0M
    if (ctxt->context->node == NULL)
8436
0
  return(NULL);
8437
19.0M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8438
10.3M
  return(NULL);
8439
8.75M
    if (cur == NULL) {
8440
5.53M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8441
0
      return(NULL);
8442
5.53M
        return((xmlNodePtr)ctxt->context->node->properties);
8443
5.53M
    }
8444
3.22M
    return((xmlNodePtr)cur->next);
8445
8.75M
}
8446
8447
/************************************************************************
8448
 *                  *
8449
 *    NodeTest Functions          *
8450
 *                  *
8451
 ************************************************************************/
8452
8453
#define IS_FUNCTION     200
8454
8455
8456
/************************************************************************
8457
 *                  *
8458
 *    Implicit tree core function library     *
8459
 *                  *
8460
 ************************************************************************/
8461
8462
/**
8463
 * xmlXPathRoot:
8464
 * @ctxt:  the XPath Parser context
8465
 *
8466
 * Initialize the context to the root of the document
8467
 */
8468
void
8469
11.8M
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8470
11.8M
    if ((ctxt == NULL) || (ctxt->context == NULL))
8471
0
  return;
8472
11.8M
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8473
11.8M
  (xmlNodePtr) ctxt->context->doc));
8474
11.8M
}
8475
8476
/************************************************************************
8477
 *                  *
8478
 *    The explicit core function library      *
8479
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8480
 *                  *
8481
 ************************************************************************/
8482
8483
8484
/**
8485
 * xmlXPathLastFunction:
8486
 * @ctxt:  the XPath Parser context
8487
 * @nargs:  the number of arguments
8488
 *
8489
 * Implement the last() XPath function
8490
 *    number last()
8491
 * The last function returns the number of nodes in the context node list.
8492
 */
8493
void
8494
2.21M
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8495
6.63M
    CHECK_ARITY(0);
8496
6.63M
    if (ctxt->context->contextSize >= 0) {
8497
2.21M
  valuePush(ctxt,
8498
2.21M
      xmlXPathCacheNewFloat(ctxt->context,
8499
2.21M
    (double) ctxt->context->contextSize));
8500
#ifdef DEBUG_EXPR
8501
  xmlGenericError(xmlGenericErrorContext,
8502
    "last() : %d\n", ctxt->context->contextSize);
8503
#endif
8504
2.21M
    } else {
8505
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8506
0
    }
8507
6.63M
}
8508
8509
/**
8510
 * xmlXPathPositionFunction:
8511
 * @ctxt:  the XPath Parser context
8512
 * @nargs:  the number of arguments
8513
 *
8514
 * Implement the position() XPath function
8515
 *    number position()
8516
 * The position function returns the position of the context node in the
8517
 * context node list. The first position is 1, and so the last position
8518
 * will be equal to last().
8519
 */
8520
void
8521
230k
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522
659k
    CHECK_ARITY(0);
8523
659k
    if (ctxt->context->proximityPosition >= 0) {
8524
214k
  valuePush(ctxt,
8525
214k
        xmlXPathCacheNewFloat(ctxt->context,
8526
214k
    (double) ctxt->context->proximityPosition));
8527
#ifdef DEBUG_EXPR
8528
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8529
    ctxt->context->proximityPosition);
8530
#endif
8531
214k
    } else {
8532
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8533
0
    }
8534
659k
}
8535
8536
/**
8537
 * xmlXPathCountFunction:
8538
 * @ctxt:  the XPath Parser context
8539
 * @nargs:  the number of arguments
8540
 *
8541
 * Implement the count() XPath function
8542
 *    number count(node-set)
8543
 */
8544
void
8545
189k
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546
189k
    xmlXPathObjectPtr cur;
8547
8548
555k
    CHECK_ARITY(1);
8549
555k
    if ((ctxt->value == NULL) ||
8550
182k
  ((ctxt->value->type != XPATH_NODESET) &&
8551
182k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8552
160k
  XP_ERROR(XPATH_INVALID_TYPE);
8553
160k
    cur = valuePop(ctxt);
8554
8555
160k
    if ((cur == NULL) || (cur->nodesetval == NULL))
8556
56.3k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8557
104k
    else
8558
104k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8559
104k
      (double) cur->nodesetval->nodeNr));
8560
160k
    xmlXPathReleaseObject(ctxt->context, cur);
8561
160k
}
8562
8563
/**
8564
 * xmlXPathGetElementsByIds:
8565
 * @doc:  the document
8566
 * @ids:  a whitespace separated list of IDs
8567
 *
8568
 * Selects elements by their unique ID.
8569
 *
8570
 * Returns a node-set of selected elements.
8571
 */
8572
static xmlNodeSetPtr
8573
943k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8574
943k
    xmlNodeSetPtr ret;
8575
943k
    const xmlChar *cur = ids;
8576
943k
    xmlChar *ID;
8577
943k
    xmlAttrPtr attr;
8578
943k
    xmlNodePtr elem = NULL;
8579
8580
943k
    if (ids == NULL) return(NULL);
8581
8582
943k
    ret = xmlXPathNodeSetCreate(NULL);
8583
943k
    if (ret == NULL)
8584
0
        return(ret);
8585
8586
1.00M
    while (IS_BLANK_CH(*cur)) cur++;
8587
1.33M
    while (*cur != 0) {
8588
2.72M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8589
2.33M
      cur++;
8590
8591
392k
        ID = xmlStrndup(ids, cur - ids);
8592
392k
  if (ID != NULL) {
8593
      /*
8594
       * We used to check the fact that the value passed
8595
       * was an NCName, but this generated much troubles for
8596
       * me and Aleksey Sanin, people blatantly violated that
8597
       * constraint, like Visa3D spec.
8598
       * if (xmlValidateNCName(ID, 1) == 0)
8599
       */
8600
392k
      attr = xmlGetID(doc, ID);
8601
392k
      if (attr != NULL) {
8602
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8603
0
        elem = attr->parent;
8604
0
    else if (attr->type == XML_ELEMENT_NODE)
8605
0
        elem = (xmlNodePtr) attr;
8606
0
    else
8607
0
        elem = NULL;
8608
                /* TODO: Check memory error. */
8609
0
    if (elem != NULL)
8610
0
        xmlXPathNodeSetAdd(ret, elem);
8611
0
      }
8612
392k
      xmlFree(ID);
8613
392k
  }
8614
8615
1.57M
  while (IS_BLANK_CH(*cur)) cur++;
8616
392k
  ids = cur;
8617
392k
    }
8618
943k
    return(ret);
8619
943k
}
8620
8621
/**
8622
 * xmlXPathIdFunction:
8623
 * @ctxt:  the XPath Parser context
8624
 * @nargs:  the number of arguments
8625
 *
8626
 * Implement the id() XPath function
8627
 *    node-set id(object)
8628
 * The id function selects elements by their unique ID
8629
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8630
 * then the result is the union of the result of applying id to the
8631
 * string value of each of the nodes in the argument node-set. When the
8632
 * argument to id is of any other type, the argument is converted to a
8633
 * string as if by a call to the string function; the string is split
8634
 * into a whitespace-separated list of tokens (whitespace is any sequence
8635
 * of characters matching the production S); the result is a node-set
8636
 * containing the elements in the same document as the context node that
8637
 * have a unique ID equal to any of the tokens in the list.
8638
 */
8639
void
8640
881k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8641
881k
    xmlChar *tokens;
8642
881k
    xmlNodeSetPtr ret;
8643
881k
    xmlXPathObjectPtr obj;
8644
8645
2.62M
    CHECK_ARITY(1);
8646
2.62M
    obj = valuePop(ctxt);
8647
2.62M
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8648
874k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8649
173k
  xmlNodeSetPtr ns;
8650
173k
  int i;
8651
8652
        /* TODO: Check memory error. */
8653
173k
  ret = xmlXPathNodeSetCreate(NULL);
8654
8655
173k
  if (obj->nodesetval != NULL) {
8656
404k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8657
242k
    tokens =
8658
242k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8659
242k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8660
                /* TODO: Check memory error. */
8661
242k
    ret = xmlXPathNodeSetMerge(ret, ns);
8662
242k
    xmlXPathFreeNodeSet(ns);
8663
242k
    if (tokens != NULL)
8664
242k
        xmlFree(tokens);
8665
242k
      }
8666
161k
  }
8667
173k
  xmlXPathReleaseObject(ctxt->context, obj);
8668
173k
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8669
173k
  return;
8670
173k
    }
8671
700k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8672
700k
    if (obj == NULL) return;
8673
700k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8674
700k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8675
700k
    xmlXPathReleaseObject(ctxt->context, obj);
8676
700k
    return;
8677
700k
}
8678
8679
/**
8680
 * xmlXPathLocalNameFunction:
8681
 * @ctxt:  the XPath Parser context
8682
 * @nargs:  the number of arguments
8683
 *
8684
 * Implement the local-name() XPath function
8685
 *    string local-name(node-set?)
8686
 * The local-name function returns a string containing the local part
8687
 * of the name of the node in the argument node-set that is first in
8688
 * document order. If the node-set is empty or the first node has no
8689
 * name, an empty string is returned. If the argument is omitted it
8690
 * defaults to the context node.
8691
 */
8692
void
8693
1.31M
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8694
1.31M
    xmlXPathObjectPtr cur;
8695
8696
1.31M
    if (ctxt == NULL) return;
8697
8698
1.31M
    if (nargs == 0) {
8699
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8700
0
      ctxt->context->node));
8701
0
  nargs = 1;
8702
0
    }
8703
8704
3.93M
    CHECK_ARITY(1);
8705
3.93M
    if ((ctxt->value == NULL) ||
8706
1.31M
  ((ctxt->value->type != XPATH_NODESET) &&
8707
1.31M
   (ctxt->value->type != XPATH_XSLT_TREE)))
8708
1.31M
  XP_ERROR(XPATH_INVALID_TYPE);
8709
1.31M
    cur = valuePop(ctxt);
8710
8711
1.31M
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8712
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
1.31M
    } else {
8714
1.31M
  int i = 0; /* Should be first in document order !!!!! */
8715
1.31M
  switch (cur->nodesetval->nodeTab[i]->type) {
8716
0
  case XML_ELEMENT_NODE:
8717
0
  case XML_ATTRIBUTE_NODE:
8718
81.2k
  case XML_PI_NODE:
8719
81.2k
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8720
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8721
81.2k
      else
8722
81.2k
    valuePush(ctxt,
8723
81.2k
          xmlXPathCacheNewString(ctxt->context,
8724
81.2k
      cur->nodesetval->nodeTab[i]->name));
8725
81.2k
      break;
8726
14.9k
  case XML_NAMESPACE_DECL:
8727
14.9k
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8728
14.9k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8729
14.9k
      break;
8730
1.21M
  default:
8731
1.21M
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8732
1.31M
  }
8733
1.31M
    }
8734
1.31M
    xmlXPathReleaseObject(ctxt->context, cur);
8735
1.31M
}
8736
8737
/**
8738
 * xmlXPathNamespaceURIFunction:
8739
 * @ctxt:  the XPath Parser context
8740
 * @nargs:  the number of arguments
8741
 *
8742
 * Implement the namespace-uri() XPath function
8743
 *    string namespace-uri(node-set?)
8744
 * The namespace-uri function returns a string containing the
8745
 * namespace URI of the expanded name of the node in the argument
8746
 * node-set that is first in document order. If the node-set is empty,
8747
 * the first node has no name, or the expanded name has no namespace
8748
 * URI, an empty string is returned. If the argument is omitted it
8749
 * defaults to the context node.
8750
 */
8751
void
8752
1.04M
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8753
1.04M
    xmlXPathObjectPtr cur;
8754
8755
1.04M
    if (ctxt == NULL) return;
8756
8757
1.04M
    if (nargs == 0) {
8758
455k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8759
455k
      ctxt->context->node));
8760
455k
  nargs = 1;
8761
455k
    }
8762
3.13M
    CHECK_ARITY(1);
8763
3.13M
    if ((ctxt->value == NULL) ||
8764
1.04M
  ((ctxt->value->type != XPATH_NODESET) &&
8765
1.04M
   (ctxt->value->type != XPATH_XSLT_TREE)))
8766
1.00M
  XP_ERROR(XPATH_INVALID_TYPE);
8767
1.00M
    cur = valuePop(ctxt);
8768
8769
1.00M
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8770
381k
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8771
622k
    } else {
8772
622k
  int i = 0; /* Should be first in document order !!!!! */
8773
622k
  switch (cur->nodesetval->nodeTab[i]->type) {
8774
297k
  case XML_ELEMENT_NODE:
8775
297k
  case XML_ATTRIBUTE_NODE:
8776
297k
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8777
205k
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8778
92.6k
      else
8779
92.6k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8780
92.6k
        cur->nodesetval->nodeTab[i]->ns->href));
8781
297k
      break;
8782
324k
  default:
8783
324k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784
622k
  }
8785
622k
    }
8786
1.00M
    xmlXPathReleaseObject(ctxt->context, cur);
8787
1.00M
}
8788
8789
/**
8790
 * xmlXPathNameFunction:
8791
 * @ctxt:  the XPath Parser context
8792
 * @nargs:  the number of arguments
8793
 *
8794
 * Implement the name() XPath function
8795
 *    string name(node-set?)
8796
 * The name function returns a string containing a QName representing
8797
 * the name of the node in the argument node-set that is first in document
8798
 * order. The QName must represent the name with respect to the namespace
8799
 * declarations in effect on the node whose name is being represented.
8800
 * Typically, this will be the form in which the name occurred in the XML
8801
 * source. This need not be the case if there are namespace declarations
8802
 * in effect on the node that associate multiple prefixes with the same
8803
 * namespace. However, an implementation may include information about
8804
 * the original prefix in its representation of nodes; in this case, an
8805
 * implementation can ensure that the returned string is always the same
8806
 * as the QName used in the XML source. If the argument it omitted it
8807
 * defaults to the context node.
8808
 * Libxml keep the original prefix so the "real qualified name" used is
8809
 * returned.
8810
 */
8811
static void
8812
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8813
2.67M
{
8814
2.67M
    xmlXPathObjectPtr cur;
8815
8816
2.67M
    if (nargs == 0) {
8817
2.05M
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8818
2.05M
      ctxt->context->node));
8819
2.05M
        nargs = 1;
8820
2.05M
    }
8821
8822
8.00M
    CHECK_ARITY(1);
8823
8.00M
    if ((ctxt->value == NULL) ||
8824
2.66M
        ((ctxt->value->type != XPATH_NODESET) &&
8825
2.66M
         (ctxt->value->type != XPATH_XSLT_TREE)))
8826
2.66M
        XP_ERROR(XPATH_INVALID_TYPE);
8827
2.66M
    cur = valuePop(ctxt);
8828
8829
2.66M
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8830
506k
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8831
2.15M
    } else {
8832
2.15M
        int i = 0;              /* Should be first in document order !!!!! */
8833
8834
2.15M
        switch (cur->nodesetval->nodeTab[i]->type) {
8835
842k
            case XML_ELEMENT_NODE:
8836
842k
            case XML_ATTRIBUTE_NODE:
8837
842k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8838
0
        valuePush(ctxt,
8839
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8840
842k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8841
842k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8842
441k
        valuePush(ctxt,
8843
441k
            xmlXPathCacheNewString(ctxt->context,
8844
441k
          cur->nodesetval->nodeTab[i]->name));
8845
441k
    } else {
8846
400k
        xmlChar *fullname;
8847
8848
400k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8849
400k
             cur->nodesetval->nodeTab[i]->ns->prefix,
8850
400k
             NULL, 0);
8851
400k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8852
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8853
400k
        if (fullname == NULL) {
8854
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8855
0
        }
8856
400k
        valuePush(ctxt, xmlXPathCacheWrapString(
8857
400k
      ctxt->context, fullname));
8858
400k
                }
8859
842k
                break;
8860
1.31M
            default:
8861
1.31M
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8862
1.31M
        cur->nodesetval->nodeTab[i]));
8863
1.31M
                xmlXPathLocalNameFunction(ctxt, 1);
8864
2.15M
        }
8865
2.15M
    }
8866
2.66M
    xmlXPathReleaseObject(ctxt->context, cur);
8867
2.66M
}
8868
8869
8870
/**
8871
 * xmlXPathStringFunction:
8872
 * @ctxt:  the XPath Parser context
8873
 * @nargs:  the number of arguments
8874
 *
8875
 * Implement the string() XPath function
8876
 *    string string(object?)
8877
 * The string function converts an object to a string as follows:
8878
 *    - A node-set is converted to a string by returning the value of
8879
 *      the node in the node-set that is first in document order.
8880
 *      If the node-set is empty, an empty string is returned.
8881
 *    - A number is converted to a string as follows
8882
 *      + NaN is converted to the string NaN
8883
 *      + positive zero is converted to the string 0
8884
 *      + negative zero is converted to the string 0
8885
 *      + positive infinity is converted to the string Infinity
8886
 *      + negative infinity is converted to the string -Infinity
8887
 *      + if the number is an integer, the number is represented in
8888
 *        decimal form as a Number with no decimal point and no leading
8889
 *        zeros, preceded by a minus sign (-) if the number is negative
8890
 *      + otherwise, the number is represented in decimal form as a
8891
 *        Number including a decimal point with at least one digit
8892
 *        before the decimal point and at least one digit after the
8893
 *        decimal point, preceded by a minus sign (-) if the number
8894
 *        is negative; there must be no leading zeros before the decimal
8895
 *        point apart possibly from the one required digit immediately
8896
 *        before the decimal point; beyond the one required digit
8897
 *        after the decimal point there must be as many, but only as
8898
 *        many, more digits as are needed to uniquely distinguish the
8899
 *        number from all other IEEE 754 numeric values.
8900
 *    - The boolean false value is converted to the string false.
8901
 *      The boolean true value is converted to the string true.
8902
 *
8903
 * If the argument is omitted, it defaults to a node-set with the
8904
 * context node as its only member.
8905
 */
8906
void
8907
19.1M
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908
19.1M
    xmlXPathObjectPtr cur;
8909
8910
19.1M
    if (ctxt == NULL) return;
8911
19.1M
    if (nargs == 0) {
8912
782k
    valuePush(ctxt,
8913
782k
  xmlXPathCacheWrapString(ctxt->context,
8914
782k
      xmlXPathCastNodeToString(ctxt->context->node)));
8915
782k
  return;
8916
782k
    }
8917
8918
73.3M
    CHECK_ARITY(1);
8919
73.3M
    cur = valuePop(ctxt);
8920
73.3M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8921
18.3M
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8922
18.3M
}
8923
8924
/**
8925
 * xmlXPathStringLengthFunction:
8926
 * @ctxt:  the XPath Parser context
8927
 * @nargs:  the number of arguments
8928
 *
8929
 * Implement the string-length() XPath function
8930
 *    number string-length(string?)
8931
 * The string-length returns the number of characters in the string
8932
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8933
 * the context node converted to a string, in other words the value
8934
 * of the context node.
8935
 */
8936
void
8937
630k
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8938
630k
    xmlXPathObjectPtr cur;
8939
8940
630k
    if (nargs == 0) {
8941
487k
        if ((ctxt == NULL) || (ctxt->context == NULL))
8942
0
      return;
8943
487k
  if (ctxt->context->node == NULL) {
8944
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8945
487k
  } else {
8946
487k
      xmlChar *content;
8947
8948
487k
      content = xmlXPathCastNodeToString(ctxt->context->node);
8949
487k
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8950
487k
    xmlUTF8Strlen(content)));
8951
487k
      xmlFree(content);
8952
487k
  }
8953
487k
  return;
8954
487k
    }
8955
570k
    CHECK_ARITY(1);
8956
570k
    CAST_TO_STRING;
8957
570k
    CHECK_TYPE(XPATH_STRING);
8958
142k
    cur = valuePop(ctxt);
8959
142k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960
142k
  xmlUTF8Strlen(cur->stringval)));
8961
142k
    xmlXPathReleaseObject(ctxt->context, cur);
8962
142k
}
8963
8964
/**
8965
 * xmlXPathConcatFunction:
8966
 * @ctxt:  the XPath Parser context
8967
 * @nargs:  the number of arguments
8968
 *
8969
 * Implement the concat() XPath function
8970
 *    string concat(string, string, string*)
8971
 * The concat function returns the concatenation of its arguments.
8972
 */
8973
void
8974
148k
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975
148k
    xmlXPathObjectPtr cur, newobj;
8976
148k
    xmlChar *tmp;
8977
8978
148k
    if (ctxt == NULL) return;
8979
148k
    if (nargs < 2) {
8980
3.90k
  CHECK_ARITY(2);
8981
3.90k
    }
8982
8983
144k
    CAST_TO_STRING;
8984
144k
    cur = valuePop(ctxt);
8985
144k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8986
0
  xmlXPathReleaseObject(ctxt->context, cur);
8987
0
  return;
8988
0
    }
8989
144k
    nargs--;
8990
8991
363k
    while (nargs > 0) {
8992
219k
  CAST_TO_STRING;
8993
219k
  newobj = valuePop(ctxt);
8994
219k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8995
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8996
0
      xmlXPathReleaseObject(ctxt->context, cur);
8997
0
      XP_ERROR(XPATH_INVALID_TYPE);
8998
0
  }
8999
219k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
9000
219k
  newobj->stringval = cur->stringval;
9001
219k
  cur->stringval = tmp;
9002
219k
  xmlXPathReleaseObject(ctxt->context, newobj);
9003
219k
  nargs--;
9004
219k
    }
9005
144k
    valuePush(ctxt, cur);
9006
144k
}
9007
9008
/**
9009
 * xmlXPathContainsFunction:
9010
 * @ctxt:  the XPath Parser context
9011
 * @nargs:  the number of arguments
9012
 *
9013
 * Implement the contains() XPath function
9014
 *    boolean contains(string, string)
9015
 * The contains function returns true if the first argument string
9016
 * contains the second argument string, and otherwise returns false.
9017
 */
9018
void
9019
192k
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
192k
    xmlXPathObjectPtr hay, needle;
9021
9022
576k
    CHECK_ARITY(2);
9023
576k
    CAST_TO_STRING;
9024
576k
    CHECK_TYPE(XPATH_STRING);
9025
191k
    needle = valuePop(ctxt);
9026
191k
    CAST_TO_STRING;
9027
191k
    hay = valuePop(ctxt);
9028
9029
191k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9030
0
  xmlXPathReleaseObject(ctxt->context, hay);
9031
0
  xmlXPathReleaseObject(ctxt->context, needle);
9032
0
  XP_ERROR(XPATH_INVALID_TYPE);
9033
0
    }
9034
191k
    if (xmlStrstr(hay->stringval, needle->stringval))
9035
76.6k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9036
115k
    else
9037
115k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
191k
    xmlXPathReleaseObject(ctxt->context, hay);
9039
191k
    xmlXPathReleaseObject(ctxt->context, needle);
9040
191k
}
9041
9042
/**
9043
 * xmlXPathStartsWithFunction:
9044
 * @ctxt:  the XPath Parser context
9045
 * @nargs:  the number of arguments
9046
 *
9047
 * Implement the starts-with() XPath function
9048
 *    boolean starts-with(string, string)
9049
 * The starts-with function returns true if the first argument string
9050
 * starts with the second argument string, and otherwise returns false.
9051
 */
9052
void
9053
96.0k
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9054
96.0k
    xmlXPathObjectPtr hay, needle;
9055
96.0k
    int n;
9056
9057
282k
    CHECK_ARITY(2);
9058
282k
    CAST_TO_STRING;
9059
282k
    CHECK_TYPE(XPATH_STRING);
9060
93.1k
    needle = valuePop(ctxt);
9061
93.1k
    CAST_TO_STRING;
9062
93.1k
    hay = valuePop(ctxt);
9063
9064
93.1k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9065
0
  xmlXPathReleaseObject(ctxt->context, hay);
9066
0
  xmlXPathReleaseObject(ctxt->context, needle);
9067
0
  XP_ERROR(XPATH_INVALID_TYPE);
9068
0
    }
9069
93.1k
    n = xmlStrlen(needle->stringval);
9070
93.1k
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9071
29.5k
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9072
63.5k
    else
9073
63.5k
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9074
93.1k
    xmlXPathReleaseObject(ctxt->context, hay);
9075
93.1k
    xmlXPathReleaseObject(ctxt->context, needle);
9076
93.1k
}
9077
9078
/**
9079
 * xmlXPathSubstringFunction:
9080
 * @ctxt:  the XPath Parser context
9081
 * @nargs:  the number of arguments
9082
 *
9083
 * Implement the substring() XPath function
9084
 *    string substring(string, number, number?)
9085
 * The substring function returns the substring of the first argument
9086
 * starting at the position specified in the second argument with
9087
 * length specified in the third argument. For example,
9088
 * substring("12345",2,3) returns "234". If the third argument is not
9089
 * specified, it returns the substring starting at the position specified
9090
 * in the second argument and continuing to the end of the string. For
9091
 * example, substring("12345",2) returns "2345".  More precisely, each
9092
 * character in the string (see [3.6 Strings]) is considered to have a
9093
 * numeric position: the position of the first character is 1, the position
9094
 * of the second character is 2 and so on. The returned substring contains
9095
 * those characters for which the position of the character is greater than
9096
 * or equal to the second argument and, if the third argument is specified,
9097
 * less than the sum of the second and third arguments; the comparisons
9098
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9099
 *  - substring("12345", 1.5, 2.6) returns "234"
9100
 *  - substring("12345", 0, 3) returns "12"
9101
 *  - substring("12345", 0 div 0, 3) returns ""
9102
 *  - substring("12345", 1, 0 div 0) returns ""
9103
 *  - substring("12345", -42, 1 div 0) returns "12345"
9104
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9105
 */
9106
void
9107
544k
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9108
544k
    xmlXPathObjectPtr str, start, len;
9109
544k
    double le=0, in;
9110
544k
    int i = 1, j = INT_MAX;
9111
9112
544k
    if (nargs < 2) {
9113
10.8k
  CHECK_ARITY(2);
9114
10.8k
    }
9115
533k
    if (nargs > 3) {
9116
3.62k
  CHECK_ARITY(3);
9117
3.62k
    }
9118
    /*
9119
     * take care of possible last (position) argument
9120
    */
9121
530k
    if (nargs == 3) {
9122
146k
  CAST_TO_NUMBER;
9123
146k
  CHECK_TYPE(XPATH_NUMBER);
9124
146k
  len = valuePop(ctxt);
9125
146k
  le = len->floatval;
9126
146k
  xmlXPathReleaseObject(ctxt->context, len);
9127
146k
    }
9128
9129
530k
    CAST_TO_NUMBER;
9130
530k
    CHECK_TYPE(XPATH_NUMBER);
9131
530k
    start = valuePop(ctxt);
9132
530k
    in = start->floatval;
9133
530k
    xmlXPathReleaseObject(ctxt->context, start);
9134
530k
    CAST_TO_STRING;
9135
530k
    CHECK_TYPE(XPATH_STRING);
9136
530k
    str = valuePop(ctxt);
9137
9138
530k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9139
134k
        i = INT_MAX;
9140
395k
    } else if (in >= 1.0) {
9141
327k
        i = (int)in;
9142
327k
        if (in - floor(in) >= 0.5)
9143
4.91k
            i += 1;
9144
327k
    }
9145
9146
530k
    if (nargs == 3) {
9147
146k
        double rin, rle, end;
9148
9149
146k
        rin = floor(in);
9150
146k
        if (in - rin >= 0.5)
9151
152
            rin += 1.0;
9152
9153
146k
        rle = floor(le);
9154
146k
        if (le - rle >= 0.5)
9155
0
            rle += 1.0;
9156
9157
146k
        end = rin + rle;
9158
146k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9159
19.0k
            j = 1;
9160
127k
        } else if (end < INT_MAX) {
9161
84.3k
            j = (int)end;
9162
84.3k
        }
9163
146k
    }
9164
9165
530k
    if (i < j) {
9166
375k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9167
375k
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9168
375k
  xmlFree(ret);
9169
375k
    } else {
9170
154k
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9171
154k
    }
9172
9173
530k
    xmlXPathReleaseObject(ctxt->context, str);
9174
530k
}
9175
9176
/**
9177
 * xmlXPathSubstringBeforeFunction:
9178
 * @ctxt:  the XPath Parser context
9179
 * @nargs:  the number of arguments
9180
 *
9181
 * Implement the substring-before() XPath function
9182
 *    string substring-before(string, string)
9183
 * The substring-before function returns the substring of the first
9184
 * argument string that precedes the first occurrence of the second
9185
 * argument string in the first argument string, or the empty string
9186
 * if the first argument string does not contain the second argument
9187
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9188
 */
9189
void
9190
80.3k
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9191
80.3k
  xmlXPathObjectPtr str;
9192
80.3k
  xmlXPathObjectPtr find;
9193
80.3k
  xmlBufPtr target;
9194
80.3k
  const xmlChar *point;
9195
80.3k
  int offset;
9196
9197
234k
  CHECK_ARITY(2);
9198
234k
  CAST_TO_STRING;
9199
234k
  find = valuePop(ctxt);
9200
234k
  CAST_TO_STRING;
9201
234k
  str = valuePop(ctxt);
9202
9203
234k
  target = xmlBufCreate();
9204
234k
  if (target) {
9205
77.3k
    point = xmlStrstr(str->stringval, find->stringval);
9206
77.3k
    if (point) {
9207
60.3k
      offset = point - str->stringval;
9208
60.3k
      xmlBufAdd(target, str->stringval, offset);
9209
60.3k
    }
9210
77.3k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211
77.3k
  xmlBufContent(target)));
9212
77.3k
    xmlBufFree(target);
9213
77.3k
  }
9214
234k
  xmlXPathReleaseObject(ctxt->context, str);
9215
234k
  xmlXPathReleaseObject(ctxt->context, find);
9216
234k
}
9217
9218
/**
9219
 * xmlXPathSubstringAfterFunction:
9220
 * @ctxt:  the XPath Parser context
9221
 * @nargs:  the number of arguments
9222
 *
9223
 * Implement the substring-after() XPath function
9224
 *    string substring-after(string, string)
9225
 * The substring-after function returns the substring of the first
9226
 * argument string that follows the first occurrence of the second
9227
 * argument string in the first argument string, or the empty stringi
9228
 * if the first argument string does not contain the second argument
9229
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9230
 * and substring-after("1999/04/01","19") returns 99/04/01.
9231
 */
9232
void
9233
34.5k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234
34.5k
  xmlXPathObjectPtr str;
9235
34.5k
  xmlXPathObjectPtr find;
9236
34.5k
  xmlBufPtr target;
9237
34.5k
  const xmlChar *point;
9238
34.5k
  int offset;
9239
9240
95.4k
  CHECK_ARITY(2);
9241
95.4k
  CAST_TO_STRING;
9242
95.4k
  find = valuePop(ctxt);
9243
95.4k
  CAST_TO_STRING;
9244
95.4k
  str = valuePop(ctxt);
9245
9246
95.4k
  target = xmlBufCreate();
9247
95.4k
  if (target) {
9248
30.4k
    point = xmlStrstr(str->stringval, find->stringval);
9249
30.4k
    if (point) {
9250
17.8k
      offset = point - str->stringval + xmlStrlen(find->stringval);
9251
17.8k
      xmlBufAdd(target, &str->stringval[offset],
9252
17.8k
       xmlStrlen(str->stringval) - offset);
9253
17.8k
    }
9254
30.4k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9255
30.4k
  xmlBufContent(target)));
9256
30.4k
    xmlBufFree(target);
9257
30.4k
  }
9258
95.4k
  xmlXPathReleaseObject(ctxt->context, str);
9259
95.4k
  xmlXPathReleaseObject(ctxt->context, find);
9260
95.4k
}
9261
9262
/**
9263
 * xmlXPathNormalizeFunction:
9264
 * @ctxt:  the XPath Parser context
9265
 * @nargs:  the number of arguments
9266
 *
9267
 * Implement the normalize-space() XPath function
9268
 *    string normalize-space(string?)
9269
 * The normalize-space function returns the argument string with white
9270
 * space normalized by stripping leading and trailing whitespace
9271
 * and replacing sequences of whitespace characters by a single
9272
 * space. Whitespace characters are the same allowed by the S production
9273
 * in XML. If the argument is omitted, it defaults to the context
9274
 * node converted to a string, in other words the value of the context node.
9275
 */
9276
void
9277
400k
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9278
400k
    xmlChar *source, *target;
9279
400k
    int blank;
9280
9281
400k
    if (ctxt == NULL) return;
9282
400k
    if (nargs == 0) {
9283
        /* Use current context node */
9284
340k
        valuePush(ctxt,
9285
340k
            xmlXPathCacheWrapString(ctxt->context,
9286
340k
                xmlXPathCastNodeToString(ctxt->context->node)));
9287
340k
        nargs = 1;
9288
340k
    }
9289
9290
1.19M
    CHECK_ARITY(1);
9291
1.19M
    CAST_TO_STRING;
9292
1.19M
    CHECK_TYPE(XPATH_STRING);
9293
399k
    source = ctxt->value->stringval;
9294
399k
    if (source == NULL)
9295
0
        return;
9296
399k
    target = source;
9297
9298
    /* Skip leading whitespaces */
9299
399k
    while (IS_BLANK_CH(*source))
9300
1.33M
        source++;
9301
9302
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9303
399k
    blank = 0;
9304
5.58M
    while (*source) {
9305
5.18M
        if (IS_BLANK_CH(*source)) {
9306
3.33M
      blank = 1;
9307
3.33M
        } else {
9308
1.85M
            if (blank) {
9309
187k
                *target++ = 0x20;
9310
187k
                blank = 0;
9311
187k
            }
9312
1.85M
            *target++ = *source;
9313
1.85M
        }
9314
5.18M
        source++;
9315
5.18M
    }
9316
399k
    *target = 0;
9317
399k
}
9318
9319
/**
9320
 * xmlXPathTranslateFunction:
9321
 * @ctxt:  the XPath Parser context
9322
 * @nargs:  the number of arguments
9323
 *
9324
 * Implement the translate() XPath function
9325
 *    string translate(string, string, string)
9326
 * The translate function returns the first argument string with
9327
 * occurrences of characters in the second argument string replaced
9328
 * by the character at the corresponding position in the third argument
9329
 * string. For example, translate("bar","abc","ABC") returns the string
9330
 * BAr. If there is a character in the second argument string with no
9331
 * character at a corresponding position in the third argument string
9332
 * (because the second argument string is longer than the third argument
9333
 * string), then occurrences of that character in the first argument
9334
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9335
 * returns "AAA". If a character occurs more than once in second
9336
 * argument string, then the first occurrence determines the replacement
9337
 * character. If the third argument string is longer than the second
9338
 * argument string, then excess characters are ignored.
9339
 */
9340
void
9341
664k
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342
664k
    xmlXPathObjectPtr str;
9343
664k
    xmlXPathObjectPtr from;
9344
664k
    xmlXPathObjectPtr to;
9345
664k
    xmlBufPtr target;
9346
664k
    int offset, max;
9347
664k
    xmlChar ch;
9348
664k
    const xmlChar *point;
9349
664k
    xmlChar *cptr;
9350
9351
1.98M
    CHECK_ARITY(3);
9352
9353
1.98M
    CAST_TO_STRING;
9354
1.98M
    to = valuePop(ctxt);
9355
1.98M
    CAST_TO_STRING;
9356
1.98M
    from = valuePop(ctxt);
9357
1.98M
    CAST_TO_STRING;
9358
1.98M
    str = valuePop(ctxt);
9359
9360
1.98M
    target = xmlBufCreate();
9361
1.98M
    if (target) {
9362
660k
  max = xmlUTF8Strlen(to->stringval);
9363
8.00M
  for (cptr = str->stringval; (ch=*cptr); ) {
9364
7.35M
      offset = xmlUTF8Strloc(from->stringval, cptr);
9365
7.35M
      if (offset >= 0) {
9366
522k
    if (offset < max) {
9367
355k
        point = xmlUTF8Strpos(to->stringval, offset);
9368
355k
        if (point)
9369
305k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9370
355k
    }
9371
522k
      } else
9372
6.83M
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9373
9374
      /* Step to next character in input */
9375
7.35M
      cptr++;
9376
7.35M
      if ( ch & 0x80 ) {
9377
    /* if not simple ascii, verify proper format */
9378
202k
    if ( (ch & 0xc0) != 0xc0 ) {
9379
9.48k
        xmlGenericError(xmlGenericErrorContext,
9380
9.48k
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                    /* not asserting an XPath error is probably better */
9382
9.48k
        break;
9383
9.48k
    }
9384
    /* then skip over remaining bytes for this char */
9385
501k
    while ( (ch <<= 1) & 0x80 )
9386
314k
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9387
6.95k
      xmlGenericError(xmlGenericErrorContext,
9388
6.95k
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9389
                        /* not asserting an XPath error is probably better */
9390
6.95k
      break;
9391
6.95k
        }
9392
193k
    if (ch & 0x80) /* must have had error encountered */
9393
6.95k
        break;
9394
193k
      }
9395
7.35M
  }
9396
660k
    }
9397
1.98M
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9398
1.98M
  xmlBufContent(target)));
9399
1.98M
    xmlBufFree(target);
9400
1.98M
    xmlXPathReleaseObject(ctxt->context, str);
9401
1.98M
    xmlXPathReleaseObject(ctxt->context, from);
9402
1.98M
    xmlXPathReleaseObject(ctxt->context, to);
9403
1.98M
}
9404
9405
/**
9406
 * xmlXPathBooleanFunction:
9407
 * @ctxt:  the XPath Parser context
9408
 * @nargs:  the number of arguments
9409
 *
9410
 * Implement the boolean() XPath function
9411
 *    boolean boolean(object)
9412
 * The boolean function converts its argument to a boolean as follows:
9413
 *    - a number is true if and only if it is neither positive or
9414
 *      negative zero nor NaN
9415
 *    - a node-set is true if and only if it is non-empty
9416
 *    - a string is true if and only if its length is non-zero
9417
 */
9418
void
9419
7.66M
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420
7.66M
    xmlXPathObjectPtr cur;
9421
9422
22.9M
    CHECK_ARITY(1);
9423
22.9M
    cur = valuePop(ctxt);
9424
22.9M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9425
7.66M
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9426
7.66M
    valuePush(ctxt, cur);
9427
7.66M
}
9428
9429
/**
9430
 * xmlXPathNotFunction:
9431
 * @ctxt:  the XPath Parser context
9432
 * @nargs:  the number of arguments
9433
 *
9434
 * Implement the not() XPath function
9435
 *    boolean not(boolean)
9436
 * The not function returns true if its argument is false,
9437
 * and false otherwise.
9438
 */
9439
void
9440
41.1k
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9441
118k
    CHECK_ARITY(1);
9442
118k
    CAST_TO_BOOLEAN;
9443
118k
    CHECK_TYPE(XPATH_BOOLEAN);
9444
38.7k
    ctxt->value->boolval = ! ctxt->value->boolval;
9445
38.7k
}
9446
9447
/**
9448
 * xmlXPathTrueFunction:
9449
 * @ctxt:  the XPath Parser context
9450
 * @nargs:  the number of arguments
9451
 *
9452
 * Implement the true() XPath function
9453
 *    boolean true()
9454
 */
9455
void
9456
217k
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457
647k
    CHECK_ARITY(0);
9458
647k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9459
647k
}
9460
9461
/**
9462
 * xmlXPathFalseFunction:
9463
 * @ctxt:  the XPath Parser context
9464
 * @nargs:  the number of arguments
9465
 *
9466
 * Implement the false() XPath function
9467
 *    boolean false()
9468
 */
9469
void
9470
95.5k
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9471
258k
    CHECK_ARITY(0);
9472
258k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9473
258k
}
9474
9475
/**
9476
 * xmlXPathLangFunction:
9477
 * @ctxt:  the XPath Parser context
9478
 * @nargs:  the number of arguments
9479
 *
9480
 * Implement the lang() XPath function
9481
 *    boolean lang(string)
9482
 * The lang function returns true or false depending on whether the
9483
 * language of the context node as specified by xml:lang attributes
9484
 * is the same as or is a sublanguage of the language specified by
9485
 * the argument string. The language of the context node is determined
9486
 * by the value of the xml:lang attribute on the context node, or, if
9487
 * the context node has no xml:lang attribute, by the value of the
9488
 * xml:lang attribute on the nearest ancestor of the context node that
9489
 * has an xml:lang attribute. If there is no such attribute, then lang
9490
 * returns false. If there is such an attribute, then lang returns
9491
 * true if the attribute value is equal to the argument ignoring case,
9492
 * or if there is some suffix starting with - such that the attribute
9493
 * value is equal to the argument ignoring that suffix of the attribute
9494
 * value and ignoring case.
9495
 */
9496
void
9497
167k
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498
167k
    xmlXPathObjectPtr val = NULL;
9499
167k
    const xmlChar *theLang = NULL;
9500
167k
    const xmlChar *lang;
9501
167k
    int ret = 0;
9502
167k
    int i;
9503
9504
495k
    CHECK_ARITY(1);
9505
495k
    CAST_TO_STRING;
9506
495k
    CHECK_TYPE(XPATH_STRING);
9507
164k
    val = valuePop(ctxt);
9508
164k
    lang = val->stringval;
9509
164k
    theLang = xmlNodeGetLang(ctxt->context->node);
9510
164k
    if ((theLang != NULL) && (lang != NULL)) {
9511
0
        for (i = 0;lang[i] != 0;i++)
9512
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9513
0
          goto not_equal;
9514
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9515
0
      ret = 1;
9516
0
    }
9517
164k
not_equal:
9518
164k
    if (theLang != NULL)
9519
0
  xmlFree((void *)theLang);
9520
9521
164k
    xmlXPathReleaseObject(ctxt->context, val);
9522
164k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9523
164k
}
9524
9525
/**
9526
 * xmlXPathNumberFunction:
9527
 * @ctxt:  the XPath Parser context
9528
 * @nargs:  the number of arguments
9529
 *
9530
 * Implement the number() XPath function
9531
 *    number number(object?)
9532
 */
9533
void
9534
35.5M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
35.5M
    xmlXPathObjectPtr cur;
9536
35.5M
    double res;
9537
9538
35.5M
    if (ctxt == NULL) return;
9539
35.5M
    if (nargs == 0) {
9540
102k
  if (ctxt->context->node == NULL) {
9541
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9542
102k
  } else {
9543
102k
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9544
9545
102k
      res = xmlXPathStringEvalNumber(content);
9546
102k
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9547
102k
      xmlFree(content);
9548
102k
  }
9549
102k
  return;
9550
102k
    }
9551
9552
141M
    CHECK_ARITY(1);
9553
141M
    cur = valuePop(ctxt);
9554
141M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9555
141M
}
9556
9557
/**
9558
 * xmlXPathSumFunction:
9559
 * @ctxt:  the XPath Parser context
9560
 * @nargs:  the number of arguments
9561
 *
9562
 * Implement the sum() XPath function
9563
 *    number sum(node-set)
9564
 * The sum function returns the sum of the values of the nodes in
9565
 * the argument node-set.
9566
 */
9567
void
9568
243k
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9569
243k
    xmlXPathObjectPtr cur;
9570
243k
    int i;
9571
243k
    double res = 0.0;
9572
9573
687k
    CHECK_ARITY(1);
9574
687k
    if ((ctxt->value == NULL) ||
9575
222k
  ((ctxt->value->type != XPATH_NODESET) &&
9576
222k
   (ctxt->value->type != XPATH_XSLT_TREE)))
9577
204k
  XP_ERROR(XPATH_INVALID_TYPE);
9578
204k
    cur = valuePop(ctxt);
9579
9580
204k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9581
102k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9582
85.0k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9583
85.0k
  }
9584
17.4k
    }
9585
204k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9586
204k
    xmlXPathReleaseObject(ctxt->context, cur);
9587
204k
}
9588
9589
/**
9590
 * xmlXPathFloorFunction:
9591
 * @ctxt:  the XPath Parser context
9592
 * @nargs:  the number of arguments
9593
 *
9594
 * Implement the floor() XPath function
9595
 *    number floor(number)
9596
 * The floor function returns the largest (closest to positive infinity)
9597
 * number that is not greater than the argument and that is an integer.
9598
 */
9599
void
9600
56.7k
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601
123k
    CHECK_ARITY(1);
9602
123k
    CAST_TO_NUMBER;
9603
123k
    CHECK_TYPE(XPATH_NUMBER);
9604
9605
33.3k
    ctxt->value->floatval = floor(ctxt->value->floatval);
9606
33.3k
}
9607
9608
/**
9609
 * xmlXPathCeilingFunction:
9610
 * @ctxt:  the XPath Parser context
9611
 * @nargs:  the number of arguments
9612
 *
9613
 * Implement the ceiling() XPath function
9614
 *    number ceiling(number)
9615
 * The ceiling function returns the smallest (closest to negative infinity)
9616
 * number that is not less than the argument and that is an integer.
9617
 */
9618
void
9619
14.1k
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9620
38.4k
    CHECK_ARITY(1);
9621
38.4k
    CAST_TO_NUMBER;
9622
38.4k
    CHECK_TYPE(XPATH_NUMBER);
9623
9624
#ifdef _AIX
9625
    /* Work around buggy ceil() function on AIX */
9626
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9627
#else
9628
12.1k
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9629
12.1k
#endif
9630
12.1k
}
9631
9632
/**
9633
 * xmlXPathRoundFunction:
9634
 * @ctxt:  the XPath Parser context
9635
 * @nargs:  the number of arguments
9636
 *
9637
 * Implement the round() XPath function
9638
 *    number round(number)
9639
 * The round function returns the number that is closest to the
9640
 * argument and that is an integer. If there are two such numbers,
9641
 * then the one that is closest to positive infinity is returned.
9642
 */
9643
void
9644
31.8k
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9645
31.8k
    double f;
9646
9647
89.8k
    CHECK_ARITY(1);
9648
89.8k
    CAST_TO_NUMBER;
9649
89.8k
    CHECK_TYPE(XPATH_NUMBER);
9650
9651
28.9k
    f = ctxt->value->floatval;
9652
9653
28.9k
    if ((f >= -0.5) && (f < 0.5)) {
9654
        /* Handles negative zero. */
9655
2.95k
        ctxt->value->floatval *= 0.0;
9656
2.95k
    }
9657
26.0k
    else {
9658
26.0k
        double rounded = floor(f);
9659
26.0k
        if (f - rounded >= 0.5)
9660
0
            rounded += 1.0;
9661
26.0k
        ctxt->value->floatval = rounded;
9662
26.0k
    }
9663
28.9k
}
9664
9665
/************************************************************************
9666
 *                  *
9667
 *      The Parser          *
9668
 *                  *
9669
 ************************************************************************/
9670
9671
/*
9672
 * a few forward declarations since we use a recursive call based
9673
 * implementation.
9674
 */
9675
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9676
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9677
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9678
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9679
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9680
                                    int qualified);
9681
9682
/**
9683
 * xmlXPathCurrentChar:
9684
 * @ctxt:  the XPath parser context
9685
 * @cur:  pointer to the beginning of the char
9686
 * @len:  pointer to the length of the char read
9687
 *
9688
 * The current char value, if using UTF-8 this may actually span multiple
9689
 * bytes in the input buffer.
9690
 *
9691
 * Returns the current char value and its length
9692
 */
9693
9694
static int
9695
179M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9696
179M
    unsigned char c;
9697
179M
    unsigned int val;
9698
179M
    const xmlChar *cur;
9699
9700
179M
    if (ctxt == NULL)
9701
0
  return(0);
9702
179M
    cur = ctxt->cur;
9703
9704
    /*
9705
     * We are supposed to handle UTF8, check it's valid
9706
     * From rfc2044: encoding of the Unicode values on UTF-8:
9707
     *
9708
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9709
     * 0000 0000-0000 007F   0xxxxxxx
9710
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9711
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9712
     *
9713
     * Check for the 0x110000 limit too
9714
     */
9715
179M
    c = *cur;
9716
179M
    if (c & 0x80) {
9717
8.89M
  if ((cur[1] & 0xc0) != 0x80)
9718
269k
      goto encoding_error;
9719
8.62M
  if ((c & 0xe0) == 0xe0) {
9720
9721
217k
      if ((cur[2] & 0xc0) != 0x80)
9722
32.5k
    goto encoding_error;
9723
184k
      if ((c & 0xf0) == 0xf0) {
9724
50.5k
    if (((c & 0xf8) != 0xf0) ||
9725
50.5k
        ((cur[3] & 0xc0) != 0x80))
9726
27.9k
        goto encoding_error;
9727
    /* 4-byte code */
9728
22.5k
    *len = 4;
9729
22.5k
    val = (cur[0] & 0x7) << 18;
9730
22.5k
    val |= (cur[1] & 0x3f) << 12;
9731
22.5k
    val |= (cur[2] & 0x3f) << 6;
9732
22.5k
    val |= cur[3] & 0x3f;
9733
133k
      } else {
9734
        /* 3-byte code */
9735
133k
    *len = 3;
9736
133k
    val = (cur[0] & 0xf) << 12;
9737
133k
    val |= (cur[1] & 0x3f) << 6;
9738
133k
    val |= cur[2] & 0x3f;
9739
133k
      }
9740
8.41M
  } else {
9741
    /* 2-byte code */
9742
8.41M
      *len = 2;
9743
8.41M
      val = (cur[0] & 0x1f) << 6;
9744
8.41M
      val |= cur[1] & 0x3f;
9745
8.41M
  }
9746
8.56M
  if (!IS_CHAR(val)) {
9747
42.4k
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9748
0
  }
9749
8.52M
  return(val);
9750
170M
    } else {
9751
  /* 1-byte code */
9752
170M
  *len = 1;
9753
170M
  return(*cur);
9754
170M
    }
9755
330k
encoding_error:
9756
    /*
9757
     * If we detect an UTF8 error that probably means that the
9758
     * input encoding didn't get properly advertised in the
9759
     * declaration header. Report the error and switch the encoding
9760
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9761
     * encoding !)
9762
     */
9763
330k
    *len = 0;
9764
330k
    XP_ERROR0(XPATH_ENCODING_ERROR);
9765
0
}
9766
9767
/**
9768
 * xmlXPathParseNCName:
9769
 * @ctxt:  the XPath Parser context
9770
 *
9771
 * parse an XML namespace non qualified name.
9772
 *
9773
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9774
 *
9775
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9776
 *                       CombiningChar | Extender
9777
 *
9778
 * Returns the namespace name or NULL
9779
 */
9780
9781
xmlChar *
9782
23.4M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9783
23.4M
    const xmlChar *in;
9784
23.4M
    xmlChar *ret;
9785
23.4M
    int count = 0;
9786
9787
23.4M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9788
    /*
9789
     * Accelerator for simple ASCII names
9790
     */
9791
23.4M
    in = ctxt->cur;
9792
23.4M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9793
23.4M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9794
23.4M
  (*in == '_')) {
9795
21.4M
  in++;
9796
95.5M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9797
95.5M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9798
95.5M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9799
95.5M
         (*in == '_') || (*in == '.') ||
9800
95.5M
         (*in == '-'))
9801
74.1M
      in++;
9802
21.4M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9803
21.4M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9804
21.4M
            (*in == '@') || (*in == '*')) {
9805
7.76M
      count = in - ctxt->cur;
9806
7.76M
      if (count == 0)
9807
0
    return(NULL);
9808
7.76M
      ret = xmlStrndup(ctxt->cur, count);
9809
7.76M
      ctxt->cur = in;
9810
7.76M
      return(ret);
9811
7.76M
  }
9812
21.4M
    }
9813
15.6M
    return(xmlXPathParseNameComplex(ctxt, 0));
9814
23.4M
}
9815
9816
9817
/**
9818
 * xmlXPathParseQName:
9819
 * @ctxt:  the XPath Parser context
9820
 * @prefix:  a xmlChar **
9821
 *
9822
 * parse an XML qualified name
9823
 *
9824
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9825
 *
9826
 * [NS 6] Prefix ::= NCName
9827
 *
9828
 * [NS 7] LocalPart ::= NCName
9829
 *
9830
 * Returns the function returns the local part, and prefix is updated
9831
 *   to get the Prefix if any.
9832
 */
9833
9834
static xmlChar *
9835
6.22M
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9836
6.22M
    xmlChar *ret = NULL;
9837
9838
6.22M
    *prefix = NULL;
9839
6.22M
    ret = xmlXPathParseNCName(ctxt);
9840
6.22M
    if (ret && CUR == ':') {
9841
2.09M
        *prefix = ret;
9842
2.09M
  NEXT;
9843
2.09M
  ret = xmlXPathParseNCName(ctxt);
9844
2.09M
    }
9845
6.22M
    return(ret);
9846
6.22M
}
9847
9848
/**
9849
 * xmlXPathParseName:
9850
 * @ctxt:  the XPath Parser context
9851
 *
9852
 * parse an XML name
9853
 *
9854
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9855
 *                  CombiningChar | Extender
9856
 *
9857
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9858
 *
9859
 * Returns the namespace name or NULL
9860
 */
9861
9862
xmlChar *
9863
67.7k
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9864
67.7k
    const xmlChar *in;
9865
67.7k
    xmlChar *ret;
9866
67.7k
    size_t count = 0;
9867
9868
67.7k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9869
    /*
9870
     * Accelerator for simple ASCII names
9871
     */
9872
67.7k
    in = ctxt->cur;
9873
67.7k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874
67.7k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9875
67.7k
  (*in == '_') || (*in == ':')) {
9876
33.0k
  in++;
9877
433k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878
433k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9879
433k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9880
433k
         (*in == '_') || (*in == '-') ||
9881
433k
         (*in == ':') || (*in == '.'))
9882
399k
      in++;
9883
33.0k
  if ((*in > 0) && (*in < 0x80)) {
9884
21.6k
      count = in - ctxt->cur;
9885
21.6k
            if (count > XML_MAX_NAME_LENGTH) {
9886
0
                ctxt->cur = in;
9887
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9888
0
            }
9889
21.6k
      ret = xmlStrndup(ctxt->cur, count);
9890
21.6k
      ctxt->cur = in;
9891
21.6k
      return(ret);
9892
21.6k
  }
9893
33.0k
    }
9894
46.1k
    return(xmlXPathParseNameComplex(ctxt, 1));
9895
67.7k
}
9896
9897
static xmlChar *
9898
15.7M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9899
15.7M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9900
15.7M
    int len = 0, l;
9901
15.7M
    int c;
9902
9903
    /*
9904
     * Handler for more complex cases
9905
     */
9906
15.7M
    c = CUR_CHAR(l);
9907
15.7M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9908
15.7M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9909
15.7M
        (c == '*') || /* accelerators */
9910
15.7M
  (!IS_LETTER(c) && (c != '_') &&
9911
14.7M
         ((!qualified) || (c != ':')))) {
9912
1.72M
  return(NULL);
9913
1.72M
    }
9914
9915
84.2M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9916
84.2M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9917
84.0M
            (c == '.') || (c == '-') ||
9918
84.0M
      (c == '_') || ((qualified) && (c == ':')) ||
9919
84.0M
      (IS_COMBINING(c)) ||
9920
84.0M
      (IS_EXTENDER(c)))) {
9921
70.3M
  COPY_BUF(l,buf,len,c);
9922
70.3M
  NEXTL(l);
9923
70.3M
  c = CUR_CHAR(l);
9924
70.3M
  if (len >= XML_MAX_NAMELEN) {
9925
      /*
9926
       * Okay someone managed to make a huge name, so he's ready to pay
9927
       * for the processing speed.
9928
       */
9929
125k
      xmlChar *buffer;
9930
125k
      int max = len * 2;
9931
9932
125k
            if (len > XML_MAX_NAME_LENGTH) {
9933
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9934
0
            }
9935
125k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9936
125k
      if (buffer == NULL) {
9937
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9938
0
      }
9939
125k
      memcpy(buffer, buf, len);
9940
1.21M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9941
1.21M
       (c == '.') || (c == '-') ||
9942
1.21M
       (c == '_') || ((qualified) && (c == ':')) ||
9943
1.21M
       (IS_COMBINING(c)) ||
9944
1.21M
       (IS_EXTENDER(c))) {
9945
1.08M
    if (len + 10 > max) {
9946
8.05k
                    xmlChar *tmp;
9947
8.05k
                    if (max > XML_MAX_NAME_LENGTH) {
9948
0
                        xmlFree(buffer);
9949
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9950
0
                    }
9951
8.05k
        max *= 2;
9952
8.05k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9953
8.05k
        if (tmp == NULL) {
9954
0
                        xmlFree(buffer);
9955
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9956
0
        }
9957
8.05k
                    buffer = tmp;
9958
8.05k
    }
9959
1.08M
    COPY_BUF(l,buffer,len,c);
9960
1.08M
    NEXTL(l);
9961
1.08M
    c = CUR_CHAR(l);
9962
1.08M
      }
9963
125k
      buffer[len] = 0;
9964
125k
      return(buffer);
9965
125k
  }
9966
70.3M
    }
9967
13.8M
    if (len == 0)
9968
0
  return(NULL);
9969
13.8M
    return(xmlStrndup(buf, len));
9970
13.8M
}
9971
9972
419k
#define MAX_FRAC 20
9973
9974
/**
9975
 * xmlXPathStringEvalNumber:
9976
 * @str:  A string to scan
9977
 *
9978
 *  [30a]  Float  ::= Number ('e' Digits?)?
9979
 *
9980
 *  [30]   Number ::=   Digits ('.' Digits?)?
9981
 *                    | '.' Digits
9982
 *  [31]   Digits ::=   [0-9]+
9983
 *
9984
 * Compile a Number in the string
9985
 * In complement of the Number expression, this function also handles
9986
 * negative values : '-' Number.
9987
 *
9988
 * Returns the double value.
9989
 */
9990
double
9991
55.1M
xmlXPathStringEvalNumber(const xmlChar *str) {
9992
55.1M
    const xmlChar *cur = str;
9993
55.1M
    double ret;
9994
55.1M
    int ok = 0;
9995
55.1M
    int isneg = 0;
9996
55.1M
    int exponent = 0;
9997
55.1M
    int is_exponent_negative = 0;
9998
55.1M
#ifdef __GNUC__
9999
55.1M
    unsigned long tmp = 0;
10000
55.1M
    double temp;
10001
55.1M
#endif
10002
55.1M
    if (cur == NULL) return(0);
10003
245M
    while (IS_BLANK_CH(*cur)) cur++;
10004
55.1M
    if (*cur == '-') {
10005
321k
  isneg = 1;
10006
321k
  cur++;
10007
321k
    }
10008
55.1M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
10009
51.6M
        return(xmlXPathNAN);
10010
51.6M
    }
10011
10012
3.44M
#ifdef __GNUC__
10013
    /*
10014
     * tmp/temp is a workaround against a gcc compiler bug
10015
     * http://veillard.com/gcc.bug
10016
     */
10017
3.44M
    ret = 0;
10018
9.41M
    while ((*cur >= '0') && (*cur <= '9')) {
10019
5.97M
  ret = ret * 10;
10020
5.97M
  tmp = (*cur - '0');
10021
5.97M
  ok = 1;
10022
5.97M
  cur++;
10023
5.97M
  temp = (double) tmp;
10024
5.97M
  ret = ret + temp;
10025
5.97M
    }
10026
#else
10027
    ret = 0;
10028
    while ((*cur >= '0') && (*cur <= '9')) {
10029
  ret = ret * 10 + (*cur - '0');
10030
  ok = 1;
10031
  cur++;
10032
    }
10033
#endif
10034
10035
3.44M
    if (*cur == '.') {
10036
331k
  int v, frac = 0, max;
10037
331k
  double fraction = 0;
10038
10039
331k
        cur++;
10040
331k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10041
28.5k
      return(xmlXPathNAN);
10042
28.5k
  }
10043
478k
        while (*cur == '0') {
10044
176k
      frac = frac + 1;
10045
176k
      cur++;
10046
176k
        }
10047
302k
        max = frac + MAX_FRAC;
10048
713k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10049
411k
      v = (*cur - '0');
10050
411k
      fraction = fraction * 10 + v;
10051
411k
      frac = frac + 1;
10052
411k
      cur++;
10053
411k
  }
10054
302k
  fraction /= pow(10.0, frac);
10055
302k
  ret = ret + fraction;
10056
323k
  while ((*cur >= '0') && (*cur <= '9'))
10057
21.3k
      cur++;
10058
302k
    }
10059
3.41M
    if ((*cur == 'e') || (*cur == 'E')) {
10060
80.0k
      cur++;
10061
80.0k
      if (*cur == '-') {
10062
8.54k
  is_exponent_negative = 1;
10063
8.54k
  cur++;
10064
71.4k
      } else if (*cur == '+') {
10065
20.4k
        cur++;
10066
20.4k
      }
10067
162k
      while ((*cur >= '0') && (*cur <= '9')) {
10068
82.7k
        if (exponent < 1000000)
10069
79.2k
    exponent = exponent * 10 + (*cur - '0');
10070
82.7k
  cur++;
10071
82.7k
      }
10072
80.0k
    }
10073
3.41M
    while (IS_BLANK_CH(*cur)) cur++;
10074
3.41M
    if (*cur != 0) return(xmlXPathNAN);
10075
2.87M
    if (isneg) ret = -ret;
10076
2.87M
    if (is_exponent_negative) exponent = -exponent;
10077
2.87M
    ret *= pow(10.0, (double)exponent);
10078
2.87M
    return(ret);
10079
3.41M
}
10080
10081
/**
10082
 * xmlXPathCompNumber:
10083
 * @ctxt:  the XPath Parser context
10084
 *
10085
 *  [30]   Number ::=   Digits ('.' Digits?)?
10086
 *                    | '.' Digits
10087
 *  [31]   Digits ::=   [0-9]+
10088
 *
10089
 * Compile a Number, then push it on the stack
10090
 *
10091
 */
10092
static void
10093
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10094
5.32M
{
10095
5.32M
    double ret = 0.0;
10096
5.32M
    int ok = 0;
10097
5.32M
    int exponent = 0;
10098
5.32M
    int is_exponent_negative = 0;
10099
5.32M
    xmlXPathObjectPtr num;
10100
5.32M
#ifdef __GNUC__
10101
5.32M
    unsigned long tmp = 0;
10102
5.32M
    double temp;
10103
5.32M
#endif
10104
10105
5.32M
    CHECK_ERROR;
10106
5.32M
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10107
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10108
0
    }
10109
5.32M
#ifdef __GNUC__
10110
    /*
10111
     * tmp/temp is a workaround against a gcc compiler bug
10112
     * http://veillard.com/gcc.bug
10113
     */
10114
5.32M
    ret = 0;
10115
11.0M
    while ((CUR >= '0') && (CUR <= '9')) {
10116
5.69M
  ret = ret * 10;
10117
5.69M
  tmp = (CUR - '0');
10118
5.69M
        ok = 1;
10119
5.69M
        NEXT;
10120
5.69M
  temp = (double) tmp;
10121
5.69M
  ret = ret + temp;
10122
5.69M
    }
10123
#else
10124
    ret = 0;
10125
    while ((CUR >= '0') && (CUR <= '9')) {
10126
  ret = ret * 10 + (CUR - '0');
10127
  ok = 1;
10128
  NEXT;
10129
    }
10130
#endif
10131
5.32M
    if (CUR == '.') {
10132
117k
  int v, frac = 0, max;
10133
117k
  double fraction = 0;
10134
10135
117k
        NEXT;
10136
117k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10137
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10138
0
        }
10139
144k
        while (CUR == '0') {
10140
27.2k
            frac = frac + 1;
10141
27.2k
            NEXT;
10142
27.2k
        }
10143
117k
        max = frac + MAX_FRAC;
10144
468k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10145
351k
      v = (CUR - '0');
10146
351k
      fraction = fraction * 10 + v;
10147
351k
      frac = frac + 1;
10148
351k
            NEXT;
10149
351k
        }
10150
117k
        fraction /= pow(10.0, frac);
10151
117k
        ret = ret + fraction;
10152
144k
        while ((CUR >= '0') && (CUR <= '9'))
10153
27.1k
            NEXT;
10154
117k
    }
10155
5.32M
    if ((CUR == 'e') || (CUR == 'E')) {
10156
111k
        NEXT;
10157
111k
        if (CUR == '-') {
10158
12.8k
            is_exponent_negative = 1;
10159
12.8k
            NEXT;
10160
99.1k
        } else if (CUR == '+') {
10161
14.2k
      NEXT;
10162
14.2k
  }
10163
266k
        while ((CUR >= '0') && (CUR <= '9')) {
10164
154k
            if (exponent < 1000000)
10165
144k
                exponent = exponent * 10 + (CUR - '0');
10166
154k
            NEXT;
10167
154k
        }
10168
111k
        if (is_exponent_negative)
10169
12.8k
            exponent = -exponent;
10170
111k
        ret *= pow(10.0, (double) exponent);
10171
111k
    }
10172
5.32M
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10173
5.32M
    if (num == NULL) {
10174
0
  ctxt->error = XPATH_MEMORY_ERROR;
10175
5.32M
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10176
5.32M
                              NULL) == -1) {
10177
0
        xmlXPathReleaseObject(ctxt->context, num);
10178
0
    }
10179
5.32M
}
10180
10181
/**
10182
 * xmlXPathParseLiteral:
10183
 * @ctxt:  the XPath Parser context
10184
 *
10185
 * Parse a Literal
10186
 *
10187
 *  [29]   Literal ::=   '"' [^"]* '"'
10188
 *                    | "'" [^']* "'"
10189
 *
10190
 * Returns the value found or NULL in case of error
10191
 */
10192
static xmlChar *
10193
137k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10194
137k
    const xmlChar *q;
10195
137k
    xmlChar *ret = NULL;
10196
10197
137k
    if (CUR == '"') {
10198
116k
        NEXT;
10199
116k
  q = CUR_PTR;
10200
780k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10201
663k
      NEXT;
10202
116k
  if (!IS_CHAR_CH(CUR)) {
10203
37.5k
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10204
79.3k
  } else {
10205
79.3k
      ret = xmlStrndup(q, CUR_PTR - q);
10206
79.3k
      NEXT;
10207
79.3k
        }
10208
116k
    } else if (CUR == '\'') {
10209
832
        NEXT;
10210
832
  q = CUR_PTR;
10211
33.4k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10212
32.6k
      NEXT;
10213
832
  if (!IS_CHAR_CH(CUR)) {
10214
272
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10215
560
  } else {
10216
560
      ret = xmlStrndup(q, CUR_PTR - q);
10217
560
      NEXT;
10218
560
        }
10219
20.1k
    } else {
10220
20.1k
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10221
0
    }
10222
79.9k
    return(ret);
10223
137k
}
10224
10225
/**
10226
 * xmlXPathCompLiteral:
10227
 * @ctxt:  the XPath Parser context
10228
 *
10229
 * Parse a Literal and push it on the stack.
10230
 *
10231
 *  [29]   Literal ::=   '"' [^"]* '"'
10232
 *                    | "'" [^']* "'"
10233
 *
10234
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10235
 */
10236
static void
10237
381k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10238
381k
    const xmlChar *q;
10239
381k
    xmlChar *ret = NULL;
10240
381k
    xmlXPathObjectPtr lit;
10241
10242
381k
    if (CUR == '"') {
10243
159k
        NEXT;
10244
159k
  q = CUR_PTR;
10245
512k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10246
352k
      NEXT;
10247
159k
  if (!IS_CHAR_CH(CUR)) {
10248
15.9k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10249
143k
  } else {
10250
143k
      ret = xmlStrndup(q, CUR_PTR - q);
10251
143k
      NEXT;
10252
143k
        }
10253
222k
    } else if (CUR == '\'') {
10254
222k
        NEXT;
10255
222k
  q = CUR_PTR;
10256
4.73M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10257
4.51M
      NEXT;
10258
222k
  if (!IS_CHAR_CH(CUR)) {
10259
800
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10260
221k
  } else {
10261
221k
      ret = xmlStrndup(q, CUR_PTR - q);
10262
221k
      NEXT;
10263
221k
        }
10264
222k
    } else {
10265
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10266
0
    }
10267
364k
    if (ret == NULL) return;
10268
364k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10269
364k
    if (lit == NULL) {
10270
0
  ctxt->error = XPATH_MEMORY_ERROR;
10271
364k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10272
364k
                              NULL) == -1) {
10273
0
        xmlXPathReleaseObject(ctxt->context, lit);
10274
0
    }
10275
364k
    xmlFree(ret);
10276
364k
}
10277
10278
/**
10279
 * xmlXPathCompVariableReference:
10280
 * @ctxt:  the XPath Parser context
10281
 *
10282
 * Parse a VariableReference, evaluate it and push it on the stack.
10283
 *
10284
 * The variable bindings consist of a mapping from variable names
10285
 * to variable values. The value of a variable is an object, which can be
10286
 * of any of the types that are possible for the value of an expression,
10287
 * and may also be of additional types not specified here.
10288
 *
10289
 * Early evaluation is possible since:
10290
 * The variable bindings [...] used to evaluate a subexpression are
10291
 * always the same as those used to evaluate the containing expression.
10292
 *
10293
 *  [36]   VariableReference ::=   '$' QName
10294
 */
10295
static void
10296
536k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10297
536k
    xmlChar *name;
10298
536k
    xmlChar *prefix;
10299
10300
536k
    SKIP_BLANKS;
10301
536k
    if (CUR != '$') {
10302
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10303
0
    }
10304
536k
    NEXT;
10305
536k
    name = xmlXPathParseQName(ctxt, &prefix);
10306
536k
    if (name == NULL) {
10307
80.8k
        xmlFree(prefix);
10308
80.8k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10309
0
    }
10310
456k
    ctxt->comp->last = -1;
10311
456k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10312
0
        xmlFree(prefix);
10313
0
        xmlFree(name);
10314
0
    }
10315
456k
    SKIP_BLANKS;
10316
456k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10317
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10318
0
    }
10319
456k
}
10320
10321
/**
10322
 * xmlXPathIsNodeType:
10323
 * @name:  a name string
10324
 *
10325
 * Is the name given a NodeType one.
10326
 *
10327
 *  [38]   NodeType ::=   'comment'
10328
 *                    | 'text'
10329
 *                    | 'processing-instruction'
10330
 *                    | 'node'
10331
 *
10332
 * Returns 1 if true 0 otherwise
10333
 */
10334
int
10335
5.98M
xmlXPathIsNodeType(const xmlChar *name) {
10336
5.98M
    if (name == NULL)
10337
0
  return(0);
10338
10339
5.98M
    if (xmlStrEqual(name, BAD_CAST "node"))
10340
144k
  return(1);
10341
5.84M
    if (xmlStrEqual(name, BAD_CAST "text"))
10342
54.7k
  return(1);
10343
5.78M
    if (xmlStrEqual(name, BAD_CAST "comment"))
10344
16.2k
  return(1);
10345
5.77M
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10346
85.3k
  return(1);
10347
5.68M
    return(0);
10348
5.77M
}
10349
10350
/**
10351
 * xmlXPathCompFunctionCall:
10352
 * @ctxt:  the XPath Parser context
10353
 *
10354
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10355
 *  [17]   Argument ::=   Expr
10356
 *
10357
 * Compile a function call, the evaluation of all arguments are
10358
 * pushed on the stack
10359
 */
10360
static void
10361
5.68M
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10362
5.68M
    xmlChar *name;
10363
5.68M
    xmlChar *prefix;
10364
5.68M
    int nbargs = 0;
10365
5.68M
    int sort = 1;
10366
10367
5.68M
    name = xmlXPathParseQName(ctxt, &prefix);
10368
5.68M
    if (name == NULL) {
10369
22.0k
  xmlFree(prefix);
10370
22.0k
  XP_ERROR(XPATH_EXPR_ERROR);
10371
0
    }
10372
5.66M
    SKIP_BLANKS;
10373
#ifdef DEBUG_EXPR
10374
    if (prefix == NULL)
10375
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10376
      name);
10377
    else
10378
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10379
      prefix, name);
10380
#endif
10381
10382
5.66M
    if (CUR != '(') {
10383
20.1k
  xmlFree(name);
10384
20.1k
  xmlFree(prefix);
10385
20.1k
  XP_ERROR(XPATH_EXPR_ERROR);
10386
0
    }
10387
5.64M
    NEXT;
10388
5.64M
    SKIP_BLANKS;
10389
10390
    /*
10391
    * Optimization for count(): we don't need the node-set to be sorted.
10392
    */
10393
5.64M
    if ((prefix == NULL) && (name[0] == 'c') &&
10394
5.64M
  xmlStrEqual(name, BAD_CAST "count"))
10395
151k
    {
10396
151k
  sort = 0;
10397
151k
    }
10398
5.64M
    ctxt->comp->last = -1;
10399
5.64M
    if (CUR != ')') {
10400
5.02M
  while (CUR != 0) {
10401
4.32M
      int op1 = ctxt->comp->last;
10402
4.32M
      ctxt->comp->last = -1;
10403
4.32M
      xmlXPathCompileExpr(ctxt, sort);
10404
4.32M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10405
236k
    xmlFree(name);
10406
236k
    xmlFree(prefix);
10407
236k
    return;
10408
236k
      }
10409
4.08M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10410
4.08M
      nbargs++;
10411
4.08M
      if (CUR == ')') break;
10412
1.47M
      if (CUR != ',') {
10413
184k
    xmlFree(name);
10414
184k
    xmlFree(prefix);
10415
184k
    XP_ERROR(XPATH_EXPR_ERROR);
10416
0
      }
10417
1.29M
      NEXT;
10418
1.29M
      SKIP_BLANKS;
10419
1.29M
  }
10420
3.73M
    }
10421
5.22M
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10422
0
        xmlFree(prefix);
10423
0
        xmlFree(name);
10424
0
    }
10425
5.22M
    NEXT;
10426
5.22M
    SKIP_BLANKS;
10427
5.22M
}
10428
10429
/**
10430
 * xmlXPathCompPrimaryExpr:
10431
 * @ctxt:  the XPath Parser context
10432
 *
10433
 *  [15]   PrimaryExpr ::=   VariableReference
10434
 *                | '(' Expr ')'
10435
 *                | Literal
10436
 *                | Number
10437
 *                | FunctionCall
10438
 *
10439
 * Compile a primary expression.
10440
 */
10441
static void
10442
14.4M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10443
14.4M
    SKIP_BLANKS;
10444
14.4M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10445
13.8M
    else if (CUR == '(') {
10446
2.50M
  NEXT;
10447
2.50M
  SKIP_BLANKS;
10448
2.50M
  xmlXPathCompileExpr(ctxt, 1);
10449
2.50M
  CHECK_ERROR;
10450
2.16M
  if (CUR != ')') {
10451
104k
      XP_ERROR(XPATH_EXPR_ERROR);
10452
0
  }
10453
2.06M
  NEXT;
10454
2.06M
  SKIP_BLANKS;
10455
11.3M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10456
5.32M
  xmlXPathCompNumber(ctxt);
10457
6.06M
    } else if ((CUR == '\'') || (CUR == '"')) {
10458
381k
  xmlXPathCompLiteral(ctxt);
10459
5.68M
    } else {
10460
5.68M
  xmlXPathCompFunctionCall(ctxt);
10461
5.68M
    }
10462
13.9M
    SKIP_BLANKS;
10463
13.9M
}
10464
10465
/**
10466
 * xmlXPathCompFilterExpr:
10467
 * @ctxt:  the XPath Parser context
10468
 *
10469
 *  [20]   FilterExpr ::=   PrimaryExpr
10470
 *               | FilterExpr Predicate
10471
 *
10472
 * Compile a filter expression.
10473
 * Square brackets are used to filter expressions in the same way that
10474
 * they are used in location paths. It is an error if the expression to
10475
 * be filtered does not evaluate to a node-set. The context node list
10476
 * used for evaluating the expression in square brackets is the node-set
10477
 * to be filtered listed in document order.
10478
 */
10479
10480
static void
10481
14.4M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10482
14.4M
    xmlXPathCompPrimaryExpr(ctxt);
10483
14.4M
    CHECK_ERROR;
10484
13.3M
    SKIP_BLANKS;
10485
10486
15.3M
    while (CUR == '[') {
10487
1.92M
  xmlXPathCompPredicate(ctxt, 1);
10488
1.92M
  SKIP_BLANKS;
10489
1.92M
    }
10490
10491
10492
13.3M
}
10493
10494
/**
10495
 * xmlXPathScanName:
10496
 * @ctxt:  the XPath Parser context
10497
 *
10498
 * Trickery: parse an XML name but without consuming the input flow
10499
 * Needed to avoid insanity in the parser state.
10500
 *
10501
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10502
 *                  CombiningChar | Extender
10503
 *
10504
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10505
 *
10506
 * [6] Names ::= Name (S Name)*
10507
 *
10508
 * Returns the Name parsed or NULL
10509
 */
10510
10511
static xmlChar *
10512
14.2M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10513
14.2M
    int l;
10514
14.2M
    int c;
10515
14.2M
    const xmlChar *cur;
10516
14.2M
    xmlChar *ret;
10517
10518
14.2M
    cur = ctxt->cur;
10519
10520
14.2M
    c = CUR_CHAR(l);
10521
14.2M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10522
14.2M
  (!IS_LETTER(c) && (c != '_') &&
10523
14.1M
         (c != ':'))) {
10524
958k
  return(NULL);
10525
958k
    }
10526
10527
91.1M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10528
91.1M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10529
89.8M
            (c == '.') || (c == '-') ||
10530
89.8M
      (c == '_') || (c == ':') ||
10531
89.8M
      (IS_COMBINING(c)) ||
10532
89.8M
      (IS_EXTENDER(c)))) {
10533
77.8M
  NEXTL(l);
10534
77.8M
  c = CUR_CHAR(l);
10535
77.8M
    }
10536
13.3M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10537
13.3M
    ctxt->cur = cur;
10538
13.3M
    return(ret);
10539
14.2M
}
10540
10541
/**
10542
 * xmlXPathCompPathExpr:
10543
 * @ctxt:  the XPath Parser context
10544
 *
10545
 *  [19]   PathExpr ::=   LocationPath
10546
 *               | FilterExpr
10547
 *               | FilterExpr '/' RelativeLocationPath
10548
 *               | FilterExpr '//' RelativeLocationPath
10549
 *
10550
 * Compile a path expression.
10551
 * The / operator and // operators combine an arbitrary expression
10552
 * and a relative location path. It is an error if the expression
10553
 * does not evaluate to a node-set.
10554
 * The / operator does composition in the same way as when / is
10555
 * used in a location path. As in location paths, // is short for
10556
 * /descendant-or-self::node()/.
10557
 */
10558
10559
static void
10560
32.1M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10561
32.1M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10562
32.1M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10563
10564
32.1M
    SKIP_BLANKS;
10565
32.1M
    if ((CUR == '$') || (CUR == '(') ||
10566
32.1M
  (IS_ASCII_DIGIT(CUR)) ||
10567
32.1M
        (CUR == '\'') || (CUR == '"') ||
10568
32.1M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10569
8.74M
  lc = 0;
10570
23.3M
    } else if (CUR == '*') {
10571
  /* relative or absolute location path */
10572
3.03M
  lc = 1;
10573
20.3M
    } else if (CUR == '/') {
10574
  /* relative or absolute location path */
10575
4.09M
  lc = 1;
10576
16.2M
    } else if (CUR == '@') {
10577
  /* relative abbreviated attribute location path */
10578
174k
  lc = 1;
10579
16.0M
    } else if (CUR == '.') {
10580
  /* relative abbreviated attribute location path */
10581
1.78M
  lc = 1;
10582
14.2M
    } else {
10583
  /*
10584
   * Problem is finding if we have a name here whether it's:
10585
   *   - a nodetype
10586
   *   - a function call in which case it's followed by '('
10587
   *   - an axis in which case it's followed by ':'
10588
   *   - a element name
10589
   * We do an a priori analysis here rather than having to
10590
   * maintain parsed token content through the recursive function
10591
   * calls. This looks uglier but makes the code easier to
10592
   * read/write/debug.
10593
   */
10594
14.2M
  SKIP_BLANKS;
10595
14.2M
  name = xmlXPathScanName(ctxt);
10596
14.2M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10597
#ifdef DEBUG_STEP
10598
      xmlGenericError(xmlGenericErrorContext,
10599
        "PathExpr: Axis\n");
10600
#endif
10601
486k
      lc = 1;
10602
486k
      xmlFree(name);
10603
13.7M
  } else if (name != NULL) {
10604
12.8M
      int len =xmlStrlen(name);
10605
10606
10607
13.9M
      while (NXT(len) != 0) {
10608
13.3M
    if (NXT(len) == '/') {
10609
        /* element name */
10610
#ifdef DEBUG_STEP
10611
        xmlGenericError(xmlGenericErrorContext,
10612
          "PathExpr: AbbrRelLocation\n");
10613
#endif
10614
596k
        lc = 1;
10615
596k
        break;
10616
12.8M
    } else if (IS_BLANK_CH(NXT(len))) {
10617
        /* ignore blanks */
10618
1.11M
        ;
10619
11.6M
    } else if (NXT(len) == ':') {
10620
#ifdef DEBUG_STEP
10621
        xmlGenericError(xmlGenericErrorContext,
10622
          "PathExpr: AbbrRelLocation\n");
10623
#endif
10624
14.4k
        lc = 1;
10625
14.4k
        break;
10626
11.6M
    } else if ((NXT(len) == '(')) {
10627
        /* Node Type or Function */
10628
5.98M
        if (xmlXPathIsNodeType(name)) {
10629
#ifdef DEBUG_STEP
10630
            xmlGenericError(xmlGenericErrorContext,
10631
        "PathExpr: Type search\n");
10632
#endif
10633
300k
      lc = 1;
10634
#ifdef LIBXML_XPTR_LOCS_ENABLED
10635
                    } else if (ctxt->xptr &&
10636
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10637
                        lc = 1;
10638
#endif
10639
5.68M
        } else {
10640
#ifdef DEBUG_STEP
10641
            xmlGenericError(xmlGenericErrorContext,
10642
        "PathExpr: function call\n");
10643
#endif
10644
5.68M
      lc = 0;
10645
5.68M
        }
10646
5.98M
                    break;
10647
5.98M
    } else if ((NXT(len) == '[')) {
10648
        /* element name */
10649
#ifdef DEBUG_STEP
10650
        xmlGenericError(xmlGenericErrorContext,
10651
          "PathExpr: AbbrRelLocation\n");
10652
#endif
10653
135k
        lc = 1;
10654
135k
        break;
10655
5.54M
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10656
5.54M
         (NXT(len) == '=')) {
10657
913k
        lc = 1;
10658
913k
        break;
10659
4.63M
    } else {
10660
4.63M
        lc = 1;
10661
4.63M
        break;
10662
4.63M
    }
10663
1.11M
    len++;
10664
1.11M
      }
10665
12.8M
      if (NXT(len) == 0) {
10666
#ifdef DEBUG_STEP
10667
    xmlGenericError(xmlGenericErrorContext,
10668
      "PathExpr: AbbrRelLocation\n");
10669
#endif
10670
    /* element name */
10671
539k
    lc = 1;
10672
539k
      }
10673
12.8M
      xmlFree(name);
10674
12.8M
  } else {
10675
      /* make sure all cases are covered explicitly */
10676
958k
      XP_ERROR(XPATH_EXPR_ERROR);
10677
0
  }
10678
14.2M
    }
10679
10680
31.1M
    if (lc) {
10681
16.7M
  if (CUR == '/') {
10682
4.09M
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10683
12.6M
  } else {
10684
12.6M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10685
12.6M
  }
10686
16.7M
  xmlXPathCompLocationPath(ctxt);
10687
16.7M
    } else {
10688
14.4M
  xmlXPathCompFilterExpr(ctxt);
10689
14.4M
  CHECK_ERROR;
10690
13.3M
  if ((CUR == '/') && (NXT(1) == '/')) {
10691
229k
      SKIP(2);
10692
229k
      SKIP_BLANKS;
10693
10694
229k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10695
229k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10696
10697
229k
      xmlXPathCompRelativeLocationPath(ctxt);
10698
13.0M
  } else if (CUR == '/') {
10699
1.90M
      xmlXPathCompRelativeLocationPath(ctxt);
10700
1.90M
  }
10701
13.3M
    }
10702
30.0M
    SKIP_BLANKS;
10703
30.0M
}
10704
10705
/**
10706
 * xmlXPathCompUnionExpr:
10707
 * @ctxt:  the XPath Parser context
10708
 *
10709
 *  [18]   UnionExpr ::=   PathExpr
10710
 *               | UnionExpr '|' PathExpr
10711
 *
10712
 * Compile an union expression.
10713
 */
10714
10715
static void
10716
28.6M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10717
28.6M
    xmlXPathCompPathExpr(ctxt);
10718
28.6M
    CHECK_ERROR;
10719
25.7M
    SKIP_BLANKS;
10720
29.2M
    while (CUR == '|') {
10721
3.44M
  int op1 = ctxt->comp->last;
10722
3.44M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723
10724
3.44M
  NEXT;
10725
3.44M
  SKIP_BLANKS;
10726
3.44M
  xmlXPathCompPathExpr(ctxt);
10727
10728
3.44M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10729
10730
3.44M
  SKIP_BLANKS;
10731
3.44M
    }
10732
25.7M
}
10733
10734
/**
10735
 * xmlXPathCompUnaryExpr:
10736
 * @ctxt:  the XPath Parser context
10737
 *
10738
 *  [27]   UnaryExpr ::=   UnionExpr
10739
 *                   | '-' UnaryExpr
10740
 *
10741
 * Compile an unary expression.
10742
 */
10743
10744
static void
10745
28.6M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10746
28.6M
    int minus = 0;
10747
28.6M
    int found = 0;
10748
10749
28.6M
    SKIP_BLANKS;
10750
28.9M
    while (CUR == '-') {
10751
321k
        minus = 1 - minus;
10752
321k
  found = 1;
10753
321k
  NEXT;
10754
321k
  SKIP_BLANKS;
10755
321k
    }
10756
10757
28.6M
    xmlXPathCompUnionExpr(ctxt);
10758
28.6M
    CHECK_ERROR;
10759
25.4M
    if (found) {
10760
199k
  if (minus)
10761
180k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10762
19.1k
  else
10763
19.1k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10764
199k
    }
10765
25.4M
}
10766
10767
/**
10768
 * xmlXPathCompMultiplicativeExpr:
10769
 * @ctxt:  the XPath Parser context
10770
 *
10771
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10772
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10773
 *                   | MultiplicativeExpr 'div' UnaryExpr
10774
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10775
 *  [34]   MultiplyOperator ::=   '*'
10776
 *
10777
 * Compile an Additive expression.
10778
 */
10779
10780
static void
10781
26.3M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10782
26.3M
    xmlXPathCompUnaryExpr(ctxt);
10783
26.3M
    CHECK_ERROR;
10784
23.4M
    SKIP_BLANKS;
10785
25.4M
    while ((CUR == '*') ||
10786
25.4M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10787
25.4M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10788
2.32M
  int op = -1;
10789
2.32M
  int op1 = ctxt->comp->last;
10790
10791
2.32M
        if (CUR == '*') {
10792
2.05M
      op = 0;
10793
2.05M
      NEXT;
10794
2.05M
  } else if (CUR == 'd') {
10795
95.0k
      op = 1;
10796
95.0k
      SKIP(3);
10797
176k
  } else if (CUR == 'm') {
10798
176k
      op = 2;
10799
176k
      SKIP(3);
10800
176k
  }
10801
2.32M
  SKIP_BLANKS;
10802
2.32M
        xmlXPathCompUnaryExpr(ctxt);
10803
2.32M
  CHECK_ERROR;
10804
1.99M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10805
1.99M
  SKIP_BLANKS;
10806
1.99M
    }
10807
23.4M
}
10808
10809
/**
10810
 * xmlXPathCompAdditiveExpr:
10811
 * @ctxt:  the XPath Parser context
10812
 *
10813
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10814
 *                   | AdditiveExpr '+' MultiplicativeExpr
10815
 *                   | AdditiveExpr '-' MultiplicativeExpr
10816
 *
10817
 * Compile an Additive expression.
10818
 */
10819
10820
static void
10821
25.4M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10822
10823
25.4M
    xmlXPathCompMultiplicativeExpr(ctxt);
10824
25.4M
    CHECK_ERROR;
10825
22.3M
    SKIP_BLANKS;
10826
23.1M
    while ((CUR == '+') || (CUR == '-')) {
10827
852k
  int plus;
10828
852k
  int op1 = ctxt->comp->last;
10829
10830
852k
        if (CUR == '+') plus = 1;
10831
454k
  else plus = 0;
10832
852k
  NEXT;
10833
852k
  SKIP_BLANKS;
10834
852k
        xmlXPathCompMultiplicativeExpr(ctxt);
10835
852k
  CHECK_ERROR;
10836
762k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10837
762k
  SKIP_BLANKS;
10838
762k
    }
10839
22.3M
}
10840
10841
/**
10842
 * xmlXPathCompRelationalExpr:
10843
 * @ctxt:  the XPath Parser context
10844
 *
10845
 *  [24]   RelationalExpr ::=   AdditiveExpr
10846
 *                 | RelationalExpr '<' AdditiveExpr
10847
 *                 | RelationalExpr '>' AdditiveExpr
10848
 *                 | RelationalExpr '<=' AdditiveExpr
10849
 *                 | RelationalExpr '>=' AdditiveExpr
10850
 *
10851
 *  A <= B > C is allowed ? Answer from James, yes with
10852
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10853
 *  which is basically what got implemented.
10854
 *
10855
 * Compile a Relational expression, then push the result
10856
 * on the stack
10857
 */
10858
10859
static void
10860
23.0M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10861
23.0M
    xmlXPathCompAdditiveExpr(ctxt);
10862
23.0M
    CHECK_ERROR;
10863
20.0M
    SKIP_BLANKS;
10864
22.2M
    while ((CUR == '<') || (CUR == '>')) {
10865
2.44M
  int inf, strict;
10866
2.44M
  int op1 = ctxt->comp->last;
10867
10868
2.44M
        if (CUR == '<') inf = 1;
10869
1.40M
  else inf = 0;
10870
2.44M
  if (NXT(1) == '=') strict = 0;
10871
2.37M
  else strict = 1;
10872
2.44M
  NEXT;
10873
2.44M
  if (!strict) NEXT;
10874
2.44M
  SKIP_BLANKS;
10875
2.44M
        xmlXPathCompAdditiveExpr(ctxt);
10876
2.44M
  CHECK_ERROR;
10877
2.17M
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10878
2.17M
  SKIP_BLANKS;
10879
2.17M
    }
10880
20.0M
}
10881
10882
/**
10883
 * xmlXPathCompEqualityExpr:
10884
 * @ctxt:  the XPath Parser context
10885
 *
10886
 *  [23]   EqualityExpr ::=   RelationalExpr
10887
 *                 | EqualityExpr '=' RelationalExpr
10888
 *                 | EqualityExpr '!=' RelationalExpr
10889
 *
10890
 *  A != B != C is allowed ? Answer from James, yes with
10891
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10892
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10893
 *  which is basically what got implemented.
10894
 *
10895
 * Compile an Equality expression.
10896
 *
10897
 */
10898
static void
10899
21.1M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10900
21.1M
    xmlXPathCompRelationalExpr(ctxt);
10901
21.1M
    CHECK_ERROR;
10902
18.1M
    SKIP_BLANKS;
10903
19.8M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10904
1.87M
  int eq;
10905
1.87M
  int op1 = ctxt->comp->last;
10906
10907
1.87M
        if (CUR == '=') eq = 1;
10908
52.7k
  else eq = 0;
10909
1.87M
  NEXT;
10910
1.87M
  if (!eq) NEXT;
10911
1.87M
  SKIP_BLANKS;
10912
1.87M
        xmlXPathCompRelationalExpr(ctxt);
10913
1.87M
  CHECK_ERROR;
10914
1.60M
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10915
1.60M
  SKIP_BLANKS;
10916
1.60M
    }
10917
18.1M
}
10918
10919
/**
10920
 * xmlXPathCompAndExpr:
10921
 * @ctxt:  the XPath Parser context
10922
 *
10923
 *  [22]   AndExpr ::=   EqualityExpr
10924
 *                 | AndExpr 'and' EqualityExpr
10925
 *
10926
 * Compile an AND expression.
10927
 *
10928
 */
10929
static void
10930
20.8M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10931
20.8M
    xmlXPathCompEqualityExpr(ctxt);
10932
20.8M
    CHECK_ERROR;
10933
17.6M
    SKIP_BLANKS;
10934
17.9M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10935
267k
  int op1 = ctxt->comp->last;
10936
267k
        SKIP(3);
10937
267k
  SKIP_BLANKS;
10938
267k
        xmlXPathCompEqualityExpr(ctxt);
10939
267k
  CHECK_ERROR;
10940
234k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10941
234k
  SKIP_BLANKS;
10942
234k
    }
10943
17.6M
}
10944
10945
/**
10946
 * xmlXPathCompileExpr:
10947
 * @ctxt:  the XPath Parser context
10948
 *
10949
 *  [14]   Expr ::=   OrExpr
10950
 *  [21]   OrExpr ::=   AndExpr
10951
 *                 | OrExpr 'or' AndExpr
10952
 *
10953
 * Parse and compile an expression
10954
 */
10955
static void
10956
20.6M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10957
20.6M
    xmlXPathContextPtr xpctxt = ctxt->context;
10958
10959
20.6M
    if (xpctxt != NULL) {
10960
20.6M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10961
20.6M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10962
        /*
10963
         * Parsing a single '(' pushes about 10 functions on the call stack
10964
         * before recursing!
10965
         */
10966
20.6M
        xpctxt->depth += 10;
10967
20.6M
    }
10968
10969
20.6M
    xmlXPathCompAndExpr(ctxt);
10970
20.6M
    CHECK_ERROR;
10971
17.4M
    SKIP_BLANKS;
10972
17.6M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10973
246k
  int op1 = ctxt->comp->last;
10974
246k
        SKIP(2);
10975
246k
  SKIP_BLANKS;
10976
246k
        xmlXPathCompAndExpr(ctxt);
10977
246k
  CHECK_ERROR;
10978
211k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10979
211k
  SKIP_BLANKS;
10980
211k
    }
10981
17.4M
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10982
  /* more ops could be optimized too */
10983
  /*
10984
  * This is the main place to eliminate sorting for
10985
  * operations which don't require a sorted node-set.
10986
  * E.g. count().
10987
  */
10988
12.4M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10989
12.4M
    }
10990
10991
17.4M
    if (xpctxt != NULL)
10992
17.4M
        xpctxt->depth -= 10;
10993
17.4M
}
10994
10995
/**
10996
 * xmlXPathCompPredicate:
10997
 * @ctxt:  the XPath Parser context
10998
 * @filter:  act as a filter
10999
 *
11000
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11001
 *  [9]   PredicateExpr ::=   Expr
11002
 *
11003
 * Compile a predicate expression
11004
 */
11005
static void
11006
4.67M
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11007
4.67M
    int op1 = ctxt->comp->last;
11008
11009
4.67M
    SKIP_BLANKS;
11010
4.67M
    if (CUR != '[') {
11011
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11012
0
    }
11013
4.67M
    NEXT;
11014
4.67M
    SKIP_BLANKS;
11015
11016
4.67M
    ctxt->comp->last = -1;
11017
    /*
11018
    * This call to xmlXPathCompileExpr() will deactivate sorting
11019
    * of the predicate result.
11020
    * TODO: Sorting is still activated for filters, since I'm not
11021
    *  sure if needed. Normally sorting should not be needed, since
11022
    *  a filter can only diminish the number of items in a sequence,
11023
    *  but won't change its order; so if the initial sequence is sorted,
11024
    *  subsequent sorting is not needed.
11025
    */
11026
4.67M
    if (! filter)
11027
2.74M
  xmlXPathCompileExpr(ctxt, 0);
11028
1.92M
    else
11029
1.92M
  xmlXPathCompileExpr(ctxt, 1);
11030
4.67M
    CHECK_ERROR;
11031
11032
4.20M
    if (CUR != ']') {
11033
106k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11034
0
    }
11035
11036
4.09M
    if (filter)
11037
1.81M
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11038
2.28M
    else
11039
2.28M
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11040
11041
4.09M
    NEXT;
11042
4.09M
    SKIP_BLANKS;
11043
4.09M
}
11044
11045
/**
11046
 * xmlXPathCompNodeTest:
11047
 * @ctxt:  the XPath Parser context
11048
 * @test:  pointer to a xmlXPathTestVal
11049
 * @type:  pointer to a xmlXPathTypeVal
11050
 * @prefix:  placeholder for a possible name prefix
11051
 *
11052
 * [7] NodeTest ::=   NameTest
11053
 *        | NodeType '(' ')'
11054
 *        | 'processing-instruction' '(' Literal ')'
11055
 *
11056
 * [37] NameTest ::=  '*'
11057
 *        | NCName ':' '*'
11058
 *        | QName
11059
 * [38] NodeType ::= 'comment'
11060
 *       | 'text'
11061
 *       | 'processing-instruction'
11062
 *       | 'node'
11063
 *
11064
 * Returns the name found and updates @test, @type and @prefix appropriately
11065
 */
11066
static xmlChar *
11067
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11068
               xmlXPathTypeVal *type, xmlChar **prefix,
11069
17.3M
         xmlChar *name) {
11070
17.3M
    int blanks;
11071
11072
17.3M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11073
0
  STRANGE;
11074
0
  return(NULL);
11075
0
    }
11076
17.3M
    *type = (xmlXPathTypeVal) 0;
11077
17.3M
    *test = (xmlXPathTestVal) 0;
11078
17.3M
    *prefix = NULL;
11079
17.3M
    SKIP_BLANKS;
11080
11081
17.3M
    if ((name == NULL) && (CUR == '*')) {
11082
  /*
11083
   * All elements
11084
   */
11085
5.16M
  NEXT;
11086
5.16M
  *test = NODE_TEST_ALL;
11087
5.16M
  return(NULL);
11088
5.16M
    }
11089
11090
12.2M
    if (name == NULL)
11091
1.76M
  name = xmlXPathParseNCName(ctxt);
11092
12.2M
    if (name == NULL) {
11093
360k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11094
0
    }
11095
11096
11.8M
    blanks = IS_BLANK_CH(CUR);
11097
11.8M
    SKIP_BLANKS;
11098
11.8M
    if (CUR == '(') {
11099
1.28M
  NEXT;
11100
  /*
11101
   * NodeType or PI search
11102
   */
11103
1.28M
  if (xmlStrEqual(name, BAD_CAST "comment"))
11104
68.2k
      *type = NODE_TYPE_COMMENT;
11105
1.21M
  else if (xmlStrEqual(name, BAD_CAST "node"))
11106
406k
      *type = NODE_TYPE_NODE;
11107
813k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11108
183k
      *type = NODE_TYPE_PI;
11109
629k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11110
603k
      *type = NODE_TYPE_TEXT;
11111
26.7k
  else {
11112
26.7k
      if (name != NULL)
11113
26.7k
    xmlFree(name);
11114
26.7k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11115
0
  }
11116
11117
1.26M
  *test = NODE_TEST_TYPE;
11118
11119
1.26M
  SKIP_BLANKS;
11120
1.26M
  if (*type == NODE_TYPE_PI) {
11121
      /*
11122
       * Specific case: search a PI by name.
11123
       */
11124
183k
      if (name != NULL)
11125
183k
    xmlFree(name);
11126
183k
      name = NULL;
11127
183k
      if (CUR != ')') {
11128
137k
    name = xmlXPathParseLiteral(ctxt);
11129
137k
                if (name == NULL) {
11130
57.9k
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11131
0
                }
11132
79.9k
    *test = NODE_TEST_PI;
11133
79.9k
    SKIP_BLANKS;
11134
79.9k
      }
11135
183k
  }
11136
1.20M
  if (CUR != ')') {
11137
99.6k
      if (name != NULL)
11138
99.6k
    xmlFree(name);
11139
99.6k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11140
0
  }
11141
1.10M
  NEXT;
11142
1.10M
  return(name);
11143
1.20M
    }
11144
10.5M
    *test = NODE_TEST_NAME;
11145
10.5M
    if ((!blanks) && (CUR == ':')) {
11146
969k
  NEXT;
11147
11148
  /*
11149
   * Since currently the parser context don't have a
11150
   * namespace list associated:
11151
   * The namespace name for this prefix can be computed
11152
   * only at evaluation time. The compilation is done
11153
   * outside of any context.
11154
   */
11155
#if 0
11156
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11157
  if (name != NULL)
11158
      xmlFree(name);
11159
  if (*prefix == NULL) {
11160
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11161
  }
11162
#else
11163
969k
  *prefix = name;
11164
969k
#endif
11165
11166
969k
  if (CUR == '*') {
11167
      /*
11168
       * All elements
11169
       */
11170
275k
      NEXT;
11171
275k
      *test = NODE_TEST_ALL;
11172
275k
      return(NULL);
11173
275k
  }
11174
11175
694k
  name = xmlXPathParseNCName(ctxt);
11176
694k
  if (name == NULL) {
11177
134k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11178
0
  }
11179
694k
    }
11180
10.1M
    return(name);
11181
10.5M
}
11182
11183
/**
11184
 * xmlXPathIsAxisName:
11185
 * @name:  a preparsed name token
11186
 *
11187
 * [6] AxisName ::=   'ancestor'
11188
 *                  | 'ancestor-or-self'
11189
 *                  | 'attribute'
11190
 *                  | 'child'
11191
 *                  | 'descendant'
11192
 *                  | 'descendant-or-self'
11193
 *                  | 'following'
11194
 *                  | 'following-sibling'
11195
 *                  | 'namespace'
11196
 *                  | 'parent'
11197
 *                  | 'preceding'
11198
 *                  | 'preceding-sibling'
11199
 *                  | 'self'
11200
 *
11201
 * Returns the axis or 0
11202
 */
11203
static xmlXPathAxisVal
11204
11.5M
xmlXPathIsAxisName(const xmlChar *name) {
11205
11.5M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11206
11.5M
    switch (name[0]) {
11207
1.12M
  case 'a':
11208
1.12M
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11209
62.5k
    ret = AXIS_ANCESTOR;
11210
1.12M
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11211
28.7k
    ret = AXIS_ANCESTOR_OR_SELF;
11212
1.12M
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11213
38.2k
    ret = AXIS_ATTRIBUTE;
11214
1.12M
      break;
11215
426k
  case 'c':
11216
426k
      if (xmlStrEqual(name, BAD_CAST "child"))
11217
57.8k
    ret = AXIS_CHILD;
11218
426k
      break;
11219
424k
  case 'd':
11220
424k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11221
42.9k
    ret = AXIS_DESCENDANT;
11222
424k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11223
83.3k
    ret = AXIS_DESCENDANT_OR_SELF;
11224
424k
      break;
11225
257k
  case 'f':
11226
257k
      if (xmlStrEqual(name, BAD_CAST "following"))
11227
23.1k
    ret = AXIS_FOLLOWING;
11228
257k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11229
60.1k
    ret = AXIS_FOLLOWING_SIBLING;
11230
257k
      break;
11231
864k
  case 'n':
11232
864k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11233
231k
    ret = AXIS_NAMESPACE;
11234
864k
      break;
11235
1.01M
  case 'p':
11236
1.01M
      if (xmlStrEqual(name, BAD_CAST "parent"))
11237
5.62k
    ret = AXIS_PARENT;
11238
1.01M
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11239
623k
    ret = AXIS_PRECEDING;
11240
1.01M
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11241
40.9k
    ret = AXIS_PRECEDING_SIBLING;
11242
1.01M
      break;
11243
462k
  case 's':
11244
462k
      if (xmlStrEqual(name, BAD_CAST "self"))
11245
34.3k
    ret = AXIS_SELF;
11246
462k
      break;
11247
11.5M
    }
11248
11.5M
    return(ret);
11249
11.5M
}
11250
11251
/**
11252
 * xmlXPathCompStep:
11253
 * @ctxt:  the XPath Parser context
11254
 *
11255
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11256
 *                  | AbbreviatedStep
11257
 *
11258
 * [12] AbbreviatedStep ::=   '.' | '..'
11259
 *
11260
 * [5] AxisSpecifier ::= AxisName '::'
11261
 *                  | AbbreviatedAxisSpecifier
11262
 *
11263
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11264
 *
11265
 * Modified for XPtr range support as:
11266
 *
11267
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11268
 *                     | AbbreviatedStep
11269
 *                     | 'range-to' '(' Expr ')' Predicate*
11270
 *
11271
 * Compile one step in a Location Path
11272
 * A location step of . is short for self::node(). This is
11273
 * particularly useful in conjunction with //. For example, the
11274
 * location path .//para is short for
11275
 * self::node()/descendant-or-self::node()/child::para
11276
 * and so will select all para descendant elements of the context
11277
 * node.
11278
 * Similarly, a location step of .. is short for parent::node().
11279
 * For example, ../title is short for parent::node()/child::title
11280
 * and so will select the title children of the parent of the context
11281
 * node.
11282
 */
11283
static void
11284
20.2M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11285
#ifdef LIBXML_XPTR_LOCS_ENABLED
11286
    int rangeto = 0;
11287
    int op2 = -1;
11288
#endif
11289
11290
20.2M
    SKIP_BLANKS;
11291
20.2M
    if ((CUR == '.') && (NXT(1) == '.')) {
11292
57.3k
  SKIP(2);
11293
57.3k
  SKIP_BLANKS;
11294
57.3k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11295
57.3k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11296
20.1M
    } else if (CUR == '.') {
11297
2.55M
  NEXT;
11298
2.55M
  SKIP_BLANKS;
11299
17.6M
    } else {
11300
17.6M
  xmlChar *name = NULL;
11301
17.6M
  xmlChar *prefix = NULL;
11302
17.6M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11303
17.6M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11304
17.6M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11305
17.6M
  int op1;
11306
11307
  /*
11308
   * The modification needed for XPointer change to the production
11309
   */
11310
#ifdef LIBXML_XPTR_LOCS_ENABLED
11311
  if (ctxt->xptr) {
11312
      name = xmlXPathParseNCName(ctxt);
11313
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11314
                op2 = ctxt->comp->last;
11315
    xmlFree(name);
11316
    SKIP_BLANKS;
11317
    if (CUR != '(') {
11318
        XP_ERROR(XPATH_EXPR_ERROR);
11319
    }
11320
    NEXT;
11321
    SKIP_BLANKS;
11322
11323
    xmlXPathCompileExpr(ctxt, 1);
11324
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11325
    CHECK_ERROR;
11326
11327
    SKIP_BLANKS;
11328
    if (CUR != ')') {
11329
        XP_ERROR(XPATH_EXPR_ERROR);
11330
    }
11331
    NEXT;
11332
    rangeto = 1;
11333
    goto eval_predicates;
11334
      }
11335
  }
11336
#endif
11337
17.6M
  if (CUR == '*') {
11338
4.93M
      axis = AXIS_CHILD;
11339
12.6M
  } else {
11340
12.6M
      if (name == NULL)
11341
12.6M
    name = xmlXPathParseNCName(ctxt);
11342
12.6M
      if (name != NULL) {
11343
11.5M
    axis = xmlXPathIsAxisName(name);
11344
11.5M
    if (axis != 0) {
11345
1.33M
        SKIP_BLANKS;
11346
1.33M
        if ((CUR == ':') && (NXT(1) == ':')) {
11347
970k
      SKIP(2);
11348
970k
      xmlFree(name);
11349
970k
      name = NULL;
11350
970k
        } else {
11351
      /* an element name can conflict with an axis one :-\ */
11352
363k
      axis = AXIS_CHILD;
11353
363k
        }
11354
10.2M
    } else {
11355
10.2M
        axis = AXIS_CHILD;
11356
10.2M
    }
11357
11.5M
      } else if (CUR == '@') {
11358
738k
    NEXT;
11359
738k
    axis = AXIS_ATTRIBUTE;
11360
738k
      } else {
11361
354k
    axis = AXIS_CHILD;
11362
354k
      }
11363
12.6M
  }
11364
11365
17.6M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11366
251k
            xmlFree(name);
11367
251k
            return;
11368
251k
        }
11369
11370
17.3M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11371
17.3M
  if (test == 0)
11372
387k
      return;
11373
11374
16.9M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11375
16.9M
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11376
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11377
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11378
0
      }
11379
0
  }
11380
#ifdef DEBUG_STEP
11381
  xmlGenericError(xmlGenericErrorContext,
11382
    "Basis : computing new set\n");
11383
#endif
11384
11385
#ifdef DEBUG_STEP
11386
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11387
  if (ctxt->value == NULL)
11388
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11389
  else if (ctxt->value->nodesetval == NULL)
11390
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11391
  else
11392
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11393
#endif
11394
11395
#ifdef LIBXML_XPTR_LOCS_ENABLED
11396
eval_predicates:
11397
#endif
11398
16.9M
  op1 = ctxt->comp->last;
11399
16.9M
  ctxt->comp->last = -1;
11400
11401
16.9M
  SKIP_BLANKS;
11402
19.7M
  while (CUR == '[') {
11403
2.74M
      xmlXPathCompPredicate(ctxt, 0);
11404
2.74M
  }
11405
11406
#ifdef LIBXML_XPTR_LOCS_ENABLED
11407
  if (rangeto) {
11408
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11409
  } else
11410
#endif
11411
16.9M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11412
16.9M
                           test, type, (void *)prefix, (void *)name) == -1) {
11413
0
            xmlFree(prefix);
11414
0
            xmlFree(name);
11415
0
        }
11416
16.9M
    }
11417
#ifdef DEBUG_STEP
11418
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11419
    if (ctxt->value == NULL)
11420
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11421
    else if (ctxt->value->nodesetval == NULL)
11422
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11423
    else
11424
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11425
    ctxt->value->nodesetval);
11426
#endif
11427
20.2M
}
11428
11429
/**
11430
 * xmlXPathCompRelativeLocationPath:
11431
 * @ctxt:  the XPath Parser context
11432
 *
11433
 *  [3]   RelativeLocationPath ::=   Step
11434
 *                     | RelativeLocationPath '/' Step
11435
 *                     | AbbreviatedRelativeLocationPath
11436
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11437
 *
11438
 * Compile a relative location path.
11439
 */
11440
static void
11441
xmlXPathCompRelativeLocationPath
11442
17.3M
(xmlXPathParserContextPtr ctxt) {
11443
17.3M
    SKIP_BLANKS;
11444
17.3M
    if ((CUR == '/') && (NXT(1) == '/')) {
11445
48.4k
  SKIP(2);
11446
48.4k
  SKIP_BLANKS;
11447
48.4k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11448
48.4k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11449
17.2M
    } else if (CUR == '/') {
11450
1.95M
      NEXT;
11451
1.95M
  SKIP_BLANKS;
11452
1.95M
    }
11453
17.3M
    xmlXPathCompStep(ctxt);
11454
17.3M
    CHECK_ERROR;
11455
16.3M
    SKIP_BLANKS;
11456
19.2M
    while (CUR == '/') {
11457
2.89M
  if ((CUR == '/') && (NXT(1) == '/')) {
11458
609k
      SKIP(2);
11459
609k
      SKIP_BLANKS;
11460
609k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11461
609k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11462
609k
      xmlXPathCompStep(ctxt);
11463
2.28M
  } else if (CUR == '/') {
11464
2.28M
      NEXT;
11465
2.28M
      SKIP_BLANKS;
11466
2.28M
      xmlXPathCompStep(ctxt);
11467
2.28M
  }
11468
2.89M
  SKIP_BLANKS;
11469
2.89M
    }
11470
16.3M
}
11471
11472
/**
11473
 * xmlXPathCompLocationPath:
11474
 * @ctxt:  the XPath Parser context
11475
 *
11476
 *  [1]   LocationPath ::=   RelativeLocationPath
11477
 *                     | AbsoluteLocationPath
11478
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11479
 *                     | AbbreviatedAbsoluteLocationPath
11480
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11481
 *                           '//' RelativeLocationPath
11482
 *
11483
 * Compile a location path
11484
 *
11485
 * // is short for /descendant-or-self::node()/. For example,
11486
 * //para is short for /descendant-or-self::node()/child::para and
11487
 * so will select any para element in the document (even a para element
11488
 * that is a document element will be selected by //para since the
11489
 * document element node is a child of the root node); div//para is
11490
 * short for div/descendant-or-self::node()/child::para and so will
11491
 * select all para descendants of div children.
11492
 */
11493
static void
11494
16.7M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11495
16.7M
    SKIP_BLANKS;
11496
16.7M
    if (CUR != '/') {
11497
12.6M
        xmlXPathCompRelativeLocationPath(ctxt);
11498
12.6M
    } else {
11499
7.91M
  while (CUR == '/') {
11500
4.12M
      if ((CUR == '/') && (NXT(1) == '/')) {
11501
1.88M
    SKIP(2);
11502
1.88M
    SKIP_BLANKS;
11503
1.88M
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11504
1.88M
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11505
1.88M
    xmlXPathCompRelativeLocationPath(ctxt);
11506
2.23M
      } else if (CUR == '/') {
11507
2.23M
    NEXT;
11508
2.23M
    SKIP_BLANKS;
11509
2.23M
    if ((CUR != 0 ) &&
11510
2.23M
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11511
1.25M
         (CUR == '@') || (CUR == '*')))
11512
709k
        xmlXPathCompRelativeLocationPath(ctxt);
11513
2.23M
      }
11514
4.12M
      CHECK_ERROR;
11515
4.12M
  }
11516
4.09M
    }
11517
16.7M
}
11518
11519
/************************************************************************
11520
 *                  *
11521
 *    XPath precompiled expression evaluation     *
11522
 *                  *
11523
 ************************************************************************/
11524
11525
static int
11526
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11527
11528
#ifdef DEBUG_STEP
11529
static void
11530
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11531
        int nbNodes)
11532
{
11533
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11534
    switch (op->value) {
11535
        case AXIS_ANCESTOR:
11536
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11537
            break;
11538
        case AXIS_ANCESTOR_OR_SELF:
11539
            xmlGenericError(xmlGenericErrorContext,
11540
                            "axis 'ancestors-or-self' ");
11541
            break;
11542
        case AXIS_ATTRIBUTE:
11543
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11544
            break;
11545
        case AXIS_CHILD:
11546
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11547
            break;
11548
        case AXIS_DESCENDANT:
11549
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11550
            break;
11551
        case AXIS_DESCENDANT_OR_SELF:
11552
            xmlGenericError(xmlGenericErrorContext,
11553
                            "axis 'descendant-or-self' ");
11554
            break;
11555
        case AXIS_FOLLOWING:
11556
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11557
            break;
11558
        case AXIS_FOLLOWING_SIBLING:
11559
            xmlGenericError(xmlGenericErrorContext,
11560
                            "axis 'following-siblings' ");
11561
            break;
11562
        case AXIS_NAMESPACE:
11563
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11564
            break;
11565
        case AXIS_PARENT:
11566
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11567
            break;
11568
        case AXIS_PRECEDING:
11569
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11570
            break;
11571
        case AXIS_PRECEDING_SIBLING:
11572
            xmlGenericError(xmlGenericErrorContext,
11573
                            "axis 'preceding-sibling' ");
11574
            break;
11575
        case AXIS_SELF:
11576
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11577
            break;
11578
    }
11579
    xmlGenericError(xmlGenericErrorContext,
11580
  " context contains %d nodes\n", nbNodes);
11581
    switch (op->value2) {
11582
        case NODE_TEST_NONE:
11583
            xmlGenericError(xmlGenericErrorContext,
11584
                            "           searching for none !!!\n");
11585
            break;
11586
        case NODE_TEST_TYPE:
11587
            xmlGenericError(xmlGenericErrorContext,
11588
                            "           searching for type %d\n", op->value3);
11589
            break;
11590
        case NODE_TEST_PI:
11591
            xmlGenericError(xmlGenericErrorContext,
11592
                            "           searching for PI !!!\n");
11593
            break;
11594
        case NODE_TEST_ALL:
11595
            xmlGenericError(xmlGenericErrorContext,
11596
                            "           searching for *\n");
11597
            break;
11598
        case NODE_TEST_NS:
11599
            xmlGenericError(xmlGenericErrorContext,
11600
                            "           searching for namespace %s\n",
11601
                            op->value5);
11602
            break;
11603
        case NODE_TEST_NAME:
11604
            xmlGenericError(xmlGenericErrorContext,
11605
                            "           searching for name %s\n", op->value5);
11606
            if (op->value4)
11607
                xmlGenericError(xmlGenericErrorContext,
11608
                                "           with namespace %s\n", op->value4);
11609
            break;
11610
    }
11611
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11612
}
11613
#endif /* DEBUG_STEP */
11614
11615
/**
11616
 * xmlXPathNodeSetFilter:
11617
 * @ctxt:  the XPath Parser context
11618
 * @set: the node set to filter
11619
 * @filterOpIndex: the index of the predicate/filter op
11620
 * @minPos: minimum position in the filtered set (1-based)
11621
 * @maxPos: maximum position in the filtered set (1-based)
11622
 * @hasNsNodes: true if the node set may contain namespace nodes
11623
 *
11624
 * Filter a node set, keeping only nodes for which the predicate expression
11625
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11626
 * filtered result.
11627
 */
11628
static void
11629
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11630
          xmlNodeSetPtr set,
11631
          int filterOpIndex,
11632
                      int minPos, int maxPos,
11633
          int hasNsNodes)
11634
15.9M
{
11635
15.9M
    xmlXPathContextPtr xpctxt;
11636
15.9M
    xmlNodePtr oldnode;
11637
15.9M
    xmlDocPtr olddoc;
11638
15.9M
    xmlXPathStepOpPtr filterOp;
11639
15.9M
    int oldcs, oldpp;
11640
15.9M
    int i, j, pos;
11641
11642
15.9M
    if ((set == NULL) || (set->nodeNr == 0))
11643
1.04M
        return;
11644
11645
    /*
11646
    * Check if the node set contains a sufficient number of nodes for
11647
    * the requested range.
11648
    */
11649
14.9M
    if (set->nodeNr < minPos) {
11650
35.3k
        xmlXPathNodeSetClear(set, hasNsNodes);
11651
35.3k
        return;
11652
35.3k
    }
11653
11654
14.9M
    xpctxt = ctxt->context;
11655
14.9M
    oldnode = xpctxt->node;
11656
14.9M
    olddoc = xpctxt->doc;
11657
14.9M
    oldcs = xpctxt->contextSize;
11658
14.9M
    oldpp = xpctxt->proximityPosition;
11659
14.9M
    filterOp = &ctxt->comp->steps[filterOpIndex];
11660
11661
14.9M
    xpctxt->contextSize = set->nodeNr;
11662
11663
57.1M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11664
46.5M
        xmlNodePtr node = set->nodeTab[i];
11665
46.5M
        int res;
11666
11667
46.5M
        xpctxt->node = node;
11668
46.5M
        xpctxt->proximityPosition = i + 1;
11669
11670
        /*
11671
        * Also set the xpath document in case things like
11672
        * key() are evaluated in the predicate.
11673
        *
11674
        * TODO: Get real doc for namespace nodes.
11675
        */
11676
46.5M
        if ((node->type != XML_NAMESPACE_DECL) &&
11677
46.5M
            (node->doc != NULL))
11678
44.2M
            xpctxt->doc = node->doc;
11679
11680
46.5M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11681
11682
46.5M
        if (ctxt->error != XPATH_EXPRESSION_OK)
11683
240k
            break;
11684
46.3M
        if (res < 0) {
11685
            /* Shouldn't happen */
11686
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11687
0
            break;
11688
0
        }
11689
11690
46.3M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11691
11.5M
            if (i != j) {
11692
1.27M
                set->nodeTab[j] = node;
11693
1.27M
                set->nodeTab[i] = NULL;
11694
1.27M
            }
11695
11696
11.5M
            j += 1;
11697
34.7M
        } else {
11698
            /* Remove the entry from the initial node set. */
11699
34.7M
            set->nodeTab[i] = NULL;
11700
34.7M
            if (node->type == XML_NAMESPACE_DECL)
11701
1.52M
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11702
34.7M
        }
11703
11704
46.3M
        if (res != 0) {
11705
11.5M
            if (pos == maxPos) {
11706
4.02M
                i += 1;
11707
4.02M
                break;
11708
4.02M
            }
11709
11710
7.50M
            pos += 1;
11711
7.50M
        }
11712
46.3M
    }
11713
11714
    /* Free remaining nodes. */
11715
14.9M
    if (hasNsNodes) {
11716
3.47M
        for (; i < set->nodeNr; i++) {
11717
411k
            xmlNodePtr node = set->nodeTab[i];
11718
411k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11719
63.5k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11720
411k
        }
11721
3.06M
    }
11722
11723
14.9M
    set->nodeNr = j;
11724
11725
    /* If too many elements were removed, shrink table to preserve memory. */
11726
14.9M
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11727
14.9M
        (set->nodeNr < set->nodeMax / 2)) {
11728
576k
        xmlNodePtr *tmp;
11729
576k
        int nodeMax = set->nodeNr;
11730
11731
576k
        if (nodeMax < XML_NODESET_DEFAULT)
11732
570k
            nodeMax = XML_NODESET_DEFAULT;
11733
576k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11734
576k
                nodeMax * sizeof(xmlNodePtr));
11735
576k
        if (tmp == NULL) {
11736
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11737
576k
        } else {
11738
576k
            set->nodeTab = tmp;
11739
576k
            set->nodeMax = nodeMax;
11740
576k
        }
11741
576k
    }
11742
11743
14.9M
    xpctxt->node = oldnode;
11744
14.9M
    xpctxt->doc = olddoc;
11745
14.9M
    xpctxt->contextSize = oldcs;
11746
14.9M
    xpctxt->proximityPosition = oldpp;
11747
14.9M
}
11748
11749
#ifdef LIBXML_XPTR_LOCS_ENABLED
11750
/**
11751
 * xmlXPathLocationSetFilter:
11752
 * @ctxt:  the XPath Parser context
11753
 * @locset: the location set to filter
11754
 * @filterOpIndex: the index of the predicate/filter op
11755
 * @minPos: minimum position in the filtered set (1-based)
11756
 * @maxPos: maximum position in the filtered set (1-based)
11757
 *
11758
 * Filter a location set, keeping only nodes for which the predicate
11759
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11760
 * in the filtered result.
11761
 */
11762
static void
11763
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11764
              xmlLocationSetPtr locset,
11765
              int filterOpIndex,
11766
                          int minPos, int maxPos)
11767
{
11768
    xmlXPathContextPtr xpctxt;
11769
    xmlNodePtr oldnode;
11770
    xmlDocPtr olddoc;
11771
    xmlXPathStepOpPtr filterOp;
11772
    int oldcs, oldpp;
11773
    int i, j, pos;
11774
11775
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11776
        return;
11777
11778
    xpctxt = ctxt->context;
11779
    oldnode = xpctxt->node;
11780
    olddoc = xpctxt->doc;
11781
    oldcs = xpctxt->contextSize;
11782
    oldpp = xpctxt->proximityPosition;
11783
    filterOp = &ctxt->comp->steps[filterOpIndex];
11784
11785
    xpctxt->contextSize = locset->locNr;
11786
11787
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11788
        xmlNodePtr contextNode = locset->locTab[i]->user;
11789
        int res;
11790
11791
        xpctxt->node = contextNode;
11792
        xpctxt->proximityPosition = i + 1;
11793
11794
        /*
11795
        * Also set the xpath document in case things like
11796
        * key() are evaluated in the predicate.
11797
        *
11798
        * TODO: Get real doc for namespace nodes.
11799
        */
11800
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11801
            (contextNode->doc != NULL))
11802
            xpctxt->doc = contextNode->doc;
11803
11804
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11805
11806
        if (ctxt->error != XPATH_EXPRESSION_OK)
11807
            break;
11808
        if (res < 0) {
11809
            /* Shouldn't happen */
11810
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11811
            break;
11812
        }
11813
11814
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11815
            if (i != j) {
11816
                locset->locTab[j] = locset->locTab[i];
11817
                locset->locTab[i] = NULL;
11818
            }
11819
11820
            j += 1;
11821
        } else {
11822
            /* Remove the entry from the initial location set. */
11823
            xmlXPathFreeObject(locset->locTab[i]);
11824
            locset->locTab[i] = NULL;
11825
        }
11826
11827
        if (res != 0) {
11828
            if (pos == maxPos) {
11829
                i += 1;
11830
                break;
11831
            }
11832
11833
            pos += 1;
11834
        }
11835
    }
11836
11837
    /* Free remaining nodes. */
11838
    for (; i < locset->locNr; i++)
11839
        xmlXPathFreeObject(locset->locTab[i]);
11840
11841
    locset->locNr = j;
11842
11843
    /* If too many elements were removed, shrink table to preserve memory. */
11844
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11845
        (locset->locNr < locset->locMax / 2)) {
11846
        xmlXPathObjectPtr *tmp;
11847
        int locMax = locset->locNr;
11848
11849
        if (locMax < XML_NODESET_DEFAULT)
11850
            locMax = XML_NODESET_DEFAULT;
11851
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11852
                locMax * sizeof(xmlXPathObjectPtr));
11853
        if (tmp == NULL) {
11854
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11855
        } else {
11856
            locset->locTab = tmp;
11857
            locset->locMax = locMax;
11858
        }
11859
    }
11860
11861
    xpctxt->node = oldnode;
11862
    xpctxt->doc = olddoc;
11863
    xpctxt->contextSize = oldcs;
11864
    xpctxt->proximityPosition = oldpp;
11865
}
11866
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11867
11868
/**
11869
 * xmlXPathCompOpEvalPredicate:
11870
 * @ctxt:  the XPath Parser context
11871
 * @op: the predicate op
11872
 * @set: the node set to filter
11873
 * @minPos: minimum position in the filtered set (1-based)
11874
 * @maxPos: maximum position in the filtered set (1-based)
11875
 * @hasNsNodes: true if the node set may contain namespace nodes
11876
 *
11877
 * Filter a node set, keeping only nodes for which the sequence of predicate
11878
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11879
 * in the filtered result.
11880
 */
11881
static void
11882
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11883
          xmlXPathStepOpPtr op,
11884
          xmlNodeSetPtr set,
11885
                            int minPos, int maxPos,
11886
          int hasNsNodes)
11887
13.9M
{
11888
13.9M
    if (op->ch1 != -1) {
11889
391k
  xmlXPathCompExprPtr comp = ctxt->comp;
11890
  /*
11891
  * Process inner predicates first.
11892
  */
11893
391k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11894
0
            xmlGenericError(xmlGenericErrorContext,
11895
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11896
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11897
0
  }
11898
391k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11899
391k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11900
391k
        ctxt->context->depth += 1;
11901
391k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11902
391k
                                    1, set->nodeNr, hasNsNodes);
11903
391k
        ctxt->context->depth -= 1;
11904
391k
  CHECK_ERROR;
11905
391k
    }
11906
11907
13.8M
    if (op->ch2 != -1)
11908
13.8M
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11909
13.8M
}
11910
11911
static int
11912
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11913
          xmlXPathStepOpPtr op,
11914
          int *maxPos)
11915
5.53M
{
11916
11917
5.53M
    xmlXPathStepOpPtr exprOp;
11918
11919
    /*
11920
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11921
    */
11922
11923
    /*
11924
    * If not -1, then ch1 will point to:
11925
    * 1) For predicates (XPATH_OP_PREDICATE):
11926
    *    - an inner predicate operator
11927
    * 2) For filters (XPATH_OP_FILTER):
11928
    *    - an inner filter operator OR
11929
    *    - an expression selecting the node set.
11930
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11931
    */
11932
5.53M
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11933
0
  return(0);
11934
11935
5.53M
    if (op->ch2 != -1) {
11936
5.53M
  exprOp = &ctxt->comp->steps[op->ch2];
11937
5.53M
    } else
11938
0
  return(0);
11939
11940
5.53M
    if ((exprOp != NULL) &&
11941
5.53M
  (exprOp->op == XPATH_OP_VALUE) &&
11942
5.53M
  (exprOp->value4 != NULL) &&
11943
5.53M
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11944
2.05M
    {
11945
2.05M
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11946
11947
  /*
11948
  * We have a "[n]" predicate here.
11949
  * TODO: Unfortunately this simplistic test here is not
11950
  * able to detect a position() predicate in compound
11951
  * expressions like "[@attr = 'a" and position() = 1],
11952
  * and even not the usage of position() in
11953
  * "[position() = 1]"; thus - obviously - a position-range,
11954
  * like it "[position() < 5]", is also not detected.
11955
  * Maybe we could rewrite the AST to ease the optimization.
11956
  */
11957
11958
2.05M
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11959
2.04M
      *maxPos = (int) floatval;
11960
2.04M
            if (floatval == (double) *maxPos)
11961
2.02M
                return(1);
11962
2.04M
        }
11963
2.05M
    }
11964
3.50M
    return(0);
11965
5.53M
}
11966
11967
static int
11968
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11969
                           xmlXPathStepOpPtr op,
11970
         xmlNodePtr * first, xmlNodePtr * last,
11971
         int toBool)
11972
91.8M
{
11973
11974
91.8M
#define XP_TEST_HIT \
11975
203M
    if (hasAxisRange != 0) { \
11976
2.29M
  if (++pos == maxPos) { \
11977
994k
      if (addNode(seq, cur) < 0) \
11978
994k
          ctxt->error = XPATH_MEMORY_ERROR; \
11979
994k
      goto axis_range_end; } \
11980
200M
    } else { \
11981
200M
  if (addNode(seq, cur) < 0) \
11982
200M
      ctxt->error = XPATH_MEMORY_ERROR; \
11983
200M
  if (breakOnFirstHit) goto first_hit; }
11984
11985
91.8M
#define XP_TEST_HIT_NS \
11986
91.8M
    if (hasAxisRange != 0) { \
11987
222k
  if (++pos == maxPos) { \
11988
143k
      hasNsNodes = 1; \
11989
143k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11990
143k
          ctxt->error = XPATH_MEMORY_ERROR; \
11991
143k
  goto axis_range_end; } \
11992
5.44M
    } else { \
11993
5.44M
  hasNsNodes = 1; \
11994
5.44M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11995
5.44M
      ctxt->error = XPATH_MEMORY_ERROR; \
11996
5.44M
  if (breakOnFirstHit) goto first_hit; }
11997
11998
91.8M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999
91.8M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000
91.8M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001
91.8M
    const xmlChar *prefix = op->value4;
12002
91.8M
    const xmlChar *name = op->value5;
12003
91.8M
    const xmlChar *URI = NULL;
12004
12005
#ifdef DEBUG_STEP
12006
    int nbMatches = 0, prevMatches = 0;
12007
#endif
12008
91.8M
    int total = 0, hasNsNodes = 0;
12009
    /* The popped object holding the context nodes */
12010
91.8M
    xmlXPathObjectPtr obj;
12011
    /* The set of context nodes for the node tests */
12012
91.8M
    xmlNodeSetPtr contextSeq;
12013
91.8M
    int contextIdx;
12014
91.8M
    xmlNodePtr contextNode;
12015
    /* The final resulting node set wrt to all context nodes */
12016
91.8M
    xmlNodeSetPtr outSeq;
12017
    /*
12018
    * The temporary resulting node set wrt 1 context node.
12019
    * Used to feed predicate evaluation.
12020
    */
12021
91.8M
    xmlNodeSetPtr seq;
12022
91.8M
    xmlNodePtr cur;
12023
    /* First predicate operator */
12024
91.8M
    xmlXPathStepOpPtr predOp;
12025
91.8M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12026
91.8M
    int hasPredicateRange, hasAxisRange, pos;
12027
91.8M
    int breakOnFirstHit;
12028
12029
91.8M
    xmlXPathTraversalFunction next = NULL;
12030
91.8M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12031
91.8M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12032
91.8M
    xmlNodePtr oldContextNode;
12033
91.8M
    xmlXPathContextPtr xpctxt = ctxt->context;
12034
12035
12036
91.8M
    CHECK_TYPE0(XPATH_NODESET);
12037
90.8M
    obj = valuePop(ctxt);
12038
    /*
12039
    * Setup namespaces.
12040
    */
12041
90.8M
    if (prefix != NULL) {
12042
1.77M
        URI = xmlXPathNsLookup(xpctxt, prefix);
12043
1.77M
        if (URI == NULL) {
12044
297k
      xmlXPathReleaseObject(xpctxt, obj);
12045
297k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12046
0
  }
12047
1.77M
    }
12048
    /*
12049
    * Setup axis.
12050
    *
12051
    * MAYBE FUTURE TODO: merging optimizations:
12052
    * - If the nodes to be traversed wrt to the initial nodes and
12053
    *   the current axis cannot overlap, then we could avoid searching
12054
    *   for duplicates during the merge.
12055
    *   But the question is how/when to evaluate if they cannot overlap.
12056
    *   Example: if we know that for two initial nodes, the one is
12057
    *   not in the ancestor-or-self axis of the other, then we could safely
12058
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12059
    *   the descendant-or-self axis.
12060
    */
12061
90.5M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12062
90.5M
    switch (axis) {
12063
427k
        case AXIS_ANCESTOR:
12064
427k
            first = NULL;
12065
427k
            next = xmlXPathNextAncestor;
12066
427k
            break;
12067
227k
        case AXIS_ANCESTOR_OR_SELF:
12068
227k
            first = NULL;
12069
227k
            next = xmlXPathNextAncestorOrSelf;
12070
227k
            break;
12071
1.44M
        case AXIS_ATTRIBUTE:
12072
1.44M
            first = NULL;
12073
1.44M
      last = NULL;
12074
1.44M
            next = xmlXPathNextAttribute;
12075
1.44M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12076
1.44M
            break;
12077
80.9M
        case AXIS_CHILD:
12078
80.9M
      last = NULL;
12079
80.9M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12080
80.9M
    (type == NODE_TYPE_NODE))
12081
74.2M
      {
12082
    /*
12083
    * Optimization if an element node type is 'element'.
12084
    */
12085
74.2M
    next = xmlXPathNextChildElement;
12086
74.2M
      } else
12087
6.69M
    next = xmlXPathNextChild;
12088
80.9M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12089
80.9M
            break;
12090
2.48M
        case AXIS_DESCENDANT:
12091
2.48M
      last = NULL;
12092
2.48M
            next = xmlXPathNextDescendant;
12093
2.48M
            break;
12094
2.91M
        case AXIS_DESCENDANT_OR_SELF:
12095
2.91M
      last = NULL;
12096
2.91M
            next = xmlXPathNextDescendantOrSelf;
12097
2.91M
            break;
12098
119k
        case AXIS_FOLLOWING:
12099
119k
      last = NULL;
12100
119k
            next = xmlXPathNextFollowing;
12101
119k
            break;
12102
219k
        case AXIS_FOLLOWING_SIBLING:
12103
219k
      last = NULL;
12104
219k
            next = xmlXPathNextFollowingSibling;
12105
219k
            break;
12106
1.03M
        case AXIS_NAMESPACE:
12107
1.03M
            first = NULL;
12108
1.03M
      last = NULL;
12109
1.03M
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12110
1.03M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12111
1.03M
            break;
12112
388k
        case AXIS_PARENT:
12113
388k
            first = NULL;
12114
388k
            next = xmlXPathNextParent;
12115
388k
            break;
12116
161k
        case AXIS_PRECEDING:
12117
161k
            first = NULL;
12118
161k
            next = xmlXPathNextPrecedingInternal;
12119
161k
            break;
12120
132k
        case AXIS_PRECEDING_SIBLING:
12121
132k
            first = NULL;
12122
132k
            next = xmlXPathNextPrecedingSibling;
12123
132k
            break;
12124
123k
        case AXIS_SELF:
12125
123k
            first = NULL;
12126
123k
      last = NULL;
12127
123k
            next = xmlXPathNextSelf;
12128
123k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12129
123k
            break;
12130
90.5M
    }
12131
12132
#ifdef DEBUG_STEP
12133
    xmlXPathDebugDumpStepAxis(op,
12134
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12135
#endif
12136
12137
90.5M
    if (next == NULL) {
12138
0
  xmlXPathReleaseObject(xpctxt, obj);
12139
0
        return(0);
12140
0
    }
12141
90.5M
    contextSeq = obj->nodesetval;
12142
90.5M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12143
11.9M
  xmlXPathReleaseObject(xpctxt, obj);
12144
11.9M
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12145
11.9M
        return(0);
12146
11.9M
    }
12147
    /*
12148
    * Predicate optimization ---------------------------------------------
12149
    * If this step has a last predicate, which contains a position(),
12150
    * then we'll optimize (although not exactly "position()", but only
12151
    * the  short-hand form, i.e., "[n]".
12152
    *
12153
    * Example - expression "/foo[parent::bar][1]":
12154
    *
12155
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12156
    *   ROOT                               -- op->ch1
12157
    *   PREDICATE                          -- op->ch2 (predOp)
12158
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12159
    *       SORT
12160
    *         COLLECT  'parent' 'name' 'node' bar
12161
    *           NODE
12162
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12163
    *
12164
    */
12165
78.6M
    maxPos = 0;
12166
78.6M
    predOp = NULL;
12167
78.6M
    hasPredicateRange = 0;
12168
78.6M
    hasAxisRange = 0;
12169
78.6M
    if (op->ch2 != -1) {
12170
  /*
12171
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12172
  */
12173
5.53M
  predOp = &ctxt->comp->steps[op->ch2];
12174
5.53M
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12175
2.02M
      if (predOp->ch1 != -1) {
12176
    /*
12177
    * Use the next inner predicate operator.
12178
    */
12179
380k
    predOp = &ctxt->comp->steps[predOp->ch1];
12180
380k
    hasPredicateRange = 1;
12181
1.64M
      } else {
12182
    /*
12183
    * There's no other predicate than the [n] predicate.
12184
    */
12185
1.64M
    predOp = NULL;
12186
1.64M
    hasAxisRange = 1;
12187
1.64M
      }
12188
2.02M
  }
12189
5.53M
    }
12190
78.6M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12191
    /*
12192
    * Axis traversal -----------------------------------------------------
12193
    */
12194
    /*
12195
     * 2.3 Node Tests
12196
     *  - For the attribute axis, the principal node type is attribute.
12197
     *  - For the namespace axis, the principal node type is namespace.
12198
     *  - For other axes, the principal node type is element.
12199
     *
12200
     * A node test * is true for any node of the
12201
     * principal node type. For example, child::* will
12202
     * select all element children of the context node
12203
     */
12204
78.6M
    oldContextNode = xpctxt->node;
12205
78.6M
    addNode = xmlXPathNodeSetAddUnique;
12206
78.6M
    outSeq = NULL;
12207
78.6M
    seq = NULL;
12208
78.6M
    contextNode = NULL;
12209
78.6M
    contextIdx = 0;
12210
12211
12212
233M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12213
233M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12214
156M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12215
12216
156M
  if (seq == NULL) {
12217
79.6M
      seq = xmlXPathNodeSetCreate(NULL);
12218
79.6M
      if (seq == NULL) {
12219
                /* TODO: Propagate memory error. */
12220
0
    total = 0;
12221
0
    goto error;
12222
0
      }
12223
79.6M
  }
12224
  /*
12225
  * Traverse the axis and test the nodes.
12226
  */
12227
156M
  pos = 0;
12228
156M
  cur = NULL;
12229
156M
  hasNsNodes = 0;
12230
501M
        do {
12231
501M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12232
574
                goto error;
12233
12234
501M
            cur = next(ctxt, cur);
12235
501M
            if (cur == NULL)
12236
154M
                break;
12237
12238
      /*
12239
      * QUESTION TODO: What does the "first" and "last" stuff do?
12240
      */
12241
347M
            if ((first != NULL) && (*first != NULL)) {
12242
1.30M
    if (*first == cur)
12243
54.6k
        break;
12244
1.25M
    if (((total % 256) == 0) &&
12245
1.25M
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12246
1.25M
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12247
#else
12248
        (xmlXPathCmpNodes(*first, cur) >= 0))
12249
#endif
12250
78.9k
    {
12251
78.9k
        break;
12252
78.9k
    }
12253
1.25M
      }
12254
347M
      if ((last != NULL) && (*last != NULL)) {
12255
878k
    if (*last == cur)
12256
17.7k
        break;
12257
860k
    if (((total % 256) == 0) &&
12258
860k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12259
860k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12260
#else
12261
        (xmlXPathCmpNodes(cur, *last) >= 0))
12262
#endif
12263
126k
    {
12264
126k
        break;
12265
126k
    }
12266
860k
      }
12267
12268
347M
            total++;
12269
12270
#ifdef DEBUG_STEP
12271
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12272
#endif
12273
12274
347M
      switch (test) {
12275
0
                case NODE_TEST_NONE:
12276
0
        total = 0;
12277
0
                    STRANGE
12278
0
        goto error;
12279
175M
                case NODE_TEST_TYPE:
12280
175M
        if (type == NODE_TYPE_NODE) {
12281
144M
      switch (cur->type) {
12282
7.43M
          case XML_DOCUMENT_NODE:
12283
7.43M
          case XML_HTML_DOCUMENT_NODE:
12284
61.4M
          case XML_ELEMENT_NODE:
12285
61.5M
          case XML_ATTRIBUTE_NODE:
12286
66.3M
          case XML_PI_NODE:
12287
71.0M
          case XML_COMMENT_NODE:
12288
73.2M
          case XML_CDATA_SECTION_NODE:
12289
143M
          case XML_TEXT_NODE:
12290
143M
        XP_TEST_HIT
12291
143M
        break;
12292
143M
          case XML_NAMESPACE_DECL: {
12293
667k
        if (axis == AXIS_NAMESPACE) {
12294
449k
            XP_TEST_HIT_NS
12295
449k
        } else {
12296
218k
                              hasNsNodes = 1;
12297
218k
            XP_TEST_HIT
12298
218k
        }
12299
625k
        break;
12300
667k
                            }
12301
625k
          default:
12302
0
        break;
12303
144M
      }
12304
144M
        } else if (cur->type == (xmlElementType) type) {
12305
16.5M
      if (cur->type == XML_NAMESPACE_DECL)
12306
0
          XP_TEST_HIT_NS
12307
16.5M
      else
12308
16.5M
          XP_TEST_HIT
12309
16.5M
        } else if ((type == NODE_TYPE_TEXT) &&
12310
14.5M
       (cur->type == XML_CDATA_SECTION_NODE))
12311
523k
        {
12312
523k
      XP_TEST_HIT
12313
523k
        }
12314
175M
        break;
12315
175M
                case NODE_TEST_PI:
12316
78.3k
                    if ((cur->type == XML_PI_NODE) &&
12317
78.3k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12318
142
        {
12319
142
      XP_TEST_HIT
12320
142
                    }
12321
78.3k
                    break;
12322
81.5M
                case NODE_TEST_ALL:
12323
81.5M
                    if (axis == AXIS_ATTRIBUTE) {
12324
1.48M
                        if (cur->type == XML_ATTRIBUTE_NODE)
12325
1.48M
      {
12326
1.48M
                            if (prefix == NULL)
12327
1.46M
          {
12328
1.46M
        XP_TEST_HIT
12329
1.46M
                            } else if ((cur->ns != NULL) &&
12330
11.9k
        (xmlStrEqual(URI, cur->ns->href)))
12331
0
          {
12332
0
        XP_TEST_HIT
12333
0
                            }
12334
1.48M
                        }
12335
80.0M
                    } else if (axis == AXIS_NAMESPACE) {
12336
4.43M
                        if (cur->type == XML_NAMESPACE_DECL)
12337
4.43M
      {
12338
4.43M
          XP_TEST_HIT_NS
12339
4.43M
                        }
12340
75.6M
                    } else {
12341
75.6M
                        if (cur->type == XML_ELEMENT_NODE) {
12342
40.7M
                            if (prefix == NULL)
12343
37.6M
          {
12344
37.6M
        XP_TEST_HIT
12345
12346
37.6M
                            } else if ((cur->ns != NULL) &&
12347
3.08M
        (xmlStrEqual(URI, cur->ns->href)))
12348
658k
          {
12349
658k
        XP_TEST_HIT
12350
658k
                            }
12351
40.7M
                        }
12352
75.6M
                    }
12353
80.6M
                    break;
12354
80.6M
                case NODE_TEST_NS:{
12355
0
                        TODO;
12356
0
                        break;
12357
81.5M
                    }
12358
90.1M
                case NODE_TEST_NAME:
12359
90.1M
                    if (axis == AXIS_ATTRIBUTE) {
12360
1.95M
                        if (cur->type != XML_ATTRIBUTE_NODE)
12361
0
          break;
12362
88.2M
        } else if (axis == AXIS_NAMESPACE) {
12363
3.56M
                        if (cur->type != XML_NAMESPACE_DECL)
12364
0
          break;
12365
84.6M
        } else {
12366
84.6M
            if (cur->type != XML_ELEMENT_NODE)
12367
30.2M
          break;
12368
84.6M
        }
12369
59.9M
                    switch (cur->type) {
12370
54.4M
                        case XML_ELEMENT_NODE:
12371
54.4M
                            if (xmlStrEqual(name, cur->name)) {
12372
3.08M
                                if (prefix == NULL) {
12373
2.97M
                                    if (cur->ns == NULL)
12374
1.85M
            {
12375
1.85M
          XP_TEST_HIT
12376
1.85M
                                    }
12377
2.97M
                                } else {
12378
117k
                                    if ((cur->ns != NULL) &&
12379
117k
                                        (xmlStrEqual(URI, cur->ns->href)))
12380
59.6k
            {
12381
59.6k
          XP_TEST_HIT
12382
59.6k
                                    }
12383
117k
                                }
12384
3.08M
                            }
12385
54.3M
                            break;
12386
54.3M
                        case XML_ATTRIBUTE_NODE:{
12387
1.95M
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389
1.95M
                                if (xmlStrEqual(name, attr->name)) {
12390
298k
                                    if (prefix == NULL) {
12391
290k
                                        if ((attr->ns == NULL) ||
12392
290k
                                            (attr->ns->prefix == NULL))
12393
290k
          {
12394
290k
              XP_TEST_HIT
12395
290k
                                        }
12396
290k
                                    } else {
12397
7.75k
                                        if ((attr->ns != NULL) &&
12398
7.75k
                                            (xmlStrEqual(URI,
12399
0
                attr->ns->href)))
12400
0
          {
12401
0
              XP_TEST_HIT
12402
0
                                        }
12403
7.75k
                                    }
12404
298k
                                }
12405
1.89M
                                break;
12406
1.95M
                            }
12407
3.56M
                        case XML_NAMESPACE_DECL:
12408
3.56M
                            if (cur->type == XML_NAMESPACE_DECL) {
12409
3.56M
                                xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411
3.56M
                                if ((ns->prefix != NULL) && (name != NULL)
12412
3.56M
                                    && (xmlStrEqual(ns->prefix, name)))
12413
783k
        {
12414
783k
            XP_TEST_HIT_NS
12415
783k
                                }
12416
3.56M
                            }
12417
3.51M
                            break;
12418
3.51M
                        default:
12419
0
                            break;
12420
59.9M
                    }
12421
59.7M
                    break;
12422
347M
      } /* switch(test) */
12423
347M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12424
12425
154M
  goto apply_predicates;
12426
12427
154M
axis_range_end: /* ----------------------------------------------------- */
12428
  /*
12429
  * We have a "/foo[n]", and position() = n was reached.
12430
  * Note that we can have as well "/foo/::parent::foo[1]", so
12431
  * a duplicate-aware merge is still needed.
12432
  * Merge with the result.
12433
  */
12434
1.13M
  if (outSeq == NULL) {
12435
481k
      outSeq = seq;
12436
481k
      seq = NULL;
12437
481k
  } else
12438
            /* TODO: Check memory error. */
12439
656k
      outSeq = mergeAndClear(outSeq, seq);
12440
  /*
12441
  * Break if only a true/false result was requested.
12442
  */
12443
1.13M
  if (toBool)
12444
10.0k
      break;
12445
1.12M
  continue;
12446
12447
1.12M
first_hit: /* ---------------------------------------------------------- */
12448
  /*
12449
  * Break if only a true/false result was requested and
12450
  * no predicates existed and a node test succeeded.
12451
  */
12452
708k
  if (outSeq == NULL) {
12453
708k
      outSeq = seq;
12454
708k
      seq = NULL;
12455
708k
  } else
12456
            /* TODO: Check memory error. */
12457
0
      outSeq = mergeAndClear(outSeq, seq);
12458
708k
  break;
12459
12460
#ifdef DEBUG_STEP
12461
  if (seq != NULL)
12462
      nbMatches += seq->nodeNr;
12463
#endif
12464
12465
154M
apply_predicates: /* --------------------------------------------------- */
12466
154M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12467
0
      goto error;
12468
12469
        /*
12470
  * Apply predicates.
12471
  */
12472
154M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12473
      /*
12474
      * E.g. when we have a "/foo[some expression][n]".
12475
      */
12476
      /*
12477
      * QUESTION TODO: The old predicate evaluation took into
12478
      *  account location-sets.
12479
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12480
      *  Do we expect such a set here?
12481
      *  All what I learned now from the evaluation semantics
12482
      *  does not indicate that a location-set will be processed
12483
      *  here, so this looks OK.
12484
      */
12485
      /*
12486
      * Iterate over all predicates, starting with the outermost
12487
      * predicate.
12488
      * TODO: Problem: we cannot execute the inner predicates first
12489
      *  since we cannot go back *up* the operator tree!
12490
      *  Options we have:
12491
      *  1) Use of recursive functions (like is it currently done
12492
      *     via xmlXPathCompOpEval())
12493
      *  2) Add a predicate evaluation information stack to the
12494
      *     context struct
12495
      *  3) Change the way the operators are linked; we need a
12496
      *     "parent" field on xmlXPathStepOp
12497
      *
12498
      * For the moment, I'll try to solve this with a recursive
12499
      * function: xmlXPathCompOpEvalPredicate().
12500
      */
12501
13.5M
      if (hasPredicateRange != 0)
12502
556k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12503
556k
              hasNsNodes);
12504
12.9M
      else
12505
12.9M
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12506
12.9M
              hasNsNodes);
12507
12508
13.5M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12509
158k
    total = 0;
12510
158k
    goto error;
12511
158k
      }
12512
13.5M
        }
12513
12514
154M
        if (seq->nodeNr > 0) {
12515
      /*
12516
      * Add to result set.
12517
      */
12518
20.9M
      if (outSeq == NULL) {
12519
9.06M
    outSeq = seq;
12520
9.06M
    seq = NULL;
12521
11.9M
      } else {
12522
                /* TODO: Check memory error. */
12523
11.9M
    outSeq = mergeAndClear(outSeq, seq);
12524
11.9M
      }
12525
12526
20.9M
            if (toBool)
12527
49.2k
                break;
12528
20.9M
  }
12529
154M
    }
12530
12531
78.6M
error:
12532
78.6M
    if ((obj->boolval) && (obj->user != NULL)) {
12533
  /*
12534
  * QUESTION TODO: What does this do and why?
12535
  * TODO: Do we have to do this also for the "error"
12536
  * cleanup further down?
12537
  */
12538
0
  ctxt->value->boolval = 1;
12539
0
  ctxt->value->user = obj->user;
12540
0
  obj->user = NULL;
12541
0
  obj->boolval = 0;
12542
0
    }
12543
78.6M
    xmlXPathReleaseObject(xpctxt, obj);
12544
12545
    /*
12546
    * Ensure we return at least an empty set.
12547
    */
12548
78.6M
    if (outSeq == NULL) {
12549
68.4M
  if ((seq != NULL) && (seq->nodeNr == 0))
12550
68.4M
      outSeq = seq;
12551
1.11k
  else
12552
            /* TODO: Check memory error. */
12553
1.11k
      outSeq = xmlXPathNodeSetCreate(NULL);
12554
68.4M
    }
12555
78.6M
    if ((seq != NULL) && (seq != outSeq)) {
12556
968k
   xmlXPathFreeNodeSet(seq);
12557
968k
    }
12558
    /*
12559
    * Hand over the result. Better to push the set also in
12560
    * case of errors.
12561
    */
12562
78.6M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563
    /*
12564
    * Reset the context node.
12565
    */
12566
78.6M
    xpctxt->node = oldContextNode;
12567
    /*
12568
    * When traversing the namespace axis in "toBool" mode, it's
12569
    * possible that tmpNsList wasn't freed.
12570
    */
12571
78.6M
    if (xpctxt->tmpNsList != NULL) {
12572
25.6k
        xmlFree(xpctxt->tmpNsList);
12573
25.6k
        xpctxt->tmpNsList = NULL;
12574
25.6k
    }
12575
12576
#ifdef DEBUG_STEP
12577
    xmlGenericError(xmlGenericErrorContext,
12578
  "\nExamined %d nodes, found %d nodes at that step\n",
12579
  total, nbMatches);
12580
#endif
12581
12582
78.6M
    return(total);
12583
78.6M
}
12584
12585
static int
12586
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12587
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12588
12589
/**
12590
 * xmlXPathCompOpEvalFirst:
12591
 * @ctxt:  the XPath parser context with the compiled expression
12592
 * @op:  an XPath compiled operation
12593
 * @first:  the first elem found so far
12594
 *
12595
 * Evaluate the Precompiled XPath operation searching only the first
12596
 * element in document order
12597
 *
12598
 * Returns the number of examined objects.
12599
 */
12600
static int
12601
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12602
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12603
8.38M
{
12604
8.38M
    int total = 0, cur;
12605
8.38M
    xmlXPathCompExprPtr comp;
12606
8.38M
    xmlXPathObjectPtr arg1, arg2;
12607
12608
8.38M
    CHECK_ERROR0;
12609
8.38M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12610
21
        return(0);
12611
8.38M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12612
8.38M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12613
8.38M
    ctxt->context->depth += 1;
12614
8.38M
    comp = ctxt->comp;
12615
8.38M
    switch (op->op) {
12616
0
        case XPATH_OP_END:
12617
0
            break;
12618
1.56M
        case XPATH_OP_UNION:
12619
1.56M
            total =
12620
1.56M
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12621
1.56M
                                        first);
12622
1.56M
      CHECK_ERROR0;
12623
1.53M
            if ((ctxt->value != NULL)
12624
1.53M
                && (ctxt->value->type == XPATH_NODESET)
12625
1.53M
                && (ctxt->value->nodesetval != NULL)
12626
1.53M
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12627
                /*
12628
                 * limit tree traversing to first node in the result
12629
                 */
12630
    /*
12631
    * OPTIMIZE TODO: This implicitly sorts
12632
    *  the result, even if not needed. E.g. if the argument
12633
    *  of the count() function, no sorting is needed.
12634
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12635
    *  already sorted?
12636
    */
12637
487k
    if (ctxt->value->nodesetval->nodeNr > 1)
12638
34.4k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12639
487k
                *first = ctxt->value->nodesetval->nodeTab[0];
12640
487k
            }
12641
1.53M
            cur =
12642
1.53M
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12643
1.53M
                                        first);
12644
1.53M
      CHECK_ERROR0;
12645
12646
1.50M
            arg2 = valuePop(ctxt);
12647
1.50M
            arg1 = valuePop(ctxt);
12648
1.50M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12649
1.50M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12650
107k
          xmlXPathReleaseObject(ctxt->context, arg1);
12651
107k
          xmlXPathReleaseObject(ctxt->context, arg2);
12652
107k
                XP_ERROR0(XPATH_INVALID_TYPE);
12653
0
            }
12654
1.39M
            if ((ctxt->context->opLimit != 0) &&
12655
1.39M
                (((arg1->nodesetval != NULL) &&
12656
1.39M
                  (xmlXPathCheckOpLimit(ctxt,
12657
1.12M
                                        arg1->nodesetval->nodeNr) < 0)) ||
12658
1.39M
                 ((arg2->nodesetval != NULL) &&
12659
1.39M
                  (xmlXPathCheckOpLimit(ctxt,
12660
1.28M
                                        arg2->nodesetval->nodeNr) < 0)))) {
12661
17
          xmlXPathReleaseObject(ctxt->context, arg1);
12662
17
          xmlXPathReleaseObject(ctxt->context, arg2);
12663
17
                break;
12664
17
            }
12665
12666
            /* TODO: Check memory error. */
12667
1.39M
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668
1.39M
                                                    arg2->nodesetval);
12669
1.39M
            valuePush(ctxt, arg1);
12670
1.39M
      xmlXPathReleaseObject(ctxt->context, arg2);
12671
            /* optimizer */
12672
1.39M
      if (total > cur)
12673
54.6k
    xmlXPathCompSwap(op);
12674
1.39M
            total += cur;
12675
1.39M
            break;
12676
152k
        case XPATH_OP_ROOT:
12677
152k
            xmlXPathRoot(ctxt);
12678
152k
            break;
12679
1.05M
        case XPATH_OP_NODE:
12680
1.05M
            if (op->ch1 != -1)
12681
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12682
1.05M
      CHECK_ERROR0;
12683
1.05M
            if (op->ch2 != -1)
12684
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12685
1.05M
      CHECK_ERROR0;
12686
1.05M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12687
1.05M
    ctxt->context->node));
12688
1.05M
            break;
12689
2.16M
        case XPATH_OP_COLLECT:{
12690
2.16M
                if (op->ch1 == -1)
12691
0
                    break;
12692
12693
2.16M
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12694
2.16M
    CHECK_ERROR0;
12695
12696
2.11M
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12697
2.11M
                break;
12698
2.16M
            }
12699
140k
        case XPATH_OP_VALUE:
12700
140k
            valuePush(ctxt,
12701
140k
                      xmlXPathCacheObjectCopy(ctxt->context,
12702
140k
      (xmlXPathObjectPtr) op->value4));
12703
140k
            break;
12704
2.22M
        case XPATH_OP_SORT:
12705
2.22M
            if (op->ch1 != -1)
12706
2.22M
                total +=
12707
2.22M
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12708
2.22M
                                            first);
12709
2.22M
      CHECK_ERROR0;
12710
1.93M
            if ((ctxt->value != NULL)
12711
1.93M
                && (ctxt->value->type == XPATH_NODESET)
12712
1.93M
                && (ctxt->value->nodesetval != NULL)
12713
1.93M
    && (ctxt->value->nodesetval->nodeNr > 1))
12714
130k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12715
1.93M
            break;
12716
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12717
866k
  case XPATH_OP_FILTER:
12718
866k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12719
866k
            break;
12720
0
#endif
12721
216k
        default:
12722
216k
            total += xmlXPathCompOpEval(ctxt, op);
12723
216k
            break;
12724
8.38M
    }
12725
12726
7.87M
    ctxt->context->depth -= 1;
12727
7.87M
    return(total);
12728
8.38M
}
12729
12730
/**
12731
 * xmlXPathCompOpEvalLast:
12732
 * @ctxt:  the XPath parser context with the compiled expression
12733
 * @op:  an XPath compiled operation
12734
 * @last:  the last elem found so far
12735
 *
12736
 * Evaluate the Precompiled XPath operation searching only the last
12737
 * element in document order
12738
 *
12739
 * Returns the number of nodes traversed
12740
 */
12741
static int
12742
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12743
                       xmlNodePtr * last)
12744
4.35M
{
12745
4.35M
    int total = 0, cur;
12746
4.35M
    xmlXPathCompExprPtr comp;
12747
4.35M
    xmlXPathObjectPtr arg1, arg2;
12748
12749
4.35M
    CHECK_ERROR0;
12750
4.35M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12751
15
        return(0);
12752
4.35M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12753
4.35M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12754
4.35M
    ctxt->context->depth += 1;
12755
4.35M
    comp = ctxt->comp;
12756
4.35M
    switch (op->op) {
12757
0
        case XPATH_OP_END:
12758
0
            break;
12759
1.20M
        case XPATH_OP_UNION:
12760
1.20M
            total =
12761
1.20M
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12762
1.20M
      CHECK_ERROR0;
12763
1.13M
            if ((ctxt->value != NULL)
12764
1.13M
                && (ctxt->value->type == XPATH_NODESET)
12765
1.13M
                && (ctxt->value->nodesetval != NULL)
12766
1.13M
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767
                /*
12768
                 * limit tree traversing to first node in the result
12769
                 */
12770
583k
    if (ctxt->value->nodesetval->nodeNr > 1)
12771
71.7k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12772
583k
                *last =
12773
583k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12774
583k
                                                     nodesetval->nodeNr -
12775
583k
                                                     1];
12776
583k
            }
12777
1.13M
            cur =
12778
1.13M
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12779
1.13M
      CHECK_ERROR0;
12780
1.10M
            if ((ctxt->value != NULL)
12781
1.10M
                && (ctxt->value->type == XPATH_NODESET)
12782
1.10M
                && (ctxt->value->nodesetval != NULL)
12783
1.10M
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12784
400k
            }
12785
12786
1.10M
            arg2 = valuePop(ctxt);
12787
1.10M
            arg1 = valuePop(ctxt);
12788
1.10M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12789
1.10M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12790
16.3k
          xmlXPathReleaseObject(ctxt->context, arg1);
12791
16.3k
          xmlXPathReleaseObject(ctxt->context, arg2);
12792
16.3k
                XP_ERROR0(XPATH_INVALID_TYPE);
12793
0
            }
12794
1.08M
            if ((ctxt->context->opLimit != 0) &&
12795
1.08M
                (((arg1->nodesetval != NULL) &&
12796
1.08M
                  (xmlXPathCheckOpLimit(ctxt,
12797
1.03M
                                        arg1->nodesetval->nodeNr) < 0)) ||
12798
1.08M
                 ((arg2->nodesetval != NULL) &&
12799
1.08M
                  (xmlXPathCheckOpLimit(ctxt,
12800
1.01M
                                        arg2->nodesetval->nodeNr) < 0)))) {
12801
13
          xmlXPathReleaseObject(ctxt->context, arg1);
12802
13
          xmlXPathReleaseObject(ctxt->context, arg2);
12803
13
                break;
12804
13
            }
12805
12806
            /* TODO: Check memory error. */
12807
1.08M
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12808
1.08M
                                                    arg2->nodesetval);
12809
1.08M
            valuePush(ctxt, arg1);
12810
1.08M
      xmlXPathReleaseObject(ctxt->context, arg2);
12811
            /* optimizer */
12812
1.08M
      if (total > cur)
12813
21.5k
    xmlXPathCompSwap(op);
12814
1.08M
            total += cur;
12815
1.08M
            break;
12816
203k
        case XPATH_OP_ROOT:
12817
203k
            xmlXPathRoot(ctxt);
12818
203k
            break;
12819
233k
        case XPATH_OP_NODE:
12820
233k
            if (op->ch1 != -1)
12821
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822
233k
      CHECK_ERROR0;
12823
233k
            if (op->ch2 != -1)
12824
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12825
233k
      CHECK_ERROR0;
12826
233k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12827
233k
    ctxt->context->node));
12828
233k
            break;
12829
1.43M
        case XPATH_OP_COLLECT:{
12830
1.43M
                if (op->ch1 == -1)
12831
0
                    break;
12832
12833
1.43M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12834
1.43M
    CHECK_ERROR0;
12835
12836
1.43M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12837
1.43M
                break;
12838
1.43M
            }
12839
16.2k
        case XPATH_OP_VALUE:
12840
16.2k
            valuePush(ctxt,
12841
16.2k
                      xmlXPathCacheObjectCopy(ctxt->context,
12842
16.2k
      (xmlXPathObjectPtr) op->value4));
12843
16.2k
            break;
12844
1.06M
        case XPATH_OP_SORT:
12845
1.06M
            if (op->ch1 != -1)
12846
1.06M
                total +=
12847
1.06M
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12848
1.06M
                                           last);
12849
1.06M
      CHECK_ERROR0;
12850
978k
            if ((ctxt->value != NULL)
12851
978k
                && (ctxt->value->type == XPATH_NODESET)
12852
978k
                && (ctxt->value->nodesetval != NULL)
12853
978k
    && (ctxt->value->nodesetval->nodeNr > 1))
12854
180k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12855
978k
            break;
12856
195k
        default:
12857
195k
            total += xmlXPathCompOpEval(ctxt, op);
12858
195k
            break;
12859
4.35M
    }
12860
12861
4.14M
    ctxt->context->depth -= 1;
12862
4.14M
    return (total);
12863
4.35M
}
12864
12865
#ifdef XP_OPTIMIZED_FILTER_FIRST
12866
static int
12867
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12868
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12869
866k
{
12870
866k
    int total = 0;
12871
866k
    xmlXPathCompExprPtr comp;
12872
866k
    xmlNodeSetPtr set;
12873
12874
866k
    CHECK_ERROR0;
12875
866k
    comp = ctxt->comp;
12876
    /*
12877
    * Optimization for ()[last()] selection i.e. the last elem
12878
    */
12879
866k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12880
866k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12881
866k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12882
495k
  int f = comp->steps[op->ch2].ch1;
12883
12884
495k
  if ((f != -1) &&
12885
495k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12886
495k
      (comp->steps[f].value5 == NULL) &&
12887
495k
      (comp->steps[f].value == 0) &&
12888
495k
      (comp->steps[f].value4 != NULL) &&
12889
495k
      (xmlStrEqual
12890
400k
      (comp->steps[f].value4, BAD_CAST "last"))) {
12891
353k
      xmlNodePtr last = NULL;
12892
12893
353k
      total +=
12894
353k
    xmlXPathCompOpEvalLast(ctxt,
12895
353k
        &comp->steps[op->ch1],
12896
353k
        &last);
12897
353k
      CHECK_ERROR0;
12898
      /*
12899
      * The nodeset should be in document order,
12900
      * Keep only the last value
12901
      */
12902
311k
      if ((ctxt->value != NULL) &&
12903
311k
    (ctxt->value->type == XPATH_NODESET) &&
12904
311k
    (ctxt->value->nodesetval != NULL) &&
12905
311k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12906
311k
    (ctxt->value->nodesetval->nodeNr > 1)) {
12907
50.9k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12908
50.9k
    *first = *(ctxt->value->nodesetval->nodeTab);
12909
50.9k
      }
12910
311k
      return (total);
12911
353k
  }
12912
495k
    }
12913
12914
512k
    if (op->ch1 != -1)
12915
512k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12916
512k
    CHECK_ERROR0;
12917
395k
    if (op->ch2 == -1)
12918
0
  return (total);
12919
395k
    if (ctxt->value == NULL)
12920
0
  return (total);
12921
12922
#ifdef LIBXML_XPTR_LOCS_ENABLED
12923
    /*
12924
    * Hum are we filtering the result of an XPointer expression
12925
    */
12926
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12927
        xmlLocationSetPtr locset = ctxt->value->user;
12928
12929
        if (locset != NULL) {
12930
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12931
            if (locset->locNr > 0)
12932
                *first = (xmlNodePtr) locset->locTab[0]->user;
12933
        }
12934
12935
  return (total);
12936
    }
12937
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12938
12939
395k
    CHECK_TYPE0(XPATH_NODESET);
12940
363k
    set = ctxt->value->nodesetval;
12941
363k
    if (set != NULL) {
12942
256k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12943
256k
        if (set->nodeNr > 0)
12944
82.3k
            *first = set->nodeTab[0];
12945
256k
    }
12946
12947
363k
    return (total);
12948
395k
}
12949
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12950
12951
/**
12952
 * xmlXPathCompOpEval:
12953
 * @ctxt:  the XPath parser context with the compiled expression
12954
 * @op:  an XPath compiled operation
12955
 *
12956
 * Evaluate the Precompiled XPath operation
12957
 * Returns the number of nodes traversed
12958
 */
12959
static int
12960
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12961
473M
{
12962
473M
    int total = 0;
12963
473M
    int equal, ret;
12964
473M
    xmlXPathCompExprPtr comp;
12965
473M
    xmlXPathObjectPtr arg1, arg2;
12966
12967
473M
    CHECK_ERROR0;
12968
473M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12969
7.61k
        return(0);
12970
473M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12971
473M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12972
473M
    ctxt->context->depth += 1;
12973
473M
    comp = ctxt->comp;
12974
473M
    switch (op->op) {
12975
0
        case XPATH_OP_END:
12976
0
            break;
12977
1.45M
        case XPATH_OP_AND:
12978
1.45M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12979
1.45M
      CHECK_ERROR0;
12980
1.38M
            xmlXPathBooleanFunction(ctxt, 1);
12981
1.38M
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12982
702k
                break;
12983
677k
            arg2 = valuePop(ctxt);
12984
677k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12985
677k
      if (ctxt->error) {
12986
17.2k
    xmlXPathFreeObject(arg2);
12987
17.2k
    break;
12988
17.2k
      }
12989
659k
            xmlXPathBooleanFunction(ctxt, 1);
12990
659k
            if (ctxt->value != NULL)
12991
659k
                ctxt->value->boolval &= arg2->boolval;
12992
659k
      xmlXPathReleaseObject(ctxt->context, arg2);
12993
659k
            break;
12994
1.24M
        case XPATH_OP_OR:
12995
1.24M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996
1.24M
      CHECK_ERROR0;
12997
1.21M
            xmlXPathBooleanFunction(ctxt, 1);
12998
1.21M
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12999
162k
                break;
13000
1.04M
            arg2 = valuePop(ctxt);
13001
1.04M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13002
1.04M
      if (ctxt->error) {
13003
156k
    xmlXPathFreeObject(arg2);
13004
156k
    break;
13005
156k
      }
13006
892k
            xmlXPathBooleanFunction(ctxt, 1);
13007
892k
            if (ctxt->value != NULL)
13008
892k
                ctxt->value->boolval |= arg2->boolval;
13009
892k
      xmlXPathReleaseObject(ctxt->context, arg2);
13010
892k
            break;
13011
18.0M
        case XPATH_OP_EQUAL:
13012
18.0M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013
18.0M
      CHECK_ERROR0;
13014
17.7M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13015
17.7M
      CHECK_ERROR0;
13016
17.2M
      if (op->value)
13017
15.8M
    equal = xmlXPathEqualValues(ctxt);
13018
1.42M
      else
13019
1.42M
    equal = xmlXPathNotEqualValues(ctxt);
13020
17.2M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13021
17.2M
            break;
13022
21.9M
        case XPATH_OP_CMP:
13023
21.9M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
21.9M
      CHECK_ERROR0;
13025
20.4M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13026
20.4M
      CHECK_ERROR0;
13027
19.9M
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13028
19.9M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13029
19.9M
            break;
13030
12.1M
        case XPATH_OP_PLUS:
13031
12.1M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13032
12.1M
      CHECK_ERROR0;
13033
11.9M
            if (op->ch2 != -1) {
13034
10.7M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13035
10.7M
      }
13036
11.9M
      CHECK_ERROR0;
13037
11.7M
            if (op->value == 0)
13038
5.15M
                xmlXPathSubValues(ctxt);
13039
6.59M
            else if (op->value == 1)
13040
5.42M
                xmlXPathAddValues(ctxt);
13041
1.16M
            else if (op->value == 2)
13042
1.05M
                xmlXPathValueFlipSign(ctxt);
13043
116k
            else if (op->value == 3) {
13044
116k
                CAST_TO_NUMBER;
13045
116k
                CHECK_TYPE0(XPATH_NUMBER);
13046
116k
            }
13047
11.7M
            break;
13048
19.0M
        case XPATH_OP_MULT:
13049
19.0M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13050
19.0M
      CHECK_ERROR0;
13051
18.7M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13052
18.7M
      CHECK_ERROR0;
13053
18.4M
            if (op->value == 0)
13054
17.6M
                xmlXPathMultValues(ctxt);
13055
777k
            else if (op->value == 1)
13056
459k
                xmlXPathDivValues(ctxt);
13057
317k
            else if (op->value == 2)
13058
317k
                xmlXPathModValues(ctxt);
13059
18.4M
            break;
13060
12.9M
        case XPATH_OP_UNION:
13061
12.9M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13062
12.9M
      CHECK_ERROR0;
13063
12.4M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13064
12.4M
      CHECK_ERROR0;
13065
13066
11.9M
            arg2 = valuePop(ctxt);
13067
11.9M
            arg1 = valuePop(ctxt);
13068
11.9M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13069
11.9M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13070
348k
          xmlXPathReleaseObject(ctxt->context, arg1);
13071
348k
          xmlXPathReleaseObject(ctxt->context, arg2);
13072
348k
                XP_ERROR0(XPATH_INVALID_TYPE);
13073
0
            }
13074
11.6M
            if ((ctxt->context->opLimit != 0) &&
13075
11.6M
                (((arg1->nodesetval != NULL) &&
13076
11.6M
                  (xmlXPathCheckOpLimit(ctxt,
13077
11.2M
                                        arg1->nodesetval->nodeNr) < 0)) ||
13078
11.6M
                 ((arg2->nodesetval != NULL) &&
13079
11.6M
                  (xmlXPathCheckOpLimit(ctxt,
13080
9.32M
                                        arg2->nodesetval->nodeNr) < 0)))) {
13081
76
          xmlXPathReleaseObject(ctxt->context, arg1);
13082
76
          xmlXPathReleaseObject(ctxt->context, arg2);
13083
76
                break;
13084
76
            }
13085
13086
11.6M
      if ((arg1->nodesetval == NULL) ||
13087
11.6M
    ((arg2->nodesetval != NULL) &&
13088
11.2M
     (arg2->nodesetval->nodeNr != 0)))
13089
2.88M
      {
13090
                /* TODO: Check memory error. */
13091
2.88M
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13092
2.88M
              arg2->nodesetval);
13093
2.88M
      }
13094
13095
11.6M
            valuePush(ctxt, arg1);
13096
11.6M
      xmlXPathReleaseObject(ctxt->context, arg2);
13097
11.6M
            break;
13098
11.4M
        case XPATH_OP_ROOT:
13099
11.4M
            xmlXPathRoot(ctxt);
13100
11.4M
            break;
13101
85.1M
        case XPATH_OP_NODE:
13102
85.1M
            if (op->ch1 != -1)
13103
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104
85.1M
      CHECK_ERROR0;
13105
85.1M
            if (op->ch2 != -1)
13106
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13107
85.1M
      CHECK_ERROR0;
13108
85.1M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13109
85.1M
    ctxt->context->node));
13110
85.1M
            break;
13111
84.8M
        case XPATH_OP_COLLECT:{
13112
84.8M
                if (op->ch1 == -1)
13113
0
                    break;
13114
13115
84.8M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13116
84.8M
    CHECK_ERROR0;
13117
13118
83.7M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13119
83.7M
                break;
13120
84.8M
            }
13121
51.6M
        case XPATH_OP_VALUE:
13122
51.6M
            valuePush(ctxt,
13123
51.6M
                      xmlXPathCacheObjectCopy(ctxt->context,
13124
51.6M
      (xmlXPathObjectPtr) op->value4));
13125
51.6M
            break;
13126
205k
        case XPATH_OP_VARIABLE:{
13127
205k
    xmlXPathObjectPtr val;
13128
13129
205k
                if (op->ch1 != -1)
13130
0
                    total +=
13131
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13132
205k
                if (op->value5 == NULL) {
13133
149k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13134
149k
        if (val == NULL)
13135
149k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13136
0
                    valuePush(ctxt, val);
13137
56.0k
    } else {
13138
56.0k
                    const xmlChar *URI;
13139
13140
56.0k
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13141
56.0k
                    if (URI == NULL) {
13142
41.1k
                        xmlGenericError(xmlGenericErrorContext,
13143
41.1k
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13144
41.1k
                                    (char *) op->value4, (char *)op->value5);
13145
41.1k
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13146
41.1k
                        break;
13147
41.1k
                    }
13148
14.8k
        val = xmlXPathVariableLookupNS(ctxt->context,
13149
14.8k
                                                       op->value4, URI);
13150
14.8k
        if (val == NULL)
13151
14.8k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13152
0
                    valuePush(ctxt, val);
13153
0
                }
13154
0
                break;
13155
205k
            }
13156
49.3M
        case XPATH_OP_FUNCTION:{
13157
49.3M
                xmlXPathFunction func;
13158
49.3M
                const xmlChar *oldFunc, *oldFuncURI;
13159
49.3M
    int i;
13160
49.3M
                int frame;
13161
13162
49.3M
                frame = xmlXPathSetFrame(ctxt);
13163
49.3M
                if (op->ch1 != -1) {
13164
40.8M
                    total +=
13165
40.8M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13166
40.8M
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13167
201k
                        xmlXPathPopFrame(ctxt, frame);
13168
201k
                        break;
13169
201k
                    }
13170
40.8M
                }
13171
49.1M
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13172
0
        xmlGenericError(xmlGenericErrorContext,
13173
0
          "xmlXPathCompOpEval: parameter error\n");
13174
0
        ctxt->error = XPATH_INVALID_OPERAND;
13175
0
                    xmlXPathPopFrame(ctxt, frame);
13176
0
        break;
13177
0
    }
13178
108M
    for (i = 0; i < op->value; i++) {
13179
59.4M
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13180
0
      xmlGenericError(xmlGenericErrorContext,
13181
0
        "xmlXPathCompOpEval: parameter error\n");
13182
0
      ctxt->error = XPATH_INVALID_OPERAND;
13183
0
                        xmlXPathPopFrame(ctxt, frame);
13184
0
      break;
13185
0
        }
13186
59.4M
                }
13187
49.1M
                if (op->cache != NULL)
13188
44.8M
                    func = op->cache;
13189
4.30M
                else {
13190
4.30M
                    const xmlChar *URI = NULL;
13191
13192
4.30M
                    if (op->value5 == NULL)
13193
2.90M
                        func =
13194
2.90M
                            xmlXPathFunctionLookup(ctxt->context,
13195
2.90M
                                                   op->value4);
13196
1.39M
                    else {
13197
1.39M
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13198
1.39M
                        if (URI == NULL) {
13199
47.8k
                            xmlGenericError(xmlGenericErrorContext,
13200
47.8k
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13201
47.8k
                                    (char *)op->value4, (char *)op->value5);
13202
47.8k
                            xmlXPathPopFrame(ctxt, frame);
13203
47.8k
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13204
47.8k
                            break;
13205
47.8k
                        }
13206
1.34M
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13207
1.34M
                                                        op->value4, URI);
13208
1.34M
                    }
13209
4.25M
                    if (func == NULL) {
13210
957k
                        xmlGenericError(xmlGenericErrorContext,
13211
957k
                                "xmlXPathCompOpEval: function %s not found\n",
13212
957k
                                        (char *)op->value4);
13213
957k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13214
0
                    }
13215
3.30M
                    op->cache = func;
13216
3.30M
                    op->cacheURI = (void *) URI;
13217
3.30M
                }
13218
48.1M
                oldFunc = ctxt->context->function;
13219
48.1M
                oldFuncURI = ctxt->context->functionURI;
13220
48.1M
                ctxt->context->function = op->value4;
13221
48.1M
                ctxt->context->functionURI = op->cacheURI;
13222
48.1M
                func(ctxt, op->value);
13223
48.1M
                ctxt->context->function = oldFunc;
13224
48.1M
                ctxt->context->functionURI = oldFuncURI;
13225
48.1M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13226
48.1M
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13227
48.1M
                    XP_ERROR0(XPATH_STACK_ERROR);
13228
48.1M
                xmlXPathPopFrame(ctxt, frame);
13229
48.1M
                break;
13230
48.1M
            }
13231
59.7M
        case XPATH_OP_ARG:
13232
59.7M
            if (op->ch1 != -1) {
13233
18.9M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13234
18.9M
          CHECK_ERROR0;
13235
18.9M
            }
13236
59.7M
            if (op->ch2 != -1) {
13237
59.7M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238
59.7M
          CHECK_ERROR0;
13239
59.7M
      }
13240
59.5M
            break;
13241
59.5M
        case XPATH_OP_PREDICATE:
13242
6.22M
        case XPATH_OP_FILTER:{
13243
6.22M
                xmlNodeSetPtr set;
13244
13245
                /*
13246
                 * Optimization for ()[1] selection i.e. the first elem
13247
                 */
13248
6.22M
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13249
6.22M
#ifdef XP_OPTIMIZED_FILTER_FIRST
13250
        /*
13251
        * FILTER TODO: Can we assume that the inner processing
13252
        *  will result in an ordered list if we have an
13253
        *  XPATH_OP_FILTER?
13254
        *  What about an additional field or flag on
13255
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13256
        *  to assume anything, so it would be more robust and
13257
        *  easier to optimize.
13258
        */
13259
6.22M
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13260
6.22M
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13261
#else
13262
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13263
#endif
13264
6.22M
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13265
3.30M
                    xmlXPathObjectPtr val;
13266
13267
3.30M
                    val = comp->steps[op->ch2].value4;
13268
3.30M
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13269
3.30M
                        (val->floatval == 1.0)) {
13270
3.06M
                        xmlNodePtr first = NULL;
13271
13272
3.06M
                        total +=
13273
3.06M
                            xmlXPathCompOpEvalFirst(ctxt,
13274
3.06M
                                                    &comp->steps[op->ch1],
13275
3.06M
                                                    &first);
13276
3.06M
      CHECK_ERROR0;
13277
                        /*
13278
                         * The nodeset should be in document order,
13279
                         * Keep only the first value
13280
                         */
13281
2.56M
                        if ((ctxt->value != NULL) &&
13282
2.56M
                            (ctxt->value->type == XPATH_NODESET) &&
13283
2.56M
                            (ctxt->value->nodesetval != NULL) &&
13284
2.56M
                            (ctxt->value->nodesetval->nodeNr > 1))
13285
130k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13286
130k
                                                        1, 1);
13287
2.56M
                        break;
13288
3.06M
                    }
13289
3.30M
                }
13290
                /*
13291
                 * Optimization for ()[last()] selection i.e. the last elem
13292
                 */
13293
3.16M
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13294
3.16M
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13295
3.16M
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13296
935k
                    int f = comp->steps[op->ch2].ch1;
13297
13298
935k
                    if ((f != -1) &&
13299
935k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13300
935k
                        (comp->steps[f].value5 == NULL) &&
13301
935k
                        (comp->steps[f].value == 0) &&
13302
935k
                        (comp->steps[f].value4 != NULL) &&
13303
935k
                        (xmlStrEqual
13304
630k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13305
599k
                        xmlNodePtr last = NULL;
13306
13307
599k
                        total +=
13308
599k
                            xmlXPathCompOpEvalLast(ctxt,
13309
599k
                                                   &comp->steps[op->ch1],
13310
599k
                                                   &last);
13311
599k
      CHECK_ERROR0;
13312
                        /*
13313
                         * The nodeset should be in document order,
13314
                         * Keep only the last value
13315
                         */
13316
559k
                        if ((ctxt->value != NULL) &&
13317
559k
                            (ctxt->value->type == XPATH_NODESET) &&
13318
559k
                            (ctxt->value->nodesetval != NULL) &&
13319
559k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13320
559k
                            (ctxt->value->nodesetval->nodeNr > 1))
13321
84.7k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13322
559k
                        break;
13323
599k
                    }
13324
935k
                }
13325
    /*
13326
    * Process inner predicates first.
13327
    * Example "index[parent::book][1]":
13328
    * ...
13329
    *   PREDICATE   <-- we are here "[1]"
13330
    *     PREDICATE <-- process "[parent::book]" first
13331
    *       SORT
13332
    *         COLLECT  'parent' 'name' 'node' book
13333
    *           NODE
13334
    *     ELEM Object is a number : 1
13335
    */
13336
2.56M
                if (op->ch1 != -1)
13337
2.56M
                    total +=
13338
2.56M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339
2.56M
    CHECK_ERROR0;
13340
2.32M
                if (op->ch2 == -1)
13341
0
                    break;
13342
2.32M
                if (ctxt->value == NULL)
13343
0
                    break;
13344
13345
#ifdef LIBXML_XPTR_LOCS_ENABLED
13346
                /*
13347
                 * Hum are we filtering the result of an XPointer expression
13348
                 */
13349
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13350
                    xmlLocationSetPtr locset = ctxt->value->user;
13351
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13352
                                              1, locset->locNr);
13353
                    break;
13354
                }
13355
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13356
13357
2.32M
                CHECK_TYPE0(XPATH_NODESET);
13358
2.00M
                set = ctxt->value->nodesetval;
13359
2.00M
                if (set != NULL)
13360
1.83M
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13361
1.83M
                                          1, set->nodeNr, 1);
13362
2.00M
                break;
13363
2.32M
            }
13364
38.0M
        case XPATH_OP_SORT:
13365
38.0M
            if (op->ch1 != -1)
13366
38.0M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367
38.0M
      CHECK_ERROR0;
13368
33.3M
            if ((ctxt->value != NULL) &&
13369
33.3M
                (ctxt->value->type == XPATH_NODESET) &&
13370
33.3M
                (ctxt->value->nodesetval != NULL) &&
13371
33.3M
    (ctxt->value->nodesetval->nodeNr > 1))
13372
2.04M
      {
13373
2.04M
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13374
2.04M
      }
13375
33.3M
            break;
13376
#ifdef LIBXML_XPTR_LOCS_ENABLED
13377
        case XPATH_OP_RANGETO:{
13378
                xmlXPathObjectPtr range;
13379
                xmlXPathObjectPtr res, obj;
13380
                xmlXPathObjectPtr tmp;
13381
                xmlLocationSetPtr newlocset = NULL;
13382
        xmlLocationSetPtr oldlocset;
13383
                xmlNodeSetPtr oldset;
13384
                xmlNodePtr oldnode = ctxt->context->node;
13385
                int oldcs = ctxt->context->contextSize;
13386
                int oldpp = ctxt->context->proximityPosition;
13387
                int i, j;
13388
13389
                if (op->ch1 != -1) {
13390
                    total +=
13391
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13392
                    CHECK_ERROR0;
13393
                }
13394
                if (ctxt->value == NULL) {
13395
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13396
                }
13397
                if (op->ch2 == -1)
13398
                    break;
13399
13400
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13401
                    /*
13402
                     * Extract the old locset, and then evaluate the result of the
13403
                     * expression for all the element in the locset. use it to grow
13404
                     * up a new locset.
13405
                     */
13406
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13407
13408
                    if ((ctxt->value->user == NULL) ||
13409
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13410
                        break;
13411
13412
                    obj = valuePop(ctxt);
13413
                    oldlocset = obj->user;
13414
13415
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13416
13417
                    for (i = 0; i < oldlocset->locNr; i++) {
13418
                        /*
13419
                         * Run the evaluation with a node list made of a
13420
                         * single item in the nodelocset.
13421
                         */
13422
                        ctxt->context->node = oldlocset->locTab[i]->user;
13423
                        ctxt->context->contextSize = oldlocset->locNr;
13424
                        ctxt->context->proximityPosition = i + 1;
13425
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13426
          ctxt->context->node);
13427
                        valuePush(ctxt, tmp);
13428
13429
                        if (op->ch2 != -1)
13430
                            total +=
13431
                                xmlXPathCompOpEval(ctxt,
13432
                                                   &comp->steps[op->ch2]);
13433
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13434
                            xmlXPtrFreeLocationSet(newlocset);
13435
                            goto rangeto_error;
13436
      }
13437
13438
                        res = valuePop(ctxt);
13439
      if (res->type == XPATH_LOCATIONSET) {
13440
          xmlLocationSetPtr rloc =
13441
              (xmlLocationSetPtr)res->user;
13442
          for (j=0; j<rloc->locNr; j++) {
13443
              range = xmlXPtrNewRange(
13444
          oldlocset->locTab[i]->user,
13445
          oldlocset->locTab[i]->index,
13446
          rloc->locTab[j]->user2,
13447
          rloc->locTab[j]->index2);
13448
        if (range != NULL) {
13449
            xmlXPtrLocationSetAdd(newlocset, range);
13450
        }
13451
          }
13452
      } else {
13453
          range = xmlXPtrNewRangeNodeObject(
13454
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13455
                            if (range != NULL) {
13456
                                xmlXPtrLocationSetAdd(newlocset,range);
13457
          }
13458
                        }
13459
13460
                        /*
13461
                         * Cleanup
13462
                         */
13463
                        if (res != NULL) {
13464
          xmlXPathReleaseObject(ctxt->context, res);
13465
      }
13466
                        if (ctxt->value == tmp) {
13467
                            res = valuePop(ctxt);
13468
          xmlXPathReleaseObject(ctxt->context, res);
13469
                        }
13470
                    }
13471
    } else {  /* Not a location set */
13472
                    CHECK_TYPE0(XPATH_NODESET);
13473
                    obj = valuePop(ctxt);
13474
                    oldset = obj->nodesetval;
13475
13476
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13477
13478
                    if (oldset != NULL) {
13479
                        for (i = 0; i < oldset->nodeNr; i++) {
13480
                            /*
13481
                             * Run the evaluation with a node list made of a single item
13482
                             * in the nodeset.
13483
                             */
13484
                            ctxt->context->node = oldset->nodeTab[i];
13485
          /*
13486
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13487
          */
13488
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13489
        ctxt->context->node);
13490
                            valuePush(ctxt, tmp);
13491
13492
                            if (op->ch2 != -1)
13493
                                total +=
13494
                                    xmlXPathCompOpEval(ctxt,
13495
                                                   &comp->steps[op->ch2]);
13496
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13497
                                xmlXPtrFreeLocationSet(newlocset);
13498
                                goto rangeto_error;
13499
          }
13500
13501
                            res = valuePop(ctxt);
13502
                            range =
13503
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13504
                                                      res);
13505
                            if (range != NULL) {
13506
                                xmlXPtrLocationSetAdd(newlocset, range);
13507
                            }
13508
13509
                            /*
13510
                             * Cleanup
13511
                             */
13512
                            if (res != NULL) {
13513
        xmlXPathReleaseObject(ctxt->context, res);
13514
          }
13515
                            if (ctxt->value == tmp) {
13516
                                res = valuePop(ctxt);
13517
        xmlXPathReleaseObject(ctxt->context, res);
13518
                            }
13519
                        }
13520
                    }
13521
                }
13522
13523
                /*
13524
                 * The result is used as the new evaluation set.
13525
                 */
13526
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13527
rangeto_error:
13528
    xmlXPathReleaseObject(ctxt->context, obj);
13529
                ctxt->context->node = oldnode;
13530
                ctxt->context->contextSize = oldcs;
13531
                ctxt->context->proximityPosition = oldpp;
13532
                break;
13533
            }
13534
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13535
0
        default:
13536
0
            xmlGenericError(xmlGenericErrorContext,
13537
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13538
0
            ctxt->error = XPATH_INVALID_OPERAND;
13539
0
            break;
13540
473M
    }
13541
13542
460M
    ctxt->context->depth -= 1;
13543
460M
    return (total);
13544
473M
}
13545
13546
/**
13547
 * xmlXPathCompOpEvalToBoolean:
13548
 * @ctxt:  the XPath parser context
13549
 *
13550
 * Evaluates if the expression evaluates to true.
13551
 *
13552
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13553
 */
13554
static int
13555
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13556
          xmlXPathStepOpPtr op,
13557
          int isPredicate)
13558
46.5M
{
13559
46.5M
    xmlXPathObjectPtr resObj = NULL;
13560
13561
49.5M
start:
13562
49.5M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13563
207
        return(0);
13564
    /* comp = ctxt->comp; */
13565
49.5M
    switch (op->op) {
13566
0
        case XPATH_OP_END:
13567
0
            return (0);
13568
1.45M
  case XPATH_OP_VALUE:
13569
1.45M
      resObj = (xmlXPathObjectPtr) op->value4;
13570
1.45M
      if (isPredicate)
13571
1.45M
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13572
0
      return(xmlXPathCastToBoolean(resObj));
13573
3.00M
  case XPATH_OP_SORT:
13574
      /*
13575
      * We don't need sorting for boolean results. Skip this one.
13576
      */
13577
3.00M
            if (op->ch1 != -1) {
13578
3.00M
    op = &ctxt->comp->steps[op->ch1];
13579
3.00M
    goto start;
13580
3.00M
      }
13581
0
      return(0);
13582
4.51M
  case XPATH_OP_COLLECT:
13583
4.51M
      if (op->ch1 == -1)
13584
0
    return(0);
13585
13586
4.51M
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13587
4.51M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13588
11.6k
    return(-1);
13589
13590
4.50M
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13591
4.50M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13592
18.3k
    return(-1);
13593
13594
4.48M
      resObj = valuePop(ctxt);
13595
4.48M
      if (resObj == NULL)
13596
0
    return(-1);
13597
4.48M
      break;
13598
40.5M
  default:
13599
      /*
13600
      * Fallback to call xmlXPathCompOpEval().
13601
      */
13602
40.5M
      xmlXPathCompOpEval(ctxt, op);
13603
40.5M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13604
210k
    return(-1);
13605
13606
40.3M
      resObj = valuePop(ctxt);
13607
40.3M
      if (resObj == NULL)
13608
0
    return(-1);
13609
40.3M
      break;
13610
49.5M
    }
13611
13612
44.8M
    if (resObj) {
13613
44.8M
  int res;
13614
13615
44.8M
  if (resObj->type == XPATH_BOOLEAN) {
13616
22.1M
      res = resObj->boolval;
13617
22.7M
  } else if (isPredicate) {
13618
      /*
13619
      * For predicates a result of type "number" is handled
13620
      * differently:
13621
      * SPEC XPath 1.0:
13622
      * "If the result is a number, the result will be converted
13623
      *  to true if the number is equal to the context position
13624
      *  and will be converted to false otherwise;"
13625
      */
13626
22.7M
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13627
22.7M
  } else {
13628
0
      res = xmlXPathCastToBoolean(resObj);
13629
0
  }
13630
44.8M
  xmlXPathReleaseObject(ctxt->context, resObj);
13631
44.8M
  return(res);
13632
44.8M
    }
13633
13634
0
    return(0);
13635
44.8M
}
13636
13637
#ifdef XPATH_STREAMING
13638
/**
13639
 * xmlXPathRunStreamEval:
13640
 * @ctxt:  the XPath parser context with the compiled expression
13641
 *
13642
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13643
 */
13644
static int
13645
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13646
          xmlXPathObjectPtr *resultSeq, int toBool)
13647
2.27M
{
13648
2.27M
    int max_depth, min_depth;
13649
2.27M
    int from_root;
13650
2.27M
    int ret, depth;
13651
2.27M
    int eval_all_nodes;
13652
2.27M
    xmlNodePtr cur = NULL, limit = NULL;
13653
2.27M
    xmlStreamCtxtPtr patstream = NULL;
13654
13655
2.27M
    if ((ctxt == NULL) || (comp == NULL))
13656
0
        return(-1);
13657
2.27M
    max_depth = xmlPatternMaxDepth(comp);
13658
2.27M
    if (max_depth == -1)
13659
0
        return(-1);
13660
2.27M
    if (max_depth == -2)
13661
306k
        max_depth = 10000;
13662
2.27M
    min_depth = xmlPatternMinDepth(comp);
13663
2.27M
    if (min_depth == -1)
13664
0
        return(-1);
13665
2.27M
    from_root = xmlPatternFromRoot(comp);
13666
2.27M
    if (from_root < 0)
13667
0
        return(-1);
13668
#if 0
13669
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13670
#endif
13671
13672
2.27M
    if (! toBool) {
13673
2.27M
  if (resultSeq == NULL)
13674
0
      return(-1);
13675
2.27M
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13676
2.27M
  if (*resultSeq == NULL)
13677
0
      return(-1);
13678
2.27M
    }
13679
13680
    /*
13681
     * handle the special cases of "/" amd "." being matched
13682
     */
13683
2.27M
    if (min_depth == 0) {
13684
81.1k
  if (from_root) {
13685
      /* Select "/" */
13686
0
      if (toBool)
13687
0
    return(1);
13688
            /* TODO: Check memory error. */
13689
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13690
0
                         (xmlNodePtr) ctxt->doc);
13691
81.1k
  } else {
13692
      /* Select "self::node()" */
13693
81.1k
      if (toBool)
13694
0
    return(1);
13695
            /* TODO: Check memory error. */
13696
81.1k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13697
81.1k
  }
13698
81.1k
    }
13699
2.27M
    if (max_depth == 0) {
13700
56.6k
  return(0);
13701
56.6k
    }
13702
13703
2.22M
    if (from_root) {
13704
810k
        cur = (xmlNodePtr)ctxt->doc;
13705
1.41M
    } else if (ctxt->node != NULL) {
13706
1.41M
        switch (ctxt->node->type) {
13707
466k
            case XML_ELEMENT_NODE:
13708
908k
            case XML_DOCUMENT_NODE:
13709
908k
            case XML_DOCUMENT_FRAG_NODE:
13710
908k
            case XML_HTML_DOCUMENT_NODE:
13711
908k
          cur = ctxt->node;
13712
908k
    break;
13713
0
            case XML_ATTRIBUTE_NODE:
13714
421k
            case XML_TEXT_NODE:
13715
435k
            case XML_CDATA_SECTION_NODE:
13716
435k
            case XML_ENTITY_REF_NODE:
13717
435k
            case XML_ENTITY_NODE:
13718
467k
            case XML_PI_NODE:
13719
494k
            case XML_COMMENT_NODE:
13720
494k
            case XML_NOTATION_NODE:
13721
494k
            case XML_DTD_NODE:
13722
494k
            case XML_DOCUMENT_TYPE_NODE:
13723
494k
            case XML_ELEMENT_DECL:
13724
494k
            case XML_ATTRIBUTE_DECL:
13725
494k
            case XML_ENTITY_DECL:
13726
502k
            case XML_NAMESPACE_DECL:
13727
502k
            case XML_XINCLUDE_START:
13728
502k
            case XML_XINCLUDE_END:
13729
502k
    break;
13730
1.41M
  }
13731
1.41M
  limit = cur;
13732
1.41M
    }
13733
2.22M
    if (cur == NULL) {
13734
502k
        return(0);
13735
502k
    }
13736
13737
1.71M
    patstream = xmlPatternGetStreamCtxt(comp);
13738
1.71M
    if (patstream == NULL) {
13739
  /*
13740
  * QUESTION TODO: Is this an error?
13741
  */
13742
0
  return(0);
13743
0
    }
13744
13745
1.71M
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746
13747
1.71M
    if (from_root) {
13748
810k
  ret = xmlStreamPush(patstream, NULL, NULL);
13749
810k
  if (ret < 0) {
13750
810k
  } else if (ret == 1) {
13751
31.7k
      if (toBool)
13752
0
    goto return_1;
13753
            /* TODO: Check memory error. */
13754
31.7k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755
31.7k
  }
13756
810k
    }
13757
1.71M
    depth = 0;
13758
1.71M
    goto scan_children;
13759
19.4M
next_node:
13760
30.6M
    do {
13761
30.6M
        if (ctxt->opLimit != 0) {
13762
30.6M
            if (ctxt->opCount >= ctxt->opLimit) {
13763
753
                xmlGenericError(xmlGenericErrorContext,
13764
753
                        "XPath operation limit exceeded\n");
13765
753
                xmlFreeStreamCtxt(patstream);
13766
753
                return(-1);
13767
753
            }
13768
30.6M
            ctxt->opCount++;
13769
30.6M
        }
13770
13771
30.6M
  switch (cur->type) {
13772
15.4M
      case XML_ELEMENT_NODE:
13773
25.5M
      case XML_TEXT_NODE:
13774
25.8M
      case XML_CDATA_SECTION_NODE:
13775
26.4M
      case XML_COMMENT_NODE:
13776
27.6M
      case XML_PI_NODE:
13777
27.6M
    if (cur->type == XML_ELEMENT_NODE) {
13778
15.4M
        ret = xmlStreamPush(patstream, cur->name,
13779
15.4M
        (cur->ns ? cur->ns->href : NULL));
13780
15.4M
    } else if (eval_all_nodes)
13781
2.93M
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13782
9.25M
    else
13783
9.25M
        break;
13784
13785
18.4M
    if (ret < 0) {
13786
        /* NOP. */
13787
18.4M
    } else if (ret == 1) {
13788
9.33M
        if (toBool)
13789
0
      goto return_1;
13790
9.33M
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13791
9.33M
            < 0) {
13792
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13793
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13794
0
        }
13795
9.33M
    }
13796
18.4M
    if ((cur->children == NULL) || (depth >= max_depth)) {
13797
13.3M
        ret = xmlStreamPop(patstream);
13798
13.3M
        while (cur->next != NULL) {
13799
11.0M
      cur = cur->next;
13800
11.0M
      if ((cur->type != XML_ENTITY_DECL) &&
13801
11.0M
          (cur->type != XML_DTD_NODE))
13802
11.0M
          goto next_node;
13803
11.0M
        }
13804
13.3M
    }
13805
10.3M
      default:
13806
10.3M
    break;
13807
30.6M
  }
13808
13809
21.3M
scan_children:
13810
21.3M
  if (cur->type == XML_NAMESPACE_DECL) break;
13811
21.3M
  if ((cur->children != NULL) && (depth < max_depth)) {
13812
      /*
13813
       * Do not descend on entities declarations
13814
       */
13815
6.43M
      if (cur->children->type != XML_ENTITY_DECL) {
13816
6.43M
    cur = cur->children;
13817
6.43M
    depth++;
13818
    /*
13819
     * Skip DTDs
13820
     */
13821
6.43M
    if (cur->type != XML_DTD_NODE)
13822
6.43M
        continue;
13823
6.43M
      }
13824
6.43M
  }
13825
13826
14.8M
  if (cur == limit)
13827
413k
      break;
13828
13829
14.4M
  while (cur->next != NULL) {
13830
8.44M
      cur = cur->next;
13831
8.44M
      if ((cur->type != XML_ENTITY_DECL) &&
13832
8.44M
    (cur->type != XML_DTD_NODE))
13833
8.44M
    goto next_node;
13834
8.44M
  }
13835
13836
6.43M
  do {
13837
6.43M
      cur = cur->parent;
13838
6.43M
      depth--;
13839
6.43M
      if ((cur == NULL) || (cur == limit) ||
13840
6.43M
                (cur->type == XML_DOCUMENT_NODE))
13841
1.30M
          goto done;
13842
5.13M
      if (cur->type == XML_ELEMENT_NODE) {
13843
5.13M
    ret = xmlStreamPop(patstream);
13844
5.13M
      } else if ((eval_all_nodes) &&
13845
0
    ((cur->type == XML_TEXT_NODE) ||
13846
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13847
0
     (cur->type == XML_COMMENT_NODE) ||
13848
0
     (cur->type == XML_PI_NODE)))
13849
0
      {
13850
0
    ret = xmlStreamPop(patstream);
13851
0
      }
13852
5.13M
      if (cur->next != NULL) {
13853
4.73M
    cur = cur->next;
13854
4.73M
    break;
13855
4.73M
      }
13856
5.13M
  } while (cur != NULL);
13857
13858
11.1M
    } while ((cur != NULL) && (depth >= 0));
13859
13860
1.71M
done:
13861
13862
1.71M
    if (patstream)
13863
1.71M
  xmlFreeStreamCtxt(patstream);
13864
1.71M
    return(0);
13865
13866
0
return_1:
13867
0
    if (patstream)
13868
0
  xmlFreeStreamCtxt(patstream);
13869
0
    return(1);
13870
19.4M
}
13871
#endif /* XPATH_STREAMING */
13872
13873
/**
13874
 * xmlXPathRunEval:
13875
 * @ctxt:  the XPath parser context with the compiled expression
13876
 * @toBool:  evaluate to a boolean result
13877
 *
13878
 * Evaluate the Precompiled XPath expression in the given context.
13879
 */
13880
static int
13881
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13882
12.5M
{
13883
12.5M
    xmlXPathCompExprPtr comp;
13884
12.5M
    int oldDepth;
13885
13886
12.5M
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13887
0
  return(-1);
13888
13889
12.5M
    if (ctxt->valueTab == NULL) {
13890
  /* Allocate the value stack */
13891
721k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13892
721k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13893
721k
  if (ctxt->valueTab == NULL) {
13894
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13895
0
      return(-1);
13896
0
  }
13897
721k
  ctxt->valueNr = 0;
13898
721k
  ctxt->valueMax = 10;
13899
721k
  ctxt->value = NULL;
13900
721k
        ctxt->valueFrame = 0;
13901
721k
    }
13902
12.5M
#ifdef XPATH_STREAMING
13903
12.5M
    if (ctxt->comp->stream) {
13904
2.27M
  int res;
13905
13906
2.27M
  if (toBool) {
13907
      /*
13908
      * Evaluation to boolean result.
13909
      */
13910
0
      res = xmlXPathRunStreamEval(ctxt->context,
13911
0
    ctxt->comp->stream, NULL, 1);
13912
0
      if (res != -1)
13913
0
    return(res);
13914
2.27M
  } else {
13915
2.27M
      xmlXPathObjectPtr resObj = NULL;
13916
13917
      /*
13918
      * Evaluation to a sequence.
13919
      */
13920
2.27M
      res = xmlXPathRunStreamEval(ctxt->context,
13921
2.27M
    ctxt->comp->stream, &resObj, 0);
13922
13923
2.27M
      if ((res != -1) && (resObj != NULL)) {
13924
2.27M
    valuePush(ctxt, resObj);
13925
2.27M
    return(0);
13926
2.27M
      }
13927
753
      if (resObj != NULL)
13928
753
    xmlXPathReleaseObject(ctxt->context, resObj);
13929
753
  }
13930
  /*
13931
  * QUESTION TODO: This falls back to normal XPath evaluation
13932
  * if res == -1. Is this intended?
13933
  */
13934
2.27M
    }
13935
10.2M
#endif
13936
10.2M
    comp = ctxt->comp;
13937
10.2M
    if (comp->last < 0) {
13938
753
  xmlGenericError(xmlGenericErrorContext,
13939
753
      "xmlXPathRunEval: last is less than zero\n");
13940
753
  return(-1);
13941
753
    }
13942
10.2M
    oldDepth = ctxt->context->depth;
13943
10.2M
    if (toBool)
13944
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13945
0
      &comp->steps[comp->last], 0));
13946
10.2M
    else
13947
10.2M
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13948
10.2M
    ctxt->context->depth = oldDepth;
13949
13950
10.2M
    return(0);
13951
10.2M
}
13952
13953
/************************************************************************
13954
 *                  *
13955
 *      Public interfaces       *
13956
 *                  *
13957
 ************************************************************************/
13958
13959
/**
13960
 * xmlXPathEvalPredicate:
13961
 * @ctxt:  the XPath context
13962
 * @res:  the Predicate Expression evaluation result
13963
 *
13964
 * Evaluate a predicate result for the current node.
13965
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13966
 * the result to a boolean. If the result is a number, the result will
13967
 * be converted to true if the number is equal to the position of the
13968
 * context node in the context node list (as returned by the position
13969
 * function) and will be converted to false otherwise; if the result
13970
 * is not a number, then the result will be converted as if by a call
13971
 * to the boolean function.
13972
 *
13973
 * Returns 1 if predicate is true, 0 otherwise
13974
 */
13975
int
13976
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13977
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13978
0
    switch (res->type) {
13979
0
        case XPATH_BOOLEAN:
13980
0
      return(res->boolval);
13981
0
        case XPATH_NUMBER:
13982
0
      return(res->floatval == ctxt->proximityPosition);
13983
0
        case XPATH_NODESET:
13984
0
        case XPATH_XSLT_TREE:
13985
0
      if (res->nodesetval == NULL)
13986
0
    return(0);
13987
0
      return(res->nodesetval->nodeNr != 0);
13988
0
        case XPATH_STRING:
13989
0
      return((res->stringval != NULL) &&
13990
0
             (xmlStrlen(res->stringval) != 0));
13991
0
        default:
13992
0
      STRANGE
13993
0
    }
13994
0
    return(0);
13995
0
}
13996
13997
/**
13998
 * xmlXPathEvaluatePredicateResult:
13999
 * @ctxt:  the XPath Parser context
14000
 * @res:  the Predicate Expression evaluation result
14001
 *
14002
 * Evaluate a predicate result for the current node.
14003
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14004
 * the result to a boolean. If the result is a number, the result will
14005
 * be converted to true if the number is equal to the position of the
14006
 * context node in the context node list (as returned by the position
14007
 * function) and will be converted to false otherwise; if the result
14008
 * is not a number, then the result will be converted as if by a call
14009
 * to the boolean function.
14010
 *
14011
 * Returns 1 if predicate is true, 0 otherwise
14012
 */
14013
int
14014
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14015
24.1M
                                xmlXPathObjectPtr res) {
14016
24.1M
    if ((ctxt == NULL) || (res == NULL)) return(0);
14017
24.1M
    switch (res->type) {
14018
0
        case XPATH_BOOLEAN:
14019
0
      return(res->boolval);
14020
10.6M
        case XPATH_NUMBER:
14021
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14022
      return((res->floatval == ctxt->context->proximityPosition) &&
14023
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14024
#else
14025
10.6M
      return(res->floatval == ctxt->context->proximityPosition);
14026
0
#endif
14027
9.30M
        case XPATH_NODESET:
14028
9.30M
        case XPATH_XSLT_TREE:
14029
9.30M
      if (res->nodesetval == NULL)
14030
893k
    return(0);
14031
8.41M
      return(res->nodesetval->nodeNr != 0);
14032
4.26M
        case XPATH_STRING:
14033
4.26M
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14034
#ifdef LIBXML_XPTR_LOCS_ENABLED
14035
  case XPATH_LOCATIONSET:{
14036
      xmlLocationSetPtr ptr = res->user;
14037
      if (ptr == NULL)
14038
          return(0);
14039
      return (ptr->locNr != 0);
14040
      }
14041
#endif
14042
611
        default:
14043
611
      STRANGE
14044
24.1M
    }
14045
611
    return(0);
14046
24.1M
}
14047
14048
#ifdef XPATH_STREAMING
14049
/**
14050
 * xmlXPathTryStreamCompile:
14051
 * @ctxt: an XPath context
14052
 * @str:  the XPath expression
14053
 *
14054
 * Try to compile the XPath expression as a streamable subset.
14055
 *
14056
 * Returns the compiled expression or NULL if failed to compile.
14057
 */
14058
static xmlXPathCompExprPtr
14059
10.1M
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14060
    /*
14061
     * Optimization: use streaming patterns when the XPath expression can
14062
     * be compiled to a stream lookup
14063
     */
14064
10.1M
    xmlPatternPtr stream;
14065
10.1M
    xmlXPathCompExprPtr comp;
14066
10.1M
    xmlDictPtr dict = NULL;
14067
10.1M
    const xmlChar **namespaces = NULL;
14068
10.1M
    xmlNsPtr ns;
14069
10.1M
    int i, j;
14070
14071
10.1M
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14072
10.1M
        (!xmlStrchr(str, '@'))) {
14073
2.85M
  const xmlChar *tmp;
14074
14075
  /*
14076
   * We don't try to handle expressions using the verbose axis
14077
   * specifiers ("::"), just the simplified form at this point.
14078
   * Additionally, if there is no list of namespaces available and
14079
   *  there's a ":" in the expression, indicating a prefixed QName,
14080
   *  then we won't try to compile either. xmlPatterncompile() needs
14081
   *  to have a list of namespaces at compilation time in order to
14082
   *  compile prefixed name tests.
14083
   */
14084
2.85M
  tmp = xmlStrchr(str, ':');
14085
2.85M
  if ((tmp != NULL) &&
14086
2.85M
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14087
355k
      return(NULL);
14088
14089
2.50M
  if (ctxt != NULL) {
14090
2.50M
      dict = ctxt->dict;
14091
2.50M
      if (ctxt->nsNr > 0) {
14092
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14093
0
    if (namespaces == NULL) {
14094
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14095
0
        return(NULL);
14096
0
    }
14097
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14098
0
        ns = ctxt->namespaces[j];
14099
0
        namespaces[i++] = ns->href;
14100
0
        namespaces[i++] = ns->prefix;
14101
0
    }
14102
0
    namespaces[i++] = NULL;
14103
0
    namespaces[i] = NULL;
14104
0
      }
14105
2.50M
  }
14106
14107
2.50M
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14108
2.50M
  if (namespaces != NULL) {
14109
0
      xmlFree((xmlChar **)namespaces);
14110
0
  }
14111
2.50M
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14112
1.03M
      comp = xmlXPathNewCompExpr();
14113
1.03M
      if (comp == NULL) {
14114
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14115
0
    return(NULL);
14116
0
      }
14117
1.03M
      comp->stream = stream;
14118
1.03M
      comp->dict = dict;
14119
1.03M
      if (comp->dict)
14120
0
    xmlDictReference(comp->dict);
14121
1.03M
      return(comp);
14122
1.03M
  }
14123
1.46M
  xmlFreePattern(stream);
14124
1.46M
    }
14125
8.79M
    return(NULL);
14126
10.1M
}
14127
#endif /* XPATH_STREAMING */
14128
14129
static void
14130
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14131
                           xmlXPathStepOpPtr op)
14132
60.8M
{
14133
60.8M
    xmlXPathCompExprPtr comp = pctxt->comp;
14134
60.8M
    xmlXPathContextPtr ctxt;
14135
14136
    /*
14137
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14138
    * internal representation.
14139
    */
14140
14141
60.8M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14142
60.8M
        (op->ch1 != -1) &&
14143
60.8M
        (op->ch2 == -1 /* no predicate */))
14144
11.0M
    {
14145
11.0M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14146
14147
11.0M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14148
11.0M
            ((xmlXPathAxisVal) prevop->value ==
14149
1.96M
                AXIS_DESCENDANT_OR_SELF) &&
14150
11.0M
            (prevop->ch2 == -1) &&
14151
11.0M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14152
11.0M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14153
780k
        {
14154
            /*
14155
            * This is a "descendant-or-self::node()" without predicates.
14156
            * Try to eliminate it.
14157
            */
14158
14159
780k
            switch ((xmlXPathAxisVal) op->value) {
14160
455k
                case AXIS_CHILD:
14161
463k
                case AXIS_DESCENDANT:
14162
                    /*
14163
                    * Convert "descendant-or-self::node()/child::" or
14164
                    * "descendant-or-self::node()/descendant::" to
14165
                    * "descendant::"
14166
                    */
14167
463k
                    op->ch1   = prevop->ch1;
14168
463k
                    op->value = AXIS_DESCENDANT;
14169
463k
                    break;
14170
7.63k
                case AXIS_SELF:
14171
36.0k
                case AXIS_DESCENDANT_OR_SELF:
14172
                    /*
14173
                    * Convert "descendant-or-self::node()/self::" or
14174
                    * "descendant-or-self::node()/descendant-or-self::" to
14175
                    * to "descendant-or-self::"
14176
                    */
14177
36.0k
                    op->ch1   = prevop->ch1;
14178
36.0k
                    op->value = AXIS_DESCENDANT_OR_SELF;
14179
36.0k
                    break;
14180
281k
                default:
14181
281k
                    break;
14182
780k
            }
14183
780k
  }
14184
11.0M
    }
14185
14186
    /* OP_VALUE has invalid ch1. */
14187
60.8M
    if (op->op == XPATH_OP_VALUE)
14188
4.70M
        return;
14189
14190
    /* Recurse */
14191
56.1M
    ctxt = pctxt->context;
14192
56.1M
    if (ctxt != NULL) {
14193
56.1M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14194
0
            return;
14195
56.1M
        ctxt->depth += 1;
14196
56.1M
    }
14197
56.1M
    if (op->ch1 != -1)
14198
37.6M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14199
56.1M
    if (op->ch2 != -1)
14200
17.4M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14201
56.1M
    if (ctxt != NULL)
14202
56.1M
        ctxt->depth -= 1;
14203
56.1M
}
14204
14205
/**
14206
 * xmlXPathCtxtCompile:
14207
 * @ctxt: an XPath context
14208
 * @str:  the XPath expression
14209
 *
14210
 * Compile an XPath expression
14211
 *
14212
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14213
 *         the caller has to free the object.
14214
 */
14215
xmlXPathCompExprPtr
14216
9.18M
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14217
9.18M
    xmlXPathParserContextPtr pctxt;
14218
9.18M
    xmlXPathCompExprPtr comp;
14219
9.18M
    int oldDepth = 0;
14220
14221
9.18M
#ifdef XPATH_STREAMING
14222
9.18M
    comp = xmlXPathTryStreamCompile(ctxt, str);
14223
9.18M
    if (comp != NULL)
14224
871k
        return(comp);
14225
8.31M
#endif
14226
14227
8.31M
    xmlInitParser();
14228
14229
8.31M
    pctxt = xmlXPathNewParserContext(str, ctxt);
14230
8.31M
    if (pctxt == NULL)
14231
0
        return NULL;
14232
8.31M
    if (ctxt != NULL)
14233
8.31M
        oldDepth = ctxt->depth;
14234
8.31M
    xmlXPathCompileExpr(pctxt, 1);
14235
8.31M
    if (ctxt != NULL)
14236
8.31M
        ctxt->depth = oldDepth;
14237
14238
8.31M
    if( pctxt->error != XPATH_EXPRESSION_OK )
14239
1.99M
    {
14240
1.99M
        xmlXPathFreeParserContext(pctxt);
14241
1.99M
        return(NULL);
14242
1.99M
    }
14243
14244
6.31M
    if (*pctxt->cur != 0) {
14245
  /*
14246
   * aleksey: in some cases this line prints *second* error message
14247
   * (see bug #78858) and probably this should be fixed.
14248
   * However, we are not sure that all error messages are printed
14249
   * out in other places. It's not critical so we leave it as-is for now
14250
   */
14251
962k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14252
962k
  comp = NULL;
14253
5.35M
    } else {
14254
5.35M
  comp = pctxt->comp;
14255
5.35M
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14256
5.13M
            if (ctxt != NULL)
14257
5.13M
                oldDepth = ctxt->depth;
14258
5.13M
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14259
5.13M
            if (ctxt != NULL)
14260
5.13M
                ctxt->depth = oldDepth;
14261
5.13M
  }
14262
5.35M
  pctxt->comp = NULL;
14263
5.35M
    }
14264
6.31M
    xmlXPathFreeParserContext(pctxt);
14265
14266
6.31M
    if (comp != NULL) {
14267
5.35M
  comp->expr = xmlStrdup(str);
14268
#ifdef DEBUG_EVAL_COUNTS
14269
  comp->string = xmlStrdup(str);
14270
  comp->nb = 0;
14271
#endif
14272
5.35M
    }
14273
6.31M
    return(comp);
14274
8.31M
}
14275
14276
/**
14277
 * xmlXPathCompile:
14278
 * @str:  the XPath expression
14279
 *
14280
 * Compile an XPath expression
14281
 *
14282
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14283
 *         the caller has to free the object.
14284
 */
14285
xmlXPathCompExprPtr
14286
0
xmlXPathCompile(const xmlChar *str) {
14287
0
    return(xmlXPathCtxtCompile(NULL, str));
14288
0
}
14289
14290
/**
14291
 * xmlXPathCompiledEvalInternal:
14292
 * @comp:  the compiled XPath expression
14293
 * @ctxt:  the XPath context
14294
 * @resObj: the resulting XPath object or NULL
14295
 * @toBool: 1 if only a boolean result is requested
14296
 *
14297
 * Evaluate the Precompiled XPath expression in the given context.
14298
 * The caller has to free @resObj.
14299
 *
14300
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14301
 *         the caller has to free the object.
14302
 */
14303
static int
14304
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14305
           xmlXPathContextPtr ctxt,
14306
           xmlXPathObjectPtr *resObjPtr,
14307
           int toBool)
14308
11.8M
{
14309
11.8M
    xmlXPathParserContextPtr pctxt;
14310
11.8M
    xmlXPathObjectPtr resObj;
14311
#ifndef LIBXML_THREAD_ENABLED
14312
    static int reentance = 0;
14313
#endif
14314
11.8M
    int res;
14315
14316
11.8M
    CHECK_CTXT_NEG(ctxt)
14317
14318
11.8M
    if (comp == NULL)
14319
0
  return(-1);
14320
11.8M
    xmlInitParser();
14321
14322
#ifndef LIBXML_THREAD_ENABLED
14323
    reentance++;
14324
    if (reentance > 1)
14325
  xmlXPathDisableOptimizer = 1;
14326
#endif
14327
14328
#ifdef DEBUG_EVAL_COUNTS
14329
    comp->nb++;
14330
    if ((comp->string != NULL) && (comp->nb > 100)) {
14331
  fprintf(stderr, "100 x %s\n", comp->string);
14332
  comp->nb = 0;
14333
    }
14334
#endif
14335
11.8M
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14336
11.8M
    res = xmlXPathRunEval(pctxt, toBool);
14337
14338
11.8M
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14339
4.08M
        resObj = NULL;
14340
7.72M
    } else {
14341
7.72M
        resObj = valuePop(pctxt);
14342
7.72M
        if (resObj == NULL) {
14343
742
            if (!toBool)
14344
742
                xmlGenericError(xmlGenericErrorContext,
14345
742
                    "xmlXPathCompiledEval: No result on the stack.\n");
14346
7.72M
        } else if (pctxt->valueNr > 0) {
14347
0
            xmlGenericError(xmlGenericErrorContext,
14348
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14349
0
                pctxt->valueNr);
14350
0
        }
14351
7.72M
    }
14352
14353
11.8M
    if (resObjPtr)
14354
11.8M
        *resObjPtr = resObj;
14355
0
    else
14356
0
        xmlXPathReleaseObject(ctxt, resObj);
14357
14358
11.8M
    pctxt->comp = NULL;
14359
11.8M
    xmlXPathFreeParserContext(pctxt);
14360
#ifndef LIBXML_THREAD_ENABLED
14361
    reentance--;
14362
#endif
14363
14364
11.8M
    return(res);
14365
11.8M
}
14366
14367
/**
14368
 * xmlXPathCompiledEval:
14369
 * @comp:  the compiled XPath expression
14370
 * @ctx:  the XPath context
14371
 *
14372
 * Evaluate the Precompiled XPath expression in the given context.
14373
 *
14374
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14375
 *         the caller has to free the object.
14376
 */
14377
xmlXPathObjectPtr
14378
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14379
11.8M
{
14380
11.8M
    xmlXPathObjectPtr res = NULL;
14381
14382
11.8M
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14383
11.8M
    return(res);
14384
11.8M
}
14385
14386
/**
14387
 * xmlXPathCompiledEvalToBoolean:
14388
 * @comp:  the compiled XPath expression
14389
 * @ctxt:  the XPath context
14390
 *
14391
 * Applies the XPath boolean() function on the result of the given
14392
 * compiled expression.
14393
 *
14394
 * Returns 1 if the expression evaluated to true, 0 if to false and
14395
 *         -1 in API and internal errors.
14396
 */
14397
int
14398
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14399
            xmlXPathContextPtr ctxt)
14400
0
{
14401
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14402
0
}
14403
14404
/**
14405
 * xmlXPathEvalExpr:
14406
 * @ctxt:  the XPath Parser context
14407
 *
14408
 * Parse and evaluate an XPath expression in the given context,
14409
 * then push the result on the context stack
14410
 */
14411
void
14412
1.00M
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14413
1.00M
#ifdef XPATH_STREAMING
14414
1.00M
    xmlXPathCompExprPtr comp;
14415
1.00M
#endif
14416
1.00M
    int oldDepth = 0;
14417
14418
1.00M
    if (ctxt == NULL) return;
14419
14420
1.00M
#ifdef XPATH_STREAMING
14421
1.00M
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422
1.00M
    if (comp != NULL) {
14423
162k
        if (ctxt->comp != NULL)
14424
162k
      xmlXPathFreeCompExpr(ctxt->comp);
14425
162k
        ctxt->comp = comp;
14426
162k
    } else
14427
837k
#endif
14428
837k
    {
14429
837k
        if (ctxt->context != NULL)
14430
837k
            oldDepth = ctxt->context->depth;
14431
837k
  xmlXPathCompileExpr(ctxt, 1);
14432
837k
        if (ctxt->context != NULL)
14433
837k
            ctxt->context->depth = oldDepth;
14434
837k
        CHECK_ERROR;
14435
14436
        /* Check for trailing characters. */
14437
639k
        if (*ctxt->cur != 0)
14438
560k
            XP_ERROR(XPATH_EXPR_ERROR);
14439
14440
560k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441
554k
            if (ctxt->context != NULL)
14442
554k
                oldDepth = ctxt->context->depth;
14443
554k
      xmlXPathOptimizeExpression(ctxt,
14444
554k
    &ctxt->comp->steps[ctxt->comp->last]);
14445
554k
            if (ctxt->context != NULL)
14446
554k
                ctxt->context->depth = oldDepth;
14447
554k
        }
14448
560k
    }
14449
14450
723k
    xmlXPathRunEval(ctxt, 0);
14451
723k
}
14452
14453
/**
14454
 * xmlXPathEval:
14455
 * @str:  the XPath expression
14456
 * @ctx:  the XPath context
14457
 *
14458
 * Evaluate the XPath Location Path in the given context.
14459
 *
14460
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14461
 *         the caller has to free the object.
14462
 */
14463
xmlXPathObjectPtr
14464
998k
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14465
998k
    xmlXPathParserContextPtr ctxt;
14466
998k
    xmlXPathObjectPtr res;
14467
14468
998k
    CHECK_CTXT(ctx)
14469
14470
998k
    xmlInitParser();
14471
14472
998k
    ctxt = xmlXPathNewParserContext(str, ctx);
14473
998k
    if (ctxt == NULL)
14474
0
        return NULL;
14475
998k
    xmlXPathEvalExpr(ctxt);
14476
14477
998k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14478
589k
  res = NULL;
14479
589k
    } else {
14480
408k
  res = valuePop(ctxt);
14481
408k
        if (res == NULL) {
14482
11
            xmlGenericError(xmlGenericErrorContext,
14483
11
                "xmlXPathCompiledEval: No result on the stack.\n");
14484
408k
        } else if (ctxt->valueNr > 0) {
14485
0
            xmlGenericError(xmlGenericErrorContext,
14486
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14487
0
                ctxt->valueNr);
14488
0
        }
14489
408k
    }
14490
14491
998k
    xmlXPathFreeParserContext(ctxt);
14492
998k
    return(res);
14493
998k
}
14494
14495
/**
14496
 * xmlXPathSetContextNode:
14497
 * @node: the node to to use as the context node
14498
 * @ctx:  the XPath context
14499
 *
14500
 * Sets 'node' as the context node. The node must be in the same
14501
 * document as that associated with the context.
14502
 *
14503
 * Returns -1 in case of error or 0 if successful
14504
 */
14505
int
14506
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14507
0
    if ((node == NULL) || (ctx == NULL))
14508
0
        return(-1);
14509
14510
0
    if (node->doc == ctx->doc) {
14511
0
        ctx->node = node;
14512
0
  return(0);
14513
0
    }
14514
0
    return(-1);
14515
0
}
14516
14517
/**
14518
 * xmlXPathNodeEval:
14519
 * @node: the node to to use as the context node
14520
 * @str:  the XPath expression
14521
 * @ctx:  the XPath context
14522
 *
14523
 * Evaluate the XPath Location Path in the given context. The node 'node'
14524
 * is set as the context node. The context node is not restored.
14525
 *
14526
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14527
 *         the caller has to free the object.
14528
 */
14529
xmlXPathObjectPtr
14530
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14531
0
    if (str == NULL)
14532
0
        return(NULL);
14533
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14534
0
        return(NULL);
14535
0
    return(xmlXPathEval(str, ctx));
14536
0
}
14537
14538
/**
14539
 * xmlXPathEvalExpression:
14540
 * @str:  the XPath expression
14541
 * @ctxt:  the XPath context
14542
 *
14543
 * Alias for xmlXPathEval().
14544
 *
14545
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14546
 *         the caller has to free the object.
14547
 */
14548
xmlXPathObjectPtr
14549
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14550
0
    return(xmlXPathEval(str, ctxt));
14551
0
}
14552
14553
/************************************************************************
14554
 *                  *
14555
 *  Extra functions not pertaining to the XPath spec    *
14556
 *                  *
14557
 ************************************************************************/
14558
/**
14559
 * xmlXPathEscapeUriFunction:
14560
 * @ctxt:  the XPath Parser context
14561
 * @nargs:  the number of arguments
14562
 *
14563
 * Implement the escape-uri() XPath function
14564
 *    string escape-uri(string $str, bool $escape-reserved)
14565
 *
14566
 * This function applies the URI escaping rules defined in section 2 of [RFC
14567
 * 2396] to the string supplied as $uri-part, which typically represents all
14568
 * or part of a URI. The effect of the function is to replace any special
14569
 * character in the string by an escape sequence of the form %xx%yy...,
14570
 * where xxyy... is the hexadecimal representation of the octets used to
14571
 * represent the character in UTF-8.
14572
 *
14573
 * The set of characters that are escaped depends on the setting of the
14574
 * boolean argument $escape-reserved.
14575
 *
14576
 * If $escape-reserved is true, all characters are escaped other than lower
14577
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14578
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14579
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14580
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14581
 * A-F).
14582
 *
14583
 * If $escape-reserved is false, the behavior differs in that characters
14584
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14585
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14586
 *
14587
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14588
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14589
 * compared using string comparison functions, this function must always use
14590
 * the upper-case letters A-F.
14591
 *
14592
 * Generally, $escape-reserved should be set to true when escaping a string
14593
 * that is to form a single part of a URI, and to false when escaping an
14594
 * entire URI or URI reference.
14595
 *
14596
 * In the case of non-ascii characters, the string is encoded according to
14597
 * utf-8 and then converted according to RFC 2396.
14598
 *
14599
 * Examples
14600
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14601
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14602
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14603
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14604
 *
14605
 */
14606
static void
14607
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14608
0
    xmlXPathObjectPtr str;
14609
0
    int escape_reserved;
14610
0
    xmlBufPtr target;
14611
0
    xmlChar *cptr;
14612
0
    xmlChar escape[4];
14613
14614
0
    CHECK_ARITY(2);
14615
14616
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14617
14618
0
    CAST_TO_STRING;
14619
0
    str = valuePop(ctxt);
14620
14621
0
    target = xmlBufCreate();
14622
14623
0
    escape[0] = '%';
14624
0
    escape[3] = 0;
14625
14626
0
    if (target) {
14627
0
  for (cptr = str->stringval; *cptr; cptr++) {
14628
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14629
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14630
0
    (*cptr >= '0' && *cptr <= '9') ||
14631
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14632
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14633
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14634
0
    (*cptr == '%' &&
14635
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14636
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14637
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14638
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14639
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14640
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14641
0
    (!escape_reserved &&
14642
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14643
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14644
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14645
0
      *cptr == ','))) {
14646
0
    xmlBufAdd(target, cptr, 1);
14647
0
      } else {
14648
0
    if ((*cptr >> 4) < 10)
14649
0
        escape[1] = '0' + (*cptr >> 4);
14650
0
    else
14651
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14652
0
    if ((*cptr & 0xF) < 10)
14653
0
        escape[2] = '0' + (*cptr & 0xF);
14654
0
    else
14655
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14656
14657
0
    xmlBufAdd(target, &escape[0], 3);
14658
0
      }
14659
0
  }
14660
0
    }
14661
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14662
0
  xmlBufContent(target)));
14663
0
    xmlBufFree(target);
14664
0
    xmlXPathReleaseObject(ctxt->context, str);
14665
0
}
14666
14667
/**
14668
 * xmlXPathRegisterAllFunctions:
14669
 * @ctxt:  the XPath context
14670
 *
14671
 * Registers all default XPath functions in this context
14672
 */
14673
void
14674
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14675
70.3k
{
14676
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14677
70.3k
                         xmlXPathBooleanFunction);
14678
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14679
70.3k
                         xmlXPathCeilingFunction);
14680
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14681
70.3k
                         xmlXPathCountFunction);
14682
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14683
70.3k
                         xmlXPathConcatFunction);
14684
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14685
70.3k
                         xmlXPathContainsFunction);
14686
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14687
70.3k
                         xmlXPathIdFunction);
14688
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14689
70.3k
                         xmlXPathFalseFunction);
14690
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14691
70.3k
                         xmlXPathFloorFunction);
14692
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14693
70.3k
                         xmlXPathLastFunction);
14694
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14695
70.3k
                         xmlXPathLangFunction);
14696
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14697
70.3k
                         xmlXPathLocalNameFunction);
14698
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14699
70.3k
                         xmlXPathNotFunction);
14700
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14701
70.3k
                         xmlXPathNameFunction);
14702
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14703
70.3k
                         xmlXPathNamespaceURIFunction);
14704
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14705
70.3k
                         xmlXPathNormalizeFunction);
14706
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14707
70.3k
                         xmlXPathNumberFunction);
14708
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14709
70.3k
                         xmlXPathPositionFunction);
14710
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14711
70.3k
                         xmlXPathRoundFunction);
14712
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14713
70.3k
                         xmlXPathStringFunction);
14714
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14715
70.3k
                         xmlXPathStringLengthFunction);
14716
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14717
70.3k
                         xmlXPathStartsWithFunction);
14718
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14719
70.3k
                         xmlXPathSubstringFunction);
14720
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14721
70.3k
                         xmlXPathSubstringBeforeFunction);
14722
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14723
70.3k
                         xmlXPathSubstringAfterFunction);
14724
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14725
70.3k
                         xmlXPathSumFunction);
14726
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14727
70.3k
                         xmlXPathTrueFunction);
14728
70.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14729
70.3k
                         xmlXPathTranslateFunction);
14730
14731
70.3k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14732
70.3k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14733
70.3k
                         xmlXPathEscapeUriFunction);
14734
70.3k
}
14735
14736
#endif /* LIBXML_XPATH_ENABLED */