Coverage Report

Created: 2023-12-14 14:10

/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
93
    xmlGenericError(xmlGenericErrorContext,       \
62
93
      "Unimplemented block at %s:%d\n",       \
63
93
            __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
213k
#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
5.35k
#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
9.78M
#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
214M
#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
146M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
162
146M
    int depth1, depth2;
163
146M
    int misc = 0, precedence1 = 0, precedence2 = 0;
164
146M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
165
146M
    xmlNodePtr cur, root;
166
146M
    ptrdiff_t l1, l2;
167
168
146M
    if ((node1 == NULL) || (node2 == NULL))
169
0
  return(-2);
170
171
146M
    if (node1 == node2)
172
0
  return(0);
173
174
    /*
175
     * a couple of optimizations which will avoid computations in most cases
176
     */
177
146M
    switch (node1->type) {
178
100M
  case XML_ELEMENT_NODE:
179
100M
      if (node2->type == XML_ELEMENT_NODE) {
180
74.1M
    if ((0 > (ptrdiff_t) node1->content) &&
181
74.1M
        (0 > (ptrdiff_t) node2->content) &&
182
74.1M
        (node1->doc == node2->doc))
183
6.33M
    {
184
6.33M
        l1 = -((ptrdiff_t) node1->content);
185
6.33M
        l2 = -((ptrdiff_t) node2->content);
186
6.33M
        if (l1 < l2)
187
5.18M
      return(1);
188
1.15M
        if (l1 > l2)
189
1.15M
      return(-1);
190
1.15M
    } else
191
67.7M
        goto turtle_comparison;
192
74.1M
      }
193
26.4M
      break;
194
26.4M
  case XML_ATTRIBUTE_NODE:
195
325k
      precedence1 = 1; /* element is owner */
196
325k
      miscNode1 = node1;
197
325k
      node1 = node1->parent;
198
325k
      misc = 1;
199
325k
      break;
200
40.7M
  case XML_TEXT_NODE:
201
41.4M
  case XML_CDATA_SECTION_NODE:
202
42.5M
  case XML_COMMENT_NODE:
203
43.4M
  case XML_PI_NODE: {
204
43.4M
      miscNode1 = node1;
205
      /*
206
      * Find nearest element node.
207
      */
208
43.4M
      if (node1->prev != NULL) {
209
14.8M
    do {
210
14.8M
        node1 = node1->prev;
211
14.8M
        if (node1->type == XML_ELEMENT_NODE) {
212
10.2M
      precedence1 = 3; /* element in prev-sibl axis */
213
10.2M
      break;
214
10.2M
        }
215
4.62M
        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
4.62M
    } while (1);
225
33.2M
      } else {
226
33.2M
    precedence1 = 2; /* element is parent */
227
33.2M
    node1 = node1->parent;
228
33.2M
      }
229
43.4M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
230
43.4M
    (0 <= (ptrdiff_t) node1->content)) {
231
    /*
232
    * Fallback for whatever case.
233
    */
234
27.1M
    node1 = miscNode1;
235
27.1M
    precedence1 = 0;
236
27.1M
      } else
237
16.3M
    misc = 1;
238
43.4M
  }
239
0
      break;
240
2.17M
  case XML_NAMESPACE_DECL:
241
      /*
242
      * TODO: why do we return 1 for namespace nodes?
243
      */
244
2.17M
      return(1);
245
398k
  default:
246
398k
      break;
247
146M
    }
248
70.6M
    switch (node2->type) {
249
21.9M
  case XML_ELEMENT_NODE:
250
21.9M
      break;
251
333k
  case XML_ATTRIBUTE_NODE:
252
333k
      precedence2 = 1; /* element is owner */
253
333k
      miscNode2 = node2;
254
333k
      node2 = node2->parent;
255
333k
      misc = 1;
256
333k
      break;
257
44.9M
  case XML_TEXT_NODE:
258
45.5M
  case XML_CDATA_SECTION_NODE:
259
46.7M
  case XML_COMMENT_NODE:
260
47.6M
  case XML_PI_NODE: {
261
47.6M
      miscNode2 = node2;
262
47.6M
      if (node2->prev != NULL) {
263
15.5M
    do {
264
15.5M
        node2 = node2->prev;
265
15.5M
        if (node2->type == XML_ELEMENT_NODE) {
266
10.1M
      precedence2 = 3; /* element in prev-sibl axis */
267
10.1M
      break;
268
10.1M
        }
269
5.45M
        if (node2->prev == NULL) {
270
0
      precedence2 = 2; /* element is parent */
271
0
      node2 = node2->parent;
272
0
      break;
273
0
        }
274
5.45M
    } while (1);
275
37.5M
      } else {
276
37.5M
    precedence2 = 2; /* element is parent */
277
37.5M
    node2 = node2->parent;
278
37.5M
      }
279
47.6M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
280
47.6M
    (0 <= (ptrdiff_t) node2->content))
281
31.8M
      {
282
31.8M
    node2 = miscNode2;
283
31.8M
    precedence2 = 0;
284
31.8M
      } else
285
15.8M
    misc = 1;
286
47.6M
  }
287
0
      break;
288
95.7k
  case XML_NAMESPACE_DECL:
289
95.7k
      return(1);
290
620k
  default:
291
620k
      break;
292
70.6M
    }
293
70.6M
    if (misc) {
294
23.5M
  if (node1 == node2) {
295
13.0M
      if (precedence1 == precedence2) {
296
    /*
297
    * The ugly case; but normally there aren't many
298
    * adjacent non-element nodes around.
299
    */
300
3.16M
    cur = miscNode2->prev;
301
3.26M
    while (cur != NULL) {
302
3.25M
        if (cur == miscNode1)
303
3.06M
      return(1);
304
196k
        if (cur->type == XML_ELEMENT_NODE)
305
98.7k
      return(-1);
306
97.5k
        cur = cur->prev;
307
97.5k
    }
308
3.85k
    return (-1);
309
9.85M
      } 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.85M
    if (precedence1 < precedence2)
316
9.38M
        return(1);
317
471k
    else
318
471k
        return(-1);
319
9.85M
      }
320
13.0M
  }
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
10.5M
  if ((precedence2 == 3) && (precedence1 > 1)) {
331
1.81M
      cur = node1->parent;
332
3.78M
      while (cur) {
333
3.02M
    if (cur == node2)
334
1.05M
        return(1);
335
1.97M
    cur = cur->parent;
336
1.97M
      }
337
1.81M
  }
338
9.46M
  if ((precedence1 == 3) && (precedence2 > 1)) {
339
813k
      cur = node2->parent;
340
2.58M
      while (cur) {
341
1.89M
    if (cur == node1)
342
127k
        return(-1);
343
1.76M
    cur = cur->parent;
344
1.76M
      }
345
813k
  }
346
9.46M
    }
347
348
    /*
349
     * Speedup using document order if available.
350
     */
351
56.3M
    if ((node1->type == XML_ELEMENT_NODE) &&
352
56.3M
  (node2->type == XML_ELEMENT_NODE) &&
353
56.3M
  (0 > (ptrdiff_t) node1->content) &&
354
56.3M
  (0 > (ptrdiff_t) node2->content) &&
355
56.3M
  (node1->doc == node2->doc)) {
356
357
8.87M
  l1 = -((ptrdiff_t) node1->content);
358
8.87M
  l2 = -((ptrdiff_t) node2->content);
359
8.87M
  if (l1 < l2)
360
7.15M
      return(1);
361
1.72M
  if (l1 > l2)
362
1.72M
      return(-1);
363
1.72M
    }
364
365
115M
turtle_comparison:
366
367
115M
    if (node1 == node2->prev)
368
39.1M
  return(1);
369
76.1M
    if (node1 == node2->next)
370
11.3M
  return(-1);
371
    /*
372
     * compute depth to root
373
     */
374
130M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
375
80.8M
  if (cur->parent == node1)
376
15.3M
      return(1);
377
65.5M
  depth2++;
378
65.5M
    }
379
49.4M
    root = cur;
380
124M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
381
76.6M
  if (cur->parent == node2)
382
1.20M
      return(-1);
383
75.4M
  depth1++;
384
75.4M
    }
385
    /*
386
     * Distinct document (or distinct entities :-( ) case.
387
     */
388
48.2M
    if (root != cur) {
389
408k
  return(-2);
390
408k
    }
391
    /*
392
     * get the nearest common ancestor.
393
     */
394
62.0M
    while (depth1 > depth2) {
395
14.1M
  depth1--;
396
14.1M
  node1 = node1->parent;
397
14.1M
    }
398
52.1M
    while (depth2 > depth1) {
399
4.35M
  depth2--;
400
4.35M
  node2 = node2->parent;
401
4.35M
    }
402
60.1M
    while (node1->parent != node2->parent) {
403
12.2M
  node1 = node1->parent;
404
12.2M
  node2 = node2->parent;
405
  /* should not happen but just in case ... */
406
12.2M
  if ((node1 == NULL) || (node2 == NULL))
407
0
      return(-2);
408
12.2M
    }
409
    /*
410
     * Find who's first.
411
     */
412
47.8M
    if (node1 == node2->prev)
413
22.4M
  return(1);
414
25.3M
    if (node1 == node2->next)
415
2.98M
  return(-1);
416
    /*
417
     * Speedup using document order if available.
418
     */
419
22.3M
    if ((node1->type == XML_ELEMENT_NODE) &&
420
22.3M
  (node2->type == XML_ELEMENT_NODE) &&
421
22.3M
  (0 > (ptrdiff_t) node1->content) &&
422
22.3M
  (0 > (ptrdiff_t) node2->content) &&
423
22.3M
  (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
20.9G
    for (cur = node1->next;cur != NULL;cur = cur->next)
434
20.9G
  if (cur == node2)
435
3.50M
      return(1);
436
18.8M
    return(-1); /* assume there is no sibling list corruption */
437
22.3M
}
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
47.6M
#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
146M
    {
461
146M
        int res = xmlXPathCmpNodesExt(x, y);
462
146M
        return res == -2 ? res : -res;
463
146M
    }
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
146M
#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.75k
xmlInitXPathInternal(void) {
505
3.75k
#if defined(NAN) && defined(INFINITY)
506
3.75k
    xmlXPathNAN = NAN;
507
3.75k
    xmlXPathPINF = INFINITY;
508
3.75k
    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.75k
}
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
3.18G
xmlXPathIsNaN(double val) {
526
3.18G
#ifdef isnan
527
3.18G
    return isnan(val);
528
#else
529
    return !(val == val);
530
#endif
531
3.18G
}
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
18.7M
xmlXPathIsInf(double val) {
541
18.7M
#ifdef isinf
542
18.7M
    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
18.7M
}
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
19.3k
    { 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
39.4M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
632
39.4M
       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
39.4M
{
704
39.4M
    if ((error < 0) || (error > MAXERRNO))
705
0
  error = MAXERRNO;
706
39.4M
    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
39.4M
    ctxt->error = error;
716
39.4M
    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
39.4M
    xmlResetError(&ctxt->context->lastError);
729
730
39.4M
    ctxt->context->lastError.domain = XML_FROM_XPATH;
731
39.4M
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732
39.4M
                           XPATH_EXPRESSION_OK;
733
39.4M
    ctxt->context->lastError.level = XML_ERR_ERROR;
734
39.4M
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735
39.4M
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736
39.4M
    ctxt->context->lastError.node = ctxt->context->debugNode;
737
39.4M
    if (ctxt->context->error != NULL) {
738
0
  ctxt->context->error(ctxt->context->userData,
739
0
                       &ctxt->context->lastError);
740
39.4M
    } else {
741
39.4M
  __xmlRaiseError(NULL, NULL, NULL,
742
39.4M
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743
39.4M
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744
39.4M
      XML_ERR_ERROR, NULL, 0,
745
39.4M
      (const char *) ctxt->base, NULL, NULL,
746
39.4M
      ctxt->cur - ctxt->base, 0,
747
39.4M
      "%s", xmlXPathErrorMessages[error]);
748
39.4M
    }
749
750
39.4M
}
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
21.9k
              int line ATTRIBUTE_UNUSED, int no) {
764
21.9k
    xmlXPathErr(ctxt, no);
765
21.9k
}
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.27G
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
777
1.27G
    xmlXPathContextPtr xpctxt = ctxt->context;
778
779
1.27G
    if ((opCount > xpctxt->opLimit) ||
780
1.27G
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
781
1.84k
        xpctxt->opCount = xpctxt->opLimit;
782
1.84k
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
783
1.84k
        return(-1);
784
1.84k
    }
785
786
1.27G
    xpctxt->opCount += opCount;
787
1.27G
    return(0);
788
1.27G
}
789
790
#define OP_LIMIT_EXCEEDED(ctxt, n) \
791
1.26G
    ((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
259M
{
820
259M
    if (list->items == NULL) {
821
276k
  if (initialSize <= 0)
822
0
      initialSize = 1;
823
276k
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
824
276k
  if (list->items == NULL) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListCreate: allocating item\n");
827
0
      return(-1);
828
0
  }
829
276k
  list->number = 0;
830
276k
  list->size = initialSize;
831
259M
    } else if (list->size <= list->number) {
832
119k
        if (list->size > 50000000) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
            return(-1);
836
0
        }
837
119k
  list->size *= 2;
838
119k
  list->items = (void **) xmlRealloc(list->items,
839
119k
      list->size * sizeof(void *));
840
119k
  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
119k
    }
847
259M
    list->items[list->number++] = item;
848
259M
    return(0);
849
259M
}
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
276k
{
861
276k
    xmlPointerListPtr ret;
862
863
276k
    ret = xmlMalloc(sizeof(xmlPointerList));
864
276k
    if (ret == NULL) {
865
0
  xmlXPathErrMemory(NULL,
866
0
      "xmlPointerListCreate: allocating item\n");
867
0
  return (NULL);
868
0
    }
869
276k
    memset(ret, 0, sizeof(xmlPointerList));
870
276k
    if (initialSize > 0) {
871
276k
  xmlPointerListAddSize(ret, NULL, initialSize);
872
276k
  ret->number = 0;
873
276k
    }
874
276k
    return (ret);
875
276k
}
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
274k
{
886
274k
    if (list == NULL)
887
0
  return;
888
274k
    if (list->items != NULL)
889
274k
  xmlFree(list->items);
890
274k
    xmlFree(list);
891
274k
}
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
694k
xmlXPathNewCompExpr(void) {
1024
694k
    xmlXPathCompExprPtr cur;
1025
1026
694k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1027
694k
    if (cur == NULL) {
1028
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1029
0
  return(NULL);
1030
0
    }
1031
694k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1032
694k
    cur->maxStep = 10;
1033
694k
    cur->nbStep = 0;
1034
694k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1035
694k
                                     sizeof(xmlXPathStepOp));
1036
694k
    if (cur->steps == NULL) {
1037
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1038
0
  xmlFree(cur);
1039
0
  return(NULL);
1040
0
    }
1041
694k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1042
694k
    cur->last = -1;
1043
#ifdef DEBUG_EVAL_COUNTS
1044
    cur->nb = 0;
1045
#endif
1046
694k
    return(cur);
1047
694k
}
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
694k
{
1058
694k
    xmlXPathStepOpPtr op;
1059
694k
    int i;
1060
1061
694k
    if (comp == NULL)
1062
0
        return;
1063
694k
    if (comp->dict == NULL) {
1064
64.6M
  for (i = 0; i < comp->nbStep; i++) {
1065
63.9M
      op = &comp->steps[i];
1066
63.9M
      if (op->value4 != NULL) {
1067
1.15M
    if (op->op == XPATH_OP_VALUE)
1068
729k
        xmlXPathFreeObject(op->value4);
1069
424k
    else
1070
424k
        xmlFree(op->value4);
1071
1.15M
      }
1072
63.9M
      if (op->value5 != NULL)
1073
2.32M
    xmlFree(op->value5);
1074
63.9M
  }
1075
694k
    } 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
694k
    if (comp->steps != NULL) {
1086
694k
        xmlFree(comp->steps);
1087
694k
    }
1088
#ifdef DEBUG_EVAL_COUNTS
1089
    if (comp->string != NULL) {
1090
        xmlFree(comp->string);
1091
    }
1092
#endif
1093
694k
#ifdef XPATH_STREAMING
1094
694k
    if (comp->stream != NULL) {
1095
8.00k
        xmlFreePatternList(comp->stream);
1096
8.00k
    }
1097
694k
#endif
1098
694k
    if (comp->expr != NULL) {
1099
147k
        xmlFree(comp->expr);
1100
147k
    }
1101
1102
694k
    xmlFree(comp);
1103
694k
}
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
63.9M
   int value2, int value3, void *value4, void *value5) {
1125
63.9M
    xmlXPathCompExprPtr comp = ctxt->comp;
1126
63.9M
    if (comp->nbStep >= comp->maxStep) {
1127
213k
  xmlXPathStepOp *real;
1128
1129
213k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
        }
1133
213k
  comp->maxStep *= 2;
1134
213k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1135
213k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1136
213k
  if (real == NULL) {
1137
0
      comp->maxStep /= 2;
1138
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1139
0
      return(-1);
1140
0
  }
1141
213k
  comp->steps = real;
1142
213k
    }
1143
63.9M
    comp->last = comp->nbStep;
1144
63.9M
    comp->steps[comp->nbStep].ch1 = ch1;
1145
63.9M
    comp->steps[comp->nbStep].ch2 = ch2;
1146
63.9M
    comp->steps[comp->nbStep].op = op;
1147
63.9M
    comp->steps[comp->nbStep].value = value;
1148
63.9M
    comp->steps[comp->nbStep].value2 = value2;
1149
63.9M
    comp->steps[comp->nbStep].value3 = value3;
1150
63.9M
    if ((comp->dict != NULL) &&
1151
63.9M
        ((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
63.9M
    } else {
1166
63.9M
  comp->steps[comp->nbStep].value4 = value4;
1167
63.9M
  comp->steps[comp->nbStep].value5 = value5;
1168
63.9M
    }
1169
63.9M
    comp->steps[comp->nbStep].cache = NULL;
1170
63.9M
    return(comp->nbStep++);
1171
63.9M
}
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
49.6k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1182
49.6k
    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
49.6k
    tmp = op->ch1;
1195
49.6k
    op->ch1 = op->ch2;
1196
49.6k
    op->ch2 = tmp;
1197
49.6k
}
1198
1199
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1200
3.52M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1201
3.52M
                  (op), (val), (val2), (val3), (val4), (val5))
1202
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1203
2.09M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1204
2.09M
                  (op), (val), (val2), (val3), (val4), (val5))
1205
1206
28.8M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1207
28.8M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1208
1209
637k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1210
637k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1211
1212
28.8M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1213
28.8M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1214
28.8M
      (val), (val2), 0 ,NULL ,NULL)
1215
1216
/************************************************************************
1217
 *                  *
1218
 *    XPath object cache structures       *
1219
 *                  *
1220
 ************************************************************************/
1221
1222
/* #define XP_DEFAULT_CACHE_ON */
1223
1224
32.4M
#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
0
    xmlGenericError(xmlGenericErrorContext,       \
1276
0
      "Internal error at %s:%d\n",        \
1277
0
            __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
157k
{
2212
157k
    xmlXPathContextCachePtr ret;
2213
2214
157k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2215
157k
    if (ret == NULL) {
2216
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2217
0
  return(NULL);
2218
0
    }
2219
157k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2220
157k
    ret->maxNodeset = 100;
2221
157k
    ret->maxString = 100;
2222
157k
    ret->maxBoolean = 100;
2223
157k
    ret->maxNumber = 100;
2224
157k
    ret->maxMisc = 100;
2225
157k
    return(ret);
2226
157k
}
2227
2228
static void
2229
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2230
274k
{
2231
274k
    int i;
2232
274k
    xmlXPathObjectPtr obj;
2233
2234
274k
    if (list == NULL)
2235
0
  return;
2236
2237
3.30M
    for (i = 0; i < list->number; i++) {
2238
3.02M
  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
3.02M
  if (obj->nodesetval != NULL) {
2244
2.64M
      if (obj->nodesetval->nodeTab != NULL)
2245
2.46M
    xmlFree(obj->nodesetval->nodeTab);
2246
2.64M
      xmlFree(obj->nodesetval);
2247
2.64M
  }
2248
3.02M
  xmlFree(obj);
2249
#ifdef XP_DEBUG_OBJ_USAGE
2250
  xmlXPathDebugObjCounterAll--;
2251
#endif
2252
3.02M
    }
2253
274k
    xmlPointerListFree(list);
2254
274k
}
2255
2256
static void
2257
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2258
150k
{
2259
150k
    if (cache == NULL)
2260
0
  return;
2261
150k
    if (cache->nodesetObjs)
2262
92.4k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2263
150k
    if (cache->stringObjs)
2264
68.6k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2265
150k
    if (cache->booleanObjs)
2266
30.4k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2267
150k
    if (cache->numberObjs)
2268
38.1k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2269
150k
    if (cache->miscObjs)
2270
44.5k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2271
150k
    xmlFree(cache);
2272
150k
}
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
307k
{
2302
307k
    if (ctxt == NULL)
2303
0
  return(-1);
2304
307k
    if (active) {
2305
157k
  xmlXPathContextCachePtr cache;
2306
2307
157k
  if (ctxt->cache == NULL) {
2308
157k
      ctxt->cache = xmlXPathNewCache();
2309
157k
      if (ctxt->cache == NULL)
2310
0
    return(-1);
2311
157k
  }
2312
157k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2313
157k
  if (options == 0) {
2314
157k
      if (value < 0)
2315
157k
    value = 100;
2316
157k
      cache->maxNodeset = value;
2317
157k
      cache->maxString = value;
2318
157k
      cache->maxNumber = value;
2319
157k
      cache->maxBoolean = value;
2320
157k
      cache->maxMisc = value;
2321
157k
  }
2322
157k
    } else if (ctxt->cache != NULL) {
2323
150k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2324
150k
  ctxt->cache = NULL;
2325
150k
    }
2326
307k
    return(0);
2327
307k
}
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
70.8M
{
2342
70.8M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2343
70.7M
  xmlXPathContextCachePtr cache =
2344
70.7M
      (xmlXPathContextCachePtr) ctxt->cache;
2345
2346
70.7M
  if ((cache->miscObjs != NULL) &&
2347
70.7M
      (cache->miscObjs->number != 0))
2348
62.0M
  {
2349
62.0M
      xmlXPathObjectPtr ret;
2350
2351
62.0M
      ret = (xmlXPathObjectPtr)
2352
62.0M
    cache->miscObjs->items[--cache->miscObjs->number];
2353
62.0M
      ret->type = XPATH_NODESET;
2354
62.0M
      ret->nodesetval = val;
2355
#ifdef XP_DEBUG_OBJ_USAGE
2356
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2357
#endif
2358
62.0M
      return(ret);
2359
62.0M
  }
2360
70.7M
    }
2361
2362
8.73M
    return(xmlXPathWrapNodeSet(val));
2363
2364
70.8M
}
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.50M
{
2379
7.50M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2380
7.50M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2381
2382
7.50M
  if ((cache->stringObjs != NULL) &&
2383
7.50M
      (cache->stringObjs->number != 0))
2384
165k
  {
2385
2386
165k
      xmlXPathObjectPtr ret;
2387
2388
165k
      ret = (xmlXPathObjectPtr)
2389
165k
    cache->stringObjs->items[--cache->stringObjs->number];
2390
165k
      ret->type = XPATH_STRING;
2391
165k
      ret->stringval = val;
2392
#ifdef XP_DEBUG_OBJ_USAGE
2393
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394
#endif
2395
165k
      return(ret);
2396
7.34M
  } else if ((cache->miscObjs != NULL) &&
2397
7.34M
      (cache->miscObjs->number != 0))
2398
6.42M
  {
2399
6.42M
      xmlXPathObjectPtr ret;
2400
      /*
2401
      * Fallback to misc-cache.
2402
      */
2403
6.42M
      ret = (xmlXPathObjectPtr)
2404
6.42M
    cache->miscObjs->items[--cache->miscObjs->number];
2405
2406
6.42M
      ret->type = XPATH_STRING;
2407
6.42M
      ret->stringval = val;
2408
#ifdef XP_DEBUG_OBJ_USAGE
2409
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2410
#endif
2411
6.42M
      return(ret);
2412
6.42M
  }
2413
7.50M
    }
2414
916k
    return(xmlXPathWrapString(val));
2415
7.50M
}
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
53.2M
{
2431
53.2M
    if ((ctxt != NULL) && (ctxt->cache)) {
2432
53.1M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2433
2434
53.1M
  if ((cache->nodesetObjs != NULL) &&
2435
53.1M
      (cache->nodesetObjs->number != 0))
2436
52.5M
  {
2437
52.5M
      xmlXPathObjectPtr ret;
2438
      /*
2439
      * Use the nodeset-cache.
2440
      */
2441
52.5M
      ret = (xmlXPathObjectPtr)
2442
52.5M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2443
52.5M
      ret->type = XPATH_NODESET;
2444
52.5M
      ret->boolval = 0;
2445
52.5M
      if (val) {
2446
52.5M
    if ((ret->nodesetval->nodeMax == 0) ||
2447
52.5M
        (val->type == XML_NAMESPACE_DECL))
2448
7.85M
    {
2449
                    /* TODO: Check memory error. */
2450
7.85M
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2451
44.7M
    } else {
2452
44.7M
        ret->nodesetval->nodeTab[0] = val;
2453
44.7M
        ret->nodesetval->nodeNr = 1;
2454
44.7M
    }
2455
52.5M
      }
2456
#ifdef XP_DEBUG_OBJ_USAGE
2457
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458
#endif
2459
52.5M
      return(ret);
2460
52.5M
  } else if ((cache->miscObjs != NULL) &&
2461
593k
      (cache->miscObjs->number != 0))
2462
5.12k
  {
2463
5.12k
      xmlXPathObjectPtr ret;
2464
      /*
2465
      * Fallback to misc-cache.
2466
      */
2467
2468
5.12k
      ret = (xmlXPathObjectPtr)
2469
5.12k
    cache->miscObjs->items[--cache->miscObjs->number];
2470
2471
5.12k
      ret->type = XPATH_NODESET;
2472
5.12k
      ret->boolval = 0;
2473
5.12k
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2474
5.12k
      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
5.12k
      return(ret);
2483
5.12k
  }
2484
53.1M
    }
2485
600k
    return(xmlXPathNewNodeSet(val));
2486
53.2M
}
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
11.1k
{
2501
11.1k
    if ((ctxt != NULL) && (ctxt->cache)) {
2502
11.1k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504
11.1k
  if ((cache->stringObjs != NULL) &&
2505
11.1k
      (cache->stringObjs->number != 0))
2506
10.4k
  {
2507
10.4k
      xmlXPathObjectPtr ret;
2508
2509
10.4k
      ret = (xmlXPathObjectPtr)
2510
10.4k
    cache->stringObjs->items[--cache->stringObjs->number];
2511
2512
10.4k
      ret->type = XPATH_STRING;
2513
10.4k
      ret->stringval = xmlStrdup(BAD_CAST val);
2514
#ifdef XP_DEBUG_OBJ_USAGE
2515
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516
#endif
2517
10.4k
      return(ret);
2518
10.4k
  } else if ((cache->miscObjs != NULL) &&
2519
716
      (cache->miscObjs->number != 0))
2520
33
  {
2521
33
      xmlXPathObjectPtr ret;
2522
2523
33
      ret = (xmlXPathObjectPtr)
2524
33
    cache->miscObjs->items[--cache->miscObjs->number];
2525
2526
33
      ret->type = XPATH_STRING;
2527
33
      ret->stringval = xmlStrdup(BAD_CAST val);
2528
#ifdef XP_DEBUG_OBJ_USAGE
2529
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2530
#endif
2531
33
      return(ret);
2532
33
  }
2533
11.1k
    }
2534
683
    return(xmlXPathNewCString(val));
2535
11.1k
}
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
36.7M
{
2550
36.7M
    if ((ctxt != NULL) && (ctxt->cache)) {
2551
36.7M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2552
2553
36.7M
  if ((cache->stringObjs != NULL) &&
2554
36.7M
      (cache->stringObjs->number != 0))
2555
36.1M
  {
2556
36.1M
      xmlXPathObjectPtr ret;
2557
2558
36.1M
      ret = (xmlXPathObjectPtr)
2559
36.1M
    cache->stringObjs->items[--cache->stringObjs->number];
2560
36.1M
      ret->type = XPATH_STRING;
2561
36.1M
      if (val != NULL)
2562
36.1M
    ret->stringval = xmlStrdup(val);
2563
20
      else
2564
20
    ret->stringval = xmlStrdup((const xmlChar *)"");
2565
#ifdef XP_DEBUG_OBJ_USAGE
2566
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2567
#endif
2568
36.1M
      return(ret);
2569
36.1M
  } else if ((cache->miscObjs != NULL) &&
2570
569k
      (cache->miscObjs->number != 0))
2571
8.21k
  {
2572
8.21k
      xmlXPathObjectPtr ret;
2573
2574
8.21k
      ret = (xmlXPathObjectPtr)
2575
8.21k
    cache->miscObjs->items[--cache->miscObjs->number];
2576
2577
8.21k
      ret->type = XPATH_STRING;
2578
8.21k
      if (val != NULL)
2579
8.21k
    ret->stringval = xmlStrdup(val);
2580
2
      else
2581
2
    ret->stringval = xmlStrdup((const xmlChar *)"");
2582
#ifdef XP_DEBUG_OBJ_USAGE
2583
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2584
#endif
2585
8.21k
      return(ret);
2586
8.21k
  }
2587
36.7M
    }
2588
561k
    return(xmlXPathNewString(val));
2589
36.7M
}
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
25.3M
{
2604
25.3M
    if ((ctxt != NULL) && (ctxt->cache)) {
2605
25.3M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607
25.3M
  if ((cache->booleanObjs != NULL) &&
2608
25.3M
      (cache->booleanObjs->number != 0))
2609
25.2M
  {
2610
25.2M
      xmlXPathObjectPtr ret;
2611
2612
25.2M
      ret = (xmlXPathObjectPtr)
2613
25.2M
    cache->booleanObjs->items[--cache->booleanObjs->number];
2614
25.2M
      ret->type = XPATH_BOOLEAN;
2615
25.2M
      ret->boolval = (val != 0);
2616
#ifdef XP_DEBUG_OBJ_USAGE
2617
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2618
#endif
2619
25.2M
      return(ret);
2620
25.2M
  } else if ((cache->miscObjs != NULL) &&
2621
107k
      (cache->miscObjs->number != 0))
2622
14.2k
  {
2623
14.2k
      xmlXPathObjectPtr ret;
2624
2625
14.2k
      ret = (xmlXPathObjectPtr)
2626
14.2k
    cache->miscObjs->items[--cache->miscObjs->number];
2627
2628
14.2k
      ret->type = XPATH_BOOLEAN;
2629
14.2k
      ret->boolval = (val != 0);
2630
#ifdef XP_DEBUG_OBJ_USAGE
2631
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2632
#endif
2633
14.2k
      return(ret);
2634
14.2k
  }
2635
25.3M
    }
2636
93.4k
    return(xmlXPathNewBoolean(val));
2637
25.3M
}
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
74.3M
{
2652
74.3M
     if ((ctxt != NULL) && (ctxt->cache)) {
2653
74.3M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2654
2655
74.3M
  if ((cache->numberObjs != NULL) &&
2656
74.3M
      (cache->numberObjs->number != 0))
2657
73.7M
  {
2658
73.7M
      xmlXPathObjectPtr ret;
2659
2660
73.7M
      ret = (xmlXPathObjectPtr)
2661
73.7M
    cache->numberObjs->items[--cache->numberObjs->number];
2662
73.7M
      ret->type = XPATH_NUMBER;
2663
73.7M
      ret->floatval = val;
2664
#ifdef XP_DEBUG_OBJ_USAGE
2665
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2666
#endif
2667
73.7M
      return(ret);
2668
73.7M
  } else if ((cache->miscObjs != NULL) &&
2669
567k
      (cache->miscObjs->number != 0))
2670
13.4k
  {
2671
13.4k
      xmlXPathObjectPtr ret;
2672
2673
13.4k
      ret = (xmlXPathObjectPtr)
2674
13.4k
    cache->miscObjs->items[--cache->miscObjs->number];
2675
2676
13.4k
      ret->type = XPATH_NUMBER;
2677
13.4k
      ret->floatval = val;
2678
#ifdef XP_DEBUG_OBJ_USAGE
2679
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2680
#endif
2681
13.4k
      return(ret);
2682
13.4k
  }
2683
74.3M
    }
2684
554k
    return(xmlXPathNewFloat(val));
2685
74.3M
}
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
14.9M
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2701
14.9M
    xmlChar *res = NULL;
2702
2703
14.9M
    if (val == NULL)
2704
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2705
2706
14.9M
    switch (val->type) {
2707
0
    case XPATH_UNDEFINED:
2708
#ifdef DEBUG_EXPR
2709
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2710
#endif
2711
0
  break;
2712
7.38M
    case XPATH_NODESET:
2713
7.38M
    case XPATH_XSLT_TREE:
2714
7.38M
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2715
7.38M
  break;
2716
7.48M
    case XPATH_STRING:
2717
7.48M
  return(val);
2718
63.7k
    case XPATH_BOOLEAN:
2719
63.7k
  res = xmlXPathCastBooleanToString(val->boolval);
2720
63.7k
  break;
2721
52.9k
    case XPATH_NUMBER:
2722
52.9k
  res = xmlXPathCastNumberToString(val->floatval);
2723
52.9k
  break;
2724
1
    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
1
  TODO;
2731
1
  break;
2732
14.9M
    }
2733
7.50M
    xmlXPathReleaseObject(ctxt, val);
2734
7.50M
    if (res == NULL)
2735
1
  return(xmlXPathCacheNewCString(ctxt, ""));
2736
7.50M
    return(xmlXPathCacheWrapString(ctxt, res));
2737
7.50M
}
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
32.4M
{
2752
32.4M
    if (val == NULL)
2753
292
  return(NULL);
2754
2755
32.4M
    if (XP_HAS_CACHE(ctxt)) {
2756
32.4M
  switch (val->type) {
2757
0
      case XPATH_NODESET:
2758
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2759
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2760
5.75M
      case XPATH_STRING:
2761
5.75M
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2762
0
      case XPATH_BOOLEAN:
2763
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2764
26.6M
      case XPATH_NUMBER:
2765
26.6M
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2766
0
      default:
2767
0
    break;
2768
32.4M
  }
2769
32.4M
    }
2770
0
    return(xmlXPathObjectCopy(val));
2771
32.4M
}
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
3.08M
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2786
3.08M
    xmlXPathObjectPtr ret;
2787
2788
3.08M
    if (val == NULL)
2789
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2790
3.08M
    if (val->type == XPATH_BOOLEAN)
2791
892k
  return(val);
2792
2.18M
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2793
2.18M
    xmlXPathReleaseObject(ctxt, val);
2794
2.18M
    return(ret);
2795
3.08M
}
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
45.0M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2810
45.0M
    xmlXPathObjectPtr ret;
2811
2812
45.0M
    if (val == NULL)
2813
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2814
45.0M
    if (val->type == XPATH_NUMBER)
2815
121
  return(val);
2816
45.0M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2817
45.0M
    xmlXPathReleaseObject(ctxt, val);
2818
45.0M
    return(ret);
2819
45.0M
}
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
2.68M
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2837
2.68M
    int ret;
2838
2839
2.68M
    if (ctxt == NULL)
2840
0
        return(0);
2841
2.68M
    ret = ctxt->valueFrame;
2842
2.68M
    ctxt->valueFrame = ctxt->valueNr;
2843
2.68M
    return(ret);
2844
2.68M
}
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
2.67M
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2855
2.67M
    if (ctxt == NULL)
2856
0
        return;
2857
2.67M
    if (ctxt->valueNr < ctxt->valueFrame) {
2858
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859
0
    }
2860
2.67M
    ctxt->valueFrame = frame;
2861
2.67M
}
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
315M
{
2874
315M
    xmlXPathObjectPtr ret;
2875
2876
315M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2877
843k
        return (NULL);
2878
2879
314M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2880
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2881
0
        return (NULL);
2882
0
    }
2883
2884
314M
    ctxt->valueNr--;
2885
314M
    if (ctxt->valueNr > 0)
2886
266M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2887
47.7M
    else
2888
47.7M
        ctxt->value = NULL;
2889
314M
    ret = ctxt->valueTab[ctxt->valueNr];
2890
314M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2891
314M
    return (ret);
2892
314M
}
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
314M
{
2906
314M
    if (ctxt == NULL) return(-1);
2907
314M
    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
34
  ctxt->error = XPATH_MEMORY_ERROR;
2913
34
        return(-1);
2914
34
    }
2915
314M
    if (ctxt->valueNr >= ctxt->valueMax) {
2916
5.35k
        xmlXPathObjectPtr *tmp;
2917
2918
5.35k
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2919
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2920
0
            return (-1);
2921
0
        }
2922
5.35k
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2923
5.35k
                                             2 * ctxt->valueMax *
2924
5.35k
                                             sizeof(ctxt->valueTab[0]));
2925
5.35k
        if (tmp == NULL) {
2926
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2927
0
            return (-1);
2928
0
        }
2929
5.35k
        ctxt->valueMax *= 2;
2930
5.35k
  ctxt->valueTab = tmp;
2931
5.35k
    }
2932
314M
    ctxt->valueTab[ctxt->valueNr] = value;
2933
314M
    ctxt->value = value;
2934
314M
    return (ctxt->valueNr++);
2935
314M
}
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
2.13k
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2948
2.13k
    xmlXPathObjectPtr obj;
2949
2.13k
    int ret;
2950
2951
2.13k
    obj = valuePop(ctxt);
2952
2.13k
    if (obj == NULL) {
2953
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2954
0
  return(0);
2955
0
    }
2956
2.13k
    if (obj->type != XPATH_BOOLEAN)
2957
1.04k
  ret = xmlXPathCastToBoolean(obj);
2958
1.08k
    else
2959
1.08k
        ret = obj->boolval;
2960
2.13k
    xmlXPathReleaseObject(ctxt->context, obj);
2961
2.13k
    return(ret);
2962
2.13k
}
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
1.50k
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2975
1.50k
    xmlXPathObjectPtr obj;
2976
1.50k
    double ret;
2977
2978
1.50k
    obj = valuePop(ctxt);
2979
1.50k
    if (obj == NULL) {
2980
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2981
0
  return(0);
2982
0
    }
2983
1.50k
    if (obj->type != XPATH_NUMBER)
2984
367
  ret = xmlXPathCastToNumber(obj);
2985
1.14k
    else
2986
1.14k
        ret = obj->floatval;
2987
1.50k
    xmlXPathReleaseObject(ctxt->context, obj);
2988
1.50k
    return(ret);
2989
1.50k
}
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
480k
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
3002
480k
    xmlXPathObjectPtr obj;
3003
480k
    xmlChar * ret;
3004
3005
480k
    obj = valuePop(ctxt);
3006
480k
    if (obj == NULL) {
3007
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3008
0
  return(NULL);
3009
0
    }
3010
480k
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3011
    /* TODO: needs refactoring somewhere else */
3012
480k
    if (obj->stringval == ret)
3013
0
  obj->stringval = NULL;
3014
480k
    xmlXPathReleaseObject(ctxt->context, obj);
3015
480k
    return(ret);
3016
480k
}
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
24.5k
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3029
24.5k
    xmlXPathObjectPtr obj;
3030
24.5k
    xmlNodeSetPtr ret;
3031
3032
24.5k
    if (ctxt == NULL) return(NULL);
3033
24.5k
    if (ctxt->value == NULL) {
3034
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3035
0
  return(NULL);
3036
0
    }
3037
24.5k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3038
473
  xmlXPathSetTypeError(ctxt);
3039
473
  return(NULL);
3040
473
    }
3041
24.0k
    obj = valuePop(ctxt);
3042
24.0k
    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
24.0k
    obj->nodesetval = NULL;
3049
24.0k
    xmlXPathReleaseObject(ctxt->context, obj);
3050
24.0k
    return(ret);
3051
24.5k
}
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
164
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3064
164
    xmlXPathObjectPtr obj;
3065
164
    void * ret;
3066
3067
164
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3068
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3069
0
  return(NULL);
3070
0
    }
3071
164
    if (ctxt->value->type != XPATH_USERS) {
3072
0
  xmlXPathSetTypeError(ctxt);
3073
0
  return(NULL);
3074
0
    }
3075
164
    obj = valuePop(ctxt);
3076
164
    ret = obj->user;
3077
164
    obj->user = NULL;
3078
164
    xmlXPathReleaseObject(ctxt->context, obj);
3079
164
    return(ret);
3080
164
}
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
533M
#define CUR (*ctxt->cur)
3106
1.19M
#define SKIP(val) ctxt->cur += (val)
3107
10.6M
#define NXT(val) ctxt->cur[(val)]
3108
640k
#define CUR_PTR ctxt->cur
3109
49.1M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3110
3111
#define COPY_BUF(l,b,i,v)                                              \
3112
11.7M
    if (l == 1) b[i++] = v;                                            \
3113
11.7M
    else i += xmlCopyChar(l,&b[i],v)
3114
3115
20.5M
#define NEXTL(l)  ctxt->cur += l
3116
3117
#define SKIP_BLANKS             \
3118
190M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3119
3120
#define CURRENT (*ctxt->cur)
3121
239M
#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
13.7k
#define UPPER_DOUBLE 1E9
3132
7.97k
#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
5.94k
#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
29.3k
{
3150
29.3k
    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
29.3k
    default:
3160
29.3k
  if (xmlXPathIsNaN(number)) {
3161
0
      if (buffersize > (int)sizeof("NaN"))
3162
0
    snprintf(buffer, buffersize, "NaN");
3163
29.3k
  } else if (number == 0) {
3164
            /* Omit sign for negative zero. */
3165
0
      snprintf(buffer, buffersize, "0");
3166
29.3k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3167
29.3k
                   (number == (int) number)) {
3168
15.5k
      char work[30];
3169
15.5k
      char *ptr, *cur;
3170
15.5k
      int value = (int) number;
3171
3172
15.5k
            ptr = &buffer[0];
3173
15.5k
      if (value == 0) {
3174
0
    *ptr++ = '0';
3175
15.5k
      } else {
3176
15.5k
    snprintf(work, 29, "%d", value);
3177
15.5k
    cur = &work[0];
3178
48.3k
    while ((*cur) && (ptr - buffer < buffersize)) {
3179
32.7k
        *ptr++ = *cur++;
3180
32.7k
    }
3181
15.5k
      }
3182
15.5k
      if (ptr - buffer < buffersize) {
3183
15.5k
    *ptr = 0;
3184
15.5k
      } else if (buffersize > 0) {
3185
0
    ptr--;
3186
0
    *ptr = 0;
3187
0
      }
3188
15.5k
  } 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
13.7k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3199
13.7k
      int integer_place, fraction_place;
3200
13.7k
      char *ptr;
3201
13.7k
      char *after_fraction;
3202
13.7k
      double absolute_value;
3203
13.7k
      int size;
3204
3205
13.7k
      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
13.7k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3213
13.7k
      (absolute_value < LOWER_DOUBLE)) &&
3214
13.7k
     (absolute_value != 0.0) ) {
3215
    /* Use scientific notation */
3216
5.94k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3217
5.94k
    fraction_place = DBL_DIG - 1;
3218
5.94k
    size = snprintf(work, sizeof(work),"%*.*e",
3219
5.94k
       integer_place, fraction_place, number);
3220
30.8k
    while ((size > 0) && (work[size] != 'e')) size--;
3221
3222
5.94k
      }
3223
7.79k
      else {
3224
    /* Use regular notation */
3225
7.79k
    if (absolute_value > 0.0) {
3226
7.79k
        integer_place = (int)log10(absolute_value);
3227
7.79k
        if (integer_place > 0)
3228
2.43k
            fraction_place = DBL_DIG - integer_place - 1;
3229
5.35k
        else
3230
5.35k
            fraction_place = DBL_DIG - integer_place;
3231
7.79k
    } else {
3232
0
        fraction_place = 1;
3233
0
    }
3234
7.79k
    size = snprintf(work, sizeof(work), "%0.*f",
3235
7.79k
        fraction_place, number);
3236
7.79k
      }
3237
3238
      /* Remove leading spaces sometimes inserted by snprintf */
3239
17.3k
      while (work[0] == ' ') {
3240
75.4k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3241
3.59k
    size--;
3242
3.59k
      }
3243
3244
      /* Remove fractional trailing zeroes */
3245
13.7k
      after_fraction = work + size;
3246
13.7k
      ptr = after_fraction;
3247
127k
      while (*(--ptr) == '0')
3248
114k
    ;
3249
13.7k
      if (*ptr != '.')
3250
11.1k
          ptr++;
3251
38.6k
      while ((*ptr++ = *after_fraction++) != 0);
3252
3253
      /* Finally copy result back to caller */
3254
13.7k
      size = strlen(work) + 1;
3255
13.7k
      if (size > buffersize) {
3256
0
    work[buffersize - 1] = 0;
3257
0
    size = buffersize;
3258
0
      }
3259
13.7k
      memmove(buffer, work, size);
3260
13.7k
  }
3261
29.3k
  break;
3262
29.3k
    }
3263
29.3k
}
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.75k
xmlXPathOrderDocElems(xmlDocPtr doc) {
3287
3.75k
    ptrdiff_t count = 0;
3288
3.75k
    xmlNodePtr cur;
3289
3290
3.75k
    if (doc == NULL)
3291
0
  return(-1);
3292
3.75k
    cur = doc->children;
3293
150k
    while (cur != NULL) {
3294
146k
  if (cur->type == XML_ELEMENT_NODE) {
3295
45.0k
      cur->content = (void *) (-(++count));
3296
45.0k
      if (cur->children != NULL) {
3297
33.7k
    cur = cur->children;
3298
33.7k
    continue;
3299
33.7k
      }
3300
45.0k
  }
3301
112k
  if (cur->next != NULL) {
3302
78.8k
      cur = cur->next;
3303
78.8k
      continue;
3304
78.8k
  }
3305
37.5k
  do {
3306
37.5k
      cur = cur->parent;
3307
37.5k
      if (cur == NULL)
3308
0
    break;
3309
37.5k
      if (cur == (xmlNodePtr) doc) {
3310
3.75k
    cur = NULL;
3311
3.75k
    break;
3312
3.75k
      }
3313
33.7k
      if (cur->next != NULL) {
3314
30.0k
    cur = cur->next;
3315
30.0k
    break;
3316
30.0k
      }
3317
33.7k
  } while (cur != NULL);
3318
33.7k
    }
3319
3.75k
    return(count);
3320
3.75k
}
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
578k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3334
578k
    int depth1, depth2;
3335
578k
    int attr1 = 0, attr2 = 0;
3336
578k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3337
578k
    xmlNodePtr cur, root;
3338
3339
578k
    if ((node1 == NULL) || (node2 == NULL))
3340
0
  return(-2);
3341
    /*
3342
     * a couple of optimizations which will avoid computations in most cases
3343
     */
3344
578k
    if (node1 == node2)    /* trivial case */
3345
0
  return(0);
3346
578k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3347
116
  attr1 = 1;
3348
116
  attrNode1 = node1;
3349
116
  node1 = node1->parent;
3350
116
    }
3351
578k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3352
144
  attr2 = 1;
3353
144
  attrNode2 = node2;
3354
144
  node2 = node2->parent;
3355
144
    }
3356
578k
    if (node1 == node2) {
3357
18
  if (attr1 == attr2) {
3358
      /* not required, but we keep attributes in order */
3359
8
      if (attr1 != 0) {
3360
8
          cur = attrNode2->prev;
3361
8
    while (cur != NULL) {
3362
8
        if (cur == attrNode1)
3363
8
            return (1);
3364
0
        cur = cur->prev;
3365
0
    }
3366
0
    return (-1);
3367
8
      }
3368
0
      return(0);
3369
8
  }
3370
10
  if (attr2 == 1)
3371
9
      return(1);
3372
1
  return(-1);
3373
10
    }
3374
578k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3375
578k
        (node2->type == XML_NAMESPACE_DECL))
3376
2.79k
  return(1);
3377
576k
    if (node1 == node2->prev)
3378
381
  return(1);
3379
575k
    if (node1 == node2->next)
3380
10
  return(-1);
3381
3382
    /*
3383
     * Speedup using document order if available.
3384
     */
3385
575k
    if ((node1->type == XML_ELEMENT_NODE) &&
3386
575k
  (node2->type == XML_ELEMENT_NODE) &&
3387
575k
  (0 > (ptrdiff_t) node1->content) &&
3388
575k
  (0 > (ptrdiff_t) node2->content) &&
3389
575k
  (node1->doc == node2->doc)) {
3390
510
  ptrdiff_t l1, l2;
3391
3392
510
  l1 = -((ptrdiff_t) node1->content);
3393
510
  l2 = -((ptrdiff_t) node2->content);
3394
510
  if (l1 < l2)
3395
496
      return(1);
3396
14
  if (l1 > l2)
3397
14
      return(-1);
3398
14
    }
3399
3400
    /*
3401
     * compute depth to root
3402
     */
3403
1.25M
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3404
705k
  if (cur->parent == node1)
3405
21.7k
      return(1);
3406
683k
  depth2++;
3407
683k
    }
3408
553k
    root = cur;
3409
1.19M
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3410
645k
  if (cur->parent == node2)
3411
8
      return(-1);
3412
645k
  depth1++;
3413
645k
    }
3414
    /*
3415
     * Distinct document (or distinct entities :-( ) case.
3416
     */
3417
553k
    if (root != cur) {
3418
12.3k
  return(-2);
3419
12.3k
    }
3420
    /*
3421
     * get the nearest common ancestor.
3422
     */
3423
541k
    while (depth1 > depth2) {
3424
105
  depth1--;
3425
105
  node1 = node1->parent;
3426
105
    }
3427
568k
    while (depth2 > depth1) {
3428
27.5k
  depth2--;
3429
27.5k
  node2 = node2->parent;
3430
27.5k
    }
3431
629k
    while (node1->parent != node2->parent) {
3432
88.1k
  node1 = node1->parent;
3433
88.1k
  node2 = node2->parent;
3434
  /* should not happen but just in case ... */
3435
88.1k
  if ((node1 == NULL) || (node2 == NULL))
3436
0
      return(-2);
3437
88.1k
    }
3438
    /*
3439
     * Find who's first.
3440
     */
3441
541k
    if (node1 == node2->prev)
3442
1.95k
  return(1);
3443
539k
    if (node1 == node2->next)
3444
49
  return(-1);
3445
    /*
3446
     * Speedup using document order if available.
3447
     */
3448
539k
    if ((node1->type == XML_ELEMENT_NODE) &&
3449
539k
  (node2->type == XML_ELEMENT_NODE) &&
3450
539k
  (0 > (ptrdiff_t) node1->content) &&
3451
539k
  (0 > (ptrdiff_t) node2->content) &&
3452
539k
  (node1->doc == node2->doc)) {
3453
163
  ptrdiff_t l1, l2;
3454
3455
163
  l1 = -((ptrdiff_t) node1->content);
3456
163
  l2 = -((ptrdiff_t) node2->content);
3457
163
  if (l1 < l2)
3458
155
      return(1);
3459
8
  if (l1 > l2)
3460
8
      return(-1);
3461
8
    }
3462
3463
5.24G
    for (cur = node1->next;cur != NULL;cur = cur->next)
3464
5.24G
  if (cur == node2)
3465
538k
      return(1);
3466
2
    return(-1); /* assume there is no sibling list corruption */
3467
538k
}
3468
3469
/**
3470
 * xmlXPathNodeSetSort:
3471
 * @set:  the node set
3472
 *
3473
 * Sort the node set in document order
3474
 */
3475
void
3476
2.12M
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3477
#ifndef WITH_TIM_SORT
3478
    int i, j, incr, len;
3479
    xmlNodePtr tmp;
3480
#endif
3481
3482
2.12M
    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
2.12M
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3514
2.12M
#endif /* WITH_TIM_SORT */
3515
2.12M
}
3516
3517
129M
#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
11.7M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3531
11.7M
    xmlNsPtr cur;
3532
3533
11.7M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3534
0
  return(NULL);
3535
11.7M
    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
11.7M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3542
11.7M
    if (cur == NULL) {
3543
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3544
0
  return(NULL);
3545
0
    }
3546
11.7M
    memset(cur, 0, sizeof(xmlNs));
3547
11.7M
    cur->type = XML_NAMESPACE_DECL;
3548
11.7M
    if (ns->href != NULL)
3549
11.7M
  cur->href = xmlStrdup(ns->href);
3550
11.7M
    if (ns->prefix != NULL)
3551
11.7M
  cur->prefix = xmlStrdup(ns->prefix);
3552
11.7M
    cur->next = (xmlNsPtr) node;
3553
11.7M
    return((xmlNodePtr) cur);
3554
11.7M
}
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
11.7M
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3566
11.7M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3567
0
  return;
3568
3569
11.7M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3570
11.7M
  if (ns->href != NULL)
3571
11.7M
      xmlFree((xmlChar *)ns->href);
3572
11.7M
  if (ns->prefix != NULL)
3573
11.7M
      xmlFree((xmlChar *)ns->prefix);
3574
11.7M
  xmlFree(ns);
3575
11.7M
    }
3576
11.7M
}
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
82.9M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3588
82.9M
    xmlNodeSetPtr ret;
3589
3590
82.9M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3591
82.9M
    if (ret == NULL) {
3592
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
  return(NULL);
3594
0
    }
3595
82.9M
    memset(ret, 0 , sizeof(xmlNodeSet));
3596
82.9M
    if (val != NULL) {
3597
13.5M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3598
13.5M
               sizeof(xmlNodePtr));
3599
13.5M
  if (ret->nodeTab == NULL) {
3600
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3601
0
      xmlFree(ret);
3602
0
      return(NULL);
3603
0
  }
3604
13.5M
  memset(ret->nodeTab, 0 ,
3605
13.5M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3606
13.5M
        ret->nodeMax = XML_NODESET_DEFAULT;
3607
13.5M
  if (val->type == XML_NAMESPACE_DECL) {
3608
112k
      xmlNsPtr ns = (xmlNsPtr) val;
3609
3610
            /* TODO: Check memory error. */
3611
112k
      ret->nodeTab[ret->nodeNr++] =
3612
112k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3613
112k
  } else
3614
13.4M
      ret->nodeTab[ret->nodeNr++] = val;
3615
13.5M
    }
3616
82.9M
    return(ret);
3617
82.9M
}
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
3.38k
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3630
3.38k
    int i;
3631
3632
3.38k
    if ((cur == NULL) || (val == NULL)) return(0);
3633
3.38k
    if (val->type == XML_NAMESPACE_DECL) {
3634
851
  for (i = 0; i < cur->nodeNr; i++) {
3635
683
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3636
0
    xmlNsPtr ns1, ns2;
3637
3638
0
    ns1 = (xmlNsPtr) val;
3639
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3640
0
    if (ns1 == ns2)
3641
0
        return(1);
3642
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3643
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3644
0
        return(1);
3645
0
      }
3646
683
  }
3647
3.22k
    } else {
3648
57.2k
  for (i = 0; i < cur->nodeNr; i++) {
3649
55.0k
      if (cur->nodeTab[i] == val)
3650
972
    return(1);
3651
55.0k
  }
3652
3.22k
    }
3653
2.41k
    return(0);
3654
3.38k
}
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
4.87M
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3668
4.87M
    int i;
3669
3670
3671
4.87M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3672
4.87M
        (ns->type != XML_NAMESPACE_DECL) ||
3673
4.87M
  (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.03M
    for (i = 0;i < cur->nodeNr;i++) {
3681
2.15M
        if ((cur->nodeTab[i] != NULL) &&
3682
2.15M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3683
2.15M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3684
2.15M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3685
0
      return(0);
3686
2.15M
    }
3687
3688
    /*
3689
     * grow the nodeTab if needed
3690
     */
3691
4.87M
    if (cur->nodeMax == 0) {
3692
324k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3693
324k
               sizeof(xmlNodePtr));
3694
324k
  if (cur->nodeTab == NULL) {
3695
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3696
0
      return(-1);
3697
0
  }
3698
324k
  memset(cur->nodeTab, 0 ,
3699
324k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3700
324k
        cur->nodeMax = XML_NODESET_DEFAULT;
3701
4.55M
    } 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
4.87M
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3719
4.87M
    return(0);
3720
4.87M
}
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
26.9k
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3733
26.9k
    int i;
3734
3735
26.9k
    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
440k
    for (i = 0;i < cur->nodeNr;i++)
3742
437k
        if (cur->nodeTab[i] == val) return(0);
3743
3744
    /*
3745
     * grow the nodeTab if needed
3746
     */
3747
3.12k
    if (cur->nodeMax == 0) {
3748
302
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3749
302
               sizeof(xmlNodePtr));
3750
302
  if (cur->nodeTab == NULL) {
3751
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3752
0
      return(-1);
3753
0
  }
3754
302
  memset(cur->nodeTab, 0 ,
3755
302
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3756
302
        cur->nodeMax = XML_NODESET_DEFAULT;
3757
2.82k
    } else if (cur->nodeNr == cur->nodeMax) {
3758
163
        xmlNodePtr *temp;
3759
3760
163
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3761
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3762
0
            return(-1);
3763
0
        }
3764
163
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3765
163
              sizeof(xmlNodePtr));
3766
163
  if (temp == NULL) {
3767
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3768
0
      return(-1);
3769
0
  }
3770
163
        cur->nodeMax *= 2;
3771
163
  cur->nodeTab = temp;
3772
163
    }
3773
3.12k
    if (val->type == XML_NAMESPACE_DECL) {
3774
33
  xmlNsPtr ns = (xmlNsPtr) val;
3775
3776
        /* TODO: Check memory error. */
3777
33
  cur->nodeTab[cur->nodeNr++] =
3778
33
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3779
33
    } else
3780
3.09k
  cur->nodeTab[cur->nodeNr++] = val;
3781
3.12k
    return(0);
3782
3.12k
}
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
562M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3796
562M
    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
562M
    if (cur->nodeMax == 0) {
3803
24.1M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3804
24.1M
               sizeof(xmlNodePtr));
3805
24.1M
  if (cur->nodeTab == NULL) {
3806
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3807
0
      return(-1);
3808
0
  }
3809
24.1M
  memset(cur->nodeTab, 0 ,
3810
24.1M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3811
24.1M
        cur->nodeMax = XML_NODESET_DEFAULT;
3812
538M
    } else if (cur->nodeNr == cur->nodeMax) {
3813
8.51M
        xmlNodePtr *temp;
3814
3815
8.51M
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3816
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3817
0
            return(-1);
3818
0
        }
3819
8.51M
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3820
8.51M
              sizeof(xmlNodePtr));
3821
8.51M
  if (temp == NULL) {
3822
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3823
0
      return(-1);
3824
0
  }
3825
8.51M
  cur->nodeTab = temp;
3826
8.51M
        cur->nodeMax *= 2;
3827
8.51M
    }
3828
562M
    if (val->type == XML_NAMESPACE_DECL) {
3829
6.41M
  xmlNsPtr ns = (xmlNsPtr) val;
3830
3831
        /* TODO: Check memory error. */
3832
6.41M
  cur->nodeTab[cur->nodeNr++] =
3833
6.41M
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3834
6.41M
    } else
3835
555M
  cur->nodeTab[cur->nodeNr++] = val;
3836
562M
    return(0);
3837
562M
}
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
11.8M
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3851
11.8M
    int i, j, initNr, skip;
3852
11.8M
    xmlNodePtr n1, n2;
3853
3854
11.8M
    if (val2 == NULL) return(val1);
3855
11.5M
    if (val1 == NULL) {
3856
2.67M
  val1 = xmlXPathNodeSetCreate(NULL);
3857
2.67M
    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
2.67M
    }
3887
3888
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3889
11.5M
    initNr = val1->nodeNr;
3890
3891
30.4M
    for (i = 0;i < val2->nodeNr;i++) {
3892
18.9M
  n2 = val2->nodeTab[i];
3893
  /*
3894
   * check against duplicates
3895
   */
3896
18.9M
  skip = 0;
3897
771M
  for (j = 0; j < initNr; j++) {
3898
756M
      n1 = val1->nodeTab[j];
3899
756M
      if (n1 == n2) {
3900
4.30M
    skip = 1;
3901
4.30M
    break;
3902
752M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3903
752M
           (n2->type == XML_NAMESPACE_DECL)) {
3904
410k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3905
410k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3906
75.6k
      ((xmlNsPtr) n2)->prefix)))
3907
59.2k
    {
3908
59.2k
        skip = 1;
3909
59.2k
        break;
3910
59.2k
    }
3911
410k
      }
3912
756M
  }
3913
18.9M
  if (skip)
3914
4.36M
      continue;
3915
3916
  /*
3917
   * grow the nodeTab if needed
3918
   */
3919
14.5M
  if (val1->nodeMax == 0) {
3920
1.96M
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3921
1.96M
                sizeof(xmlNodePtr));
3922
1.96M
      if (val1->nodeTab == NULL) {
3923
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3924
0
    return(NULL);
3925
0
      }
3926
1.96M
      memset(val1->nodeTab, 0 ,
3927
1.96M
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3928
1.96M
      val1->nodeMax = XML_NODESET_DEFAULT;
3929
12.6M
  } else if (val1->nodeNr == val1->nodeMax) {
3930
498k
      xmlNodePtr *temp;
3931
3932
498k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3933
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3934
0
                return(NULL);
3935
0
            }
3936
498k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3937
498k
               sizeof(xmlNodePtr));
3938
498k
      if (temp == NULL) {
3939
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3940
0
    return(NULL);
3941
0
      }
3942
498k
      val1->nodeTab = temp;
3943
498k
      val1->nodeMax *= 2;
3944
498k
  }
3945
14.5M
  if (n2->type == XML_NAMESPACE_DECL) {
3946
380k
      xmlNsPtr ns = (xmlNsPtr) n2;
3947
3948
            /* TODO: Check memory error. */
3949
380k
      val1->nodeTab[val1->nodeNr++] =
3950
380k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3951
380k
  } else
3952
14.1M
      val1->nodeTab[val1->nodeNr++] = n2;
3953
14.5M
    }
3954
3955
11.5M
    return(val1);
3956
11.5M
}
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
39.9M
{
3972
39.9M
    {
3973
39.9M
  int i, j, initNbSet1;
3974
39.9M
  xmlNodePtr n1, n2;
3975
3976
39.9M
  initNbSet1 = set1->nodeNr;
3977
207M
  for (i = 0;i < set2->nodeNr;i++) {
3978
167M
      n2 = set2->nodeTab[i];
3979
      /*
3980
      * Skip duplicates.
3981
      */
3982
187G
      for (j = 0; j < initNbSet1; j++) {
3983
187G
    n1 = set1->nodeTab[j];
3984
187G
    if (n1 == n2) {
3985
135M
        goto skip_node;
3986
187G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987
187G
        (n2->type == XML_NAMESPACE_DECL))
3988
277M
    {
3989
277M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990
277M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991
127k
      ((xmlNsPtr) n2)->prefix)))
3992
0
        {
3993
      /*
3994
      * Free the namespace node.
3995
      */
3996
0
      set2->nodeTab[i] = NULL;
3997
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3998
0
      goto skip_node;
3999
0
        }
4000
277M
    }
4001
187G
      }
4002
      /*
4003
      * grow the nodeTab if needed
4004
      */
4005
31.4M
      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
31.4M
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
399k
    xmlNodePtr *temp;
4017
4018
399k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    return(NULL);
4021
0
                }
4022
399k
    temp = (xmlNodePtr *) xmlRealloc(
4023
399k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
399k
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        return(NULL);
4027
0
    }
4028
399k
    set1->nodeTab = temp;
4029
399k
    set1->nodeMax *= 2;
4030
399k
      }
4031
31.4M
      set1->nodeTab[set1->nodeNr++] = n2;
4032
167M
skip_node:
4033
167M
      {}
4034
167M
  }
4035
39.9M
    }
4036
39.9M
    set2->nodeNr = 0;
4037
39.9M
    return(set1);
4038
39.9M
}
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
10.4M
{
4053
10.4M
    {
4054
10.4M
  int i;
4055
10.4M
  xmlNodePtr n2;
4056
4057
23.6M
  for (i = 0;i < set2->nodeNr;i++) {
4058
13.1M
      n2 = set2->nodeTab[i];
4059
13.1M
      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
13.1M
      } else if (set1->nodeNr >= set1->nodeMax) {
4070
369k
    xmlNodePtr *temp;
4071
4072
369k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4073
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4074
0
                    return(NULL);
4075
0
                }
4076
369k
    temp = (xmlNodePtr *) xmlRealloc(
4077
369k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4078
369k
    if (temp == NULL) {
4079
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4080
0
        return(NULL);
4081
0
    }
4082
369k
    set1->nodeTab = temp;
4083
369k
    set1->nodeMax *= 2;
4084
369k
      }
4085
13.1M
      set1->nodeTab[set1->nodeNr++] = n2;
4086
13.1M
  }
4087
10.4M
    }
4088
10.4M
    set2->nodeNr = 0;
4089
10.4M
    return(set1);
4090
10.4M
}
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
80.2M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4157
80.2M
    if (obj == NULL) return;
4158
80.2M
    if (obj->nodeTab != NULL) {
4159
37.4M
  int i;
4160
4161
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4162
446M
  for (i = 0;i < obj->nodeNr;i++)
4163
408M
      if ((obj->nodeTab[i] != NULL) &&
4164
408M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4165
3.82M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4166
37.4M
  xmlFree(obj->nodeTab);
4167
37.4M
    }
4168
80.2M
    xmlFree(obj);
4169
80.2M
}
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
114k
{
4183
114k
    if ((set == NULL) || (pos >= set->nodeNr))
4184
0
  return;
4185
114k
    else if ((hasNsNodes)) {
4186
29.8k
  int i;
4187
29.8k
  xmlNodePtr node;
4188
4189
834k
  for (i = pos; i < set->nodeNr; i++) {
4190
804k
      node = set->nodeTab[i];
4191
804k
      if ((node != NULL) &&
4192
804k
    (node->type == XML_NAMESPACE_DECL))
4193
11.7k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4194
804k
  }
4195
29.8k
    }
4196
114k
    set->nodeNr = pos;
4197
114k
}
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
88.8k
{
4210
88.8k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4211
88.8k
}
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
11.5k
{
4224
11.5k
    int i;
4225
11.5k
    xmlNodePtr node;
4226
4227
11.5k
    if ((set == NULL) || (set->nodeNr <= 1))
4228
0
  return;
4229
1.50M
    for (i = 0; i < set->nodeNr - 1; i++) {
4230
1.49M
        node = set->nodeTab[i];
4231
1.49M
        if ((node != NULL) &&
4232
1.49M
            (node->type == XML_NAMESPACE_DECL))
4233
22.2k
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4234
1.49M
    }
4235
11.5k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4236
11.5k
    set->nodeNr = 1;
4237
11.5k
}
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
21.3M
xmlXPathNewNodeSet(xmlNodePtr val) {
4319
21.3M
    xmlXPathObjectPtr ret;
4320
4321
21.3M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4322
21.3M
    if (ret == NULL) {
4323
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4324
0
  return(NULL);
4325
0
    }
4326
21.3M
    memset(ret, 0 , sizeof(xmlXPathObject));
4327
21.3M
    ret->type = XPATH_NODESET;
4328
21.3M
    ret->boolval = 0;
4329
    /* TODO: Check memory error. */
4330
21.3M
    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
21.3M
    return(ret);
4336
21.3M
}
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
8.73M
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4410
8.73M
    xmlXPathObjectPtr ret;
4411
4412
8.73M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4413
8.73M
    if (ret == NULL) {
4414
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4415
0
  return(NULL);
4416
0
    }
4417
8.73M
    memset(ret, 0 , sizeof(xmlXPathObject));
4418
8.73M
    ret->type = XPATH_NODESET;
4419
8.73M
    ret->nodesetval = val;
4420
#ifdef XP_DEBUG_OBJ_USAGE
4421
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4422
#endif
4423
8.73M
    return(ret);
4424
8.73M
}
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
224
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4455
224
    xmlNodeSetPtr ret;
4456
224
    int i, l1;
4457
224
    xmlNodePtr cur;
4458
4459
224
    if (xmlXPathNodeSetIsEmpty(nodes2))
4460
37
  return(nodes1);
4461
4462
    /* TODO: Check memory error. */
4463
187
    ret = xmlXPathNodeSetCreate(NULL);
4464
187
    if (xmlXPathNodeSetIsEmpty(nodes1))
4465
37
  return(ret);
4466
4467
150
    l1 = xmlXPathNodeSetGetLength(nodes1);
4468
4469
1.63k
    for (i = 0; i < l1; i++) {
4470
1.48k
  cur = xmlXPathNodeSetItem(nodes1, i);
4471
1.48k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4472
            /* TODO: Propagate memory error. */
4473
1.10k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4474
0
          break;
4475
1.10k
  }
4476
1.48k
    }
4477
150
    return(ret);
4478
187
}
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
205
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4493
205
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4494
205
    int i, l1;
4495
205
    xmlNodePtr cur;
4496
4497
205
    if (ret == NULL)
4498
0
        return(ret);
4499
205
    if (xmlXPathNodeSetIsEmpty(nodes1))
4500
43
  return(ret);
4501
162
    if (xmlXPathNodeSetIsEmpty(nodes2))
4502
39
  return(ret);
4503
4504
123
    l1 = xmlXPathNodeSetGetLength(nodes1);
4505
4506
1.25k
    for (i = 0; i < l1; i++) {
4507
1.13k
  cur = xmlXPathNodeSetItem(nodes1, i);
4508
1.13k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4509
            /* TODO: Propagate memory error. */
4510
320
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4511
0
          break;
4512
320
  }
4513
1.13k
    }
4514
123
    return(ret);
4515
162
}
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
645
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4529
645
    xmlNodeSetPtr ret;
4530
645
    xmlHashTablePtr hash;
4531
645
    int i, l;
4532
645
    xmlChar * strval;
4533
645
    xmlNodePtr cur;
4534
4535
645
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
47
  return(nodes);
4537
4538
598
    ret = xmlXPathNodeSetCreate(NULL);
4539
598
    if (ret == NULL)
4540
0
        return(ret);
4541
598
    l = xmlXPathNodeSetGetLength(nodes);
4542
598
    hash = xmlHashCreate (l);
4543
141k
    for (i = 0; i < l; i++) {
4544
140k
  cur = xmlXPathNodeSetItem(nodes, i);
4545
140k
  strval = xmlXPathCastNodeToString(cur);
4546
140k
  if (xmlHashLookup(hash, strval) == NULL) {
4547
11.6k
      xmlHashAddEntry(hash, strval, strval);
4548
            /* TODO: Propagate memory error. */
4549
11.6k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4550
0
          break;
4551
129k
  } else {
4552
129k
      xmlFree(strval);
4553
129k
  }
4554
140k
    }
4555
598
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4556
598
    return(ret);
4557
598
}
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
168
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4593
168
    int i, l;
4594
168
    xmlNodePtr cur;
4595
4596
168
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4597
168
  xmlXPathNodeSetIsEmpty(nodes2))
4598
75
  return(0);
4599
4600
93
    l = xmlXPathNodeSetGetLength(nodes1);
4601
515
    for (i = 0; i < l; i++) {
4602
483
  cur = xmlXPathNodeSetItem(nodes1, i);
4603
483
  if (xmlXPathNodeSetContains(nodes2, cur))
4604
61
      return(1);
4605
483
    }
4606
32
    return(0);
4607
93
}
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
203
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4623
203
    int i, l;
4624
203
    xmlNodePtr cur;
4625
203
    xmlNodeSetPtr ret;
4626
4627
203
    if (node == NULL)
4628
0
  return(nodes);
4629
4630
203
    ret = xmlXPathNodeSetCreate(NULL);
4631
203
    if (ret == NULL)
4632
0
        return(ret);
4633
203
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4634
203
  (!xmlXPathNodeSetContains(nodes, node)))
4635
95
  return(ret);
4636
4637
108
    l = xmlXPathNodeSetGetLength(nodes);
4638
831
    for (i = 0; i < l; i++) {
4639
831
  cur = xmlXPathNodeSetItem(nodes, i);
4640
831
  if (cur == node)
4641
108
      break;
4642
        /* TODO: Propagate memory error. */
4643
723
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4644
0
      break;
4645
723
    }
4646
108
    return(ret);
4647
203
}
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
186
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4729
186
    int i, l;
4730
186
    xmlNodePtr cur;
4731
186
    xmlNodeSetPtr ret;
4732
4733
186
    if (node == NULL)
4734
0
  return(nodes);
4735
4736
186
    ret = xmlXPathNodeSetCreate(NULL);
4737
186
    if (ret == NULL)
4738
0
        return(ret);
4739
186
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4740
186
  (!xmlXPathNodeSetContains(nodes, node)))
4741
81
  return(ret);
4742
4743
105
    l = xmlXPathNodeSetGetLength(nodes);
4744
1.03k
    for (i = l - 1; i >= 0; i--) {
4745
1.03k
  cur = xmlXPathNodeSetItem(nodes, i);
4746
1.03k
  if (cur == node)
4747
105
      break;
4748
        /* TODO: Propagate memory error. */
4749
929
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4750
0
      break;
4751
929
    }
4752
105
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4753
105
    return(ret);
4754
186
}
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
12.6M
         xmlXPathFunction f) {
4841
12.6M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4842
12.6M
}
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
13.1M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4858
13.1M
    if (ctxt == NULL)
4859
0
  return(-1);
4860
13.1M
    if (name == NULL)
4861
0
  return(-1);
4862
4863
13.1M
    if (ctxt->funcHash == NULL)
4864
0
  ctxt->funcHash = xmlHashCreate(0);
4865
13.1M
    if (ctxt->funcHash == NULL)
4866
0
  return(-1);
4867
13.1M
    if (f == NULL)
4868
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4869
13.1M
XML_IGNORE_FPTR_CAST_WARNINGS
4870
13.1M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4871
13.1M
XML_POP_WARNINGS
4872
13.1M
}
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.75k
          void *funcCtxt) {
4886
3.75k
    if (ctxt == NULL)
4887
0
  return;
4888
3.75k
    ctxt->funcLookupFunc = f;
4889
3.75k
    ctxt->funcLookupData = funcCtxt;
4890
3.75k
}
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
110k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4904
110k
    if (ctxt == NULL)
4905
0
  return (NULL);
4906
4907
110k
    if (ctxt->funcLookupFunc != NULL) {
4908
110k
  xmlXPathFunction ret;
4909
110k
  xmlXPathFuncLookupFunc f;
4910
4911
110k
  f = ctxt->funcLookupFunc;
4912
110k
  ret = f(ctxt->funcLookupData, name, NULL);
4913
110k
  if (ret != NULL)
4914
0
      return(ret);
4915
110k
    }
4916
110k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4917
110k
}
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
213k
       const xmlChar *ns_uri) {
4933
213k
    xmlXPathFunction ret;
4934
4935
213k
    if (ctxt == NULL)
4936
0
  return(NULL);
4937
213k
    if (name == NULL)
4938
0
  return(NULL);
4939
4940
213k
    if (ctxt->funcLookupFunc != NULL) {
4941
213k
  xmlXPathFuncLookupFunc f;
4942
4943
213k
  f = ctxt->funcLookupFunc;
4944
213k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4945
213k
  if (ret != NULL)
4946
101k
      return(ret);
4947
213k
    }
4948
4949
112k
    if (ctxt->funcHash == NULL)
4950
0
  return(NULL);
4951
4952
112k
XML_IGNORE_FPTR_CAST_WARNINGS
4953
112k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4954
112k
XML_POP_WARNINGS
4955
112k
    return(ret);
4956
112k
}
4957
4958
/**
4959
 * xmlXPathRegisteredFuncsCleanup:
4960
 * @ctxt:  the XPath context
4961
 *
4962
 * Cleanup the XPath context data associated to registered functions
4963
 */
4964
void
4965
460k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4966
460k
    if (ctxt == NULL)
4967
0
  return;
4968
4969
460k
    xmlHashFree(ctxt->funcHash, NULL);
4970
460k
    ctxt->funcHash = NULL;
4971
460k
}
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
15.0k
       xmlXPathObjectPtr value) {
4993
15.0k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4994
15.0k
}
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
15.0k
         xmlXPathObjectPtr value) {
5012
15.0k
    if (ctxt == NULL)
5013
0
  return(-1);
5014
15.0k
    if (name == NULL)
5015
0
  return(-1);
5016
5017
15.0k
    if (ctxt->varHash == NULL)
5018
3.75k
  ctxt->varHash = xmlHashCreate(0);
5019
15.0k
    if (ctxt->varHash == NULL)
5020
0
  return(-1);
5021
15.0k
    if (value == NULL)
5022
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5023
0
                             xmlXPathFreeObjectEntry));
5024
15.0k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5025
15.0k
             (void *) value, xmlXPathFreeObjectEntry));
5026
15.0k
}
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.75k
   xmlXPathVariableLookupFunc f, void *data) {
5039
3.75k
    if (ctxt == NULL)
5040
0
  return;
5041
3.75k
    ctxt->varLookupFunc = f;
5042
3.75k
    ctxt->varLookupData = data;
5043
3.75k
}
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
3.95k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5057
3.95k
    if (ctxt == NULL)
5058
0
  return(NULL);
5059
5060
3.95k
    if (ctxt->varLookupFunc != NULL) {
5061
3.95k
  xmlXPathObjectPtr ret;
5062
5063
3.95k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5064
3.95k
          (ctxt->varLookupData, name, NULL);
5065
3.95k
  return(ret);
5066
3.95k
    }
5067
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5068
3.95k
}
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
292
       const xmlChar *ns_uri) {
5084
292
    if (ctxt == NULL)
5085
0
  return(NULL);
5086
5087
292
    if (ctxt->varLookupFunc != NULL) {
5088
292
  xmlXPathObjectPtr ret;
5089
5090
292
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5091
292
          (ctxt->varLookupData, name, ns_uri);
5092
292
  if (ret != NULL) return(ret);
5093
292
    }
5094
5095
292
    if (ctxt->varHash == NULL)
5096
0
  return(NULL);
5097
292
    if (name == NULL)
5098
0
  return(NULL);
5099
5100
292
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5101
292
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5102
292
}
5103
5104
/**
5105
 * xmlXPathRegisteredVariablesCleanup:
5106
 * @ctxt:  the XPath context
5107
 *
5108
 * Cleanup the XPath context data associated to registered variables
5109
 */
5110
void
5111
460k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5112
460k
    if (ctxt == NULL)
5113
0
  return;
5114
5115
460k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5116
460k
    ctxt->varHash = NULL;
5117
460k
}
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
41.3k
         const xmlChar *ns_uri) {
5133
41.3k
    if (ctxt == NULL)
5134
0
  return(-1);
5135
41.3k
    if (prefix == NULL)
5136
0
  return(-1);
5137
41.3k
    if (prefix[0] == 0)
5138
0
  return(-1);
5139
5140
41.3k
    if (ctxt->nsHash == NULL)
5141
3.75k
  ctxt->nsHash = xmlHashCreate(10);
5142
41.3k
    if (ctxt->nsHash == NULL)
5143
0
  return(-1);
5144
41.3k
    if (ns_uri == NULL)
5145
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5146
0
                            xmlHashDefaultDeallocator));
5147
41.3k
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5148
41.3k
            xmlHashDefaultDeallocator));
5149
41.3k
}
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
1.71M
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5163
1.71M
    if (ctxt == NULL)
5164
0
  return(NULL);
5165
1.71M
    if (prefix == NULL)
5166
0
  return(NULL);
5167
5168
1.71M
#ifdef XML_XML_NAMESPACE
5169
1.71M
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5170
110
  return(XML_XML_NAMESPACE);
5171
1.71M
#endif
5172
5173
1.71M
    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
1.71M
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5184
1.71M
}
5185
5186
/**
5187
 * xmlXPathRegisteredNsCleanup:
5188
 * @ctxt:  the XPath context
5189
 *
5190
 * Cleanup the XPath context data associated to registered variables
5191
 */
5192
void
5193
460k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5194
460k
    if (ctxt == NULL)
5195
0
  return;
5196
5197
460k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5198
460k
    ctxt->nsHash = NULL;
5199
460k
}
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
561k
xmlXPathNewFloat(double val) {
5219
561k
    xmlXPathObjectPtr ret;
5220
5221
561k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5222
561k
    if (ret == NULL) {
5223
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5224
0
  return(NULL);
5225
0
    }
5226
561k
    memset(ret, 0 , sizeof(xmlXPathObject));
5227
561k
    ret->type = XPATH_NUMBER;
5228
561k
    ret->floatval = val;
5229
#ifdef XP_DEBUG_OBJ_USAGE
5230
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5231
#endif
5232
561k
    return(ret);
5233
561k
}
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
97.6k
xmlXPathNewBoolean(int val) {
5245
97.6k
    xmlXPathObjectPtr ret;
5246
5247
97.6k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248
97.6k
    if (ret == NULL) {
5249
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5250
0
  return(NULL);
5251
0
    }
5252
97.6k
    memset(ret, 0 , sizeof(xmlXPathObject));
5253
97.6k
    ret->type = XPATH_BOOLEAN;
5254
97.6k
    ret->boolval = (val != 0);
5255
#ifdef XP_DEBUG_OBJ_USAGE
5256
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5257
#endif
5258
97.6k
    return(ret);
5259
97.6k
}
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
641k
xmlXPathNewString(const xmlChar *val) {
5271
641k
    xmlXPathObjectPtr ret;
5272
5273
641k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5274
641k
    if (ret == NULL) {
5275
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5276
0
  return(NULL);
5277
0
    }
5278
641k
    memset(ret, 0 , sizeof(xmlXPathObject));
5279
641k
    ret->type = XPATH_STRING;
5280
641k
    if (val != NULL)
5281
641k
  ret->stringval = xmlStrdup(val);
5282
79
    else
5283
79
  ret->stringval = xmlStrdup((const xmlChar *)"");
5284
#ifdef XP_DEBUG_OBJ_USAGE
5285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5286
#endif
5287
641k
    return(ret);
5288
641k
}
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
923k
xmlXPathWrapString (xmlChar *val) {
5300
923k
    xmlXPathObjectPtr ret;
5301
5302
923k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5303
923k
    if (ret == NULL) {
5304
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5305
0
  return(NULL);
5306
0
    }
5307
923k
    memset(ret, 0 , sizeof(xmlXPathObject));
5308
923k
    ret->type = XPATH_STRING;
5309
923k
    ret->stringval = val;
5310
#ifdef XP_DEBUG_OBJ_USAGE
5311
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5312
#endif
5313
923k
    return(ret);
5314
923k
}
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
12.2k
xmlXPathNewCString(const char *val) {
5326
12.2k
    xmlXPathObjectPtr ret;
5327
5328
12.2k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5329
12.2k
    if (ret == NULL) {
5330
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5331
0
  return(NULL);
5332
0
    }
5333
12.2k
    memset(ret, 0 , sizeof(xmlXPathObject));
5334
12.2k
    ret->type = XPATH_STRING;
5335
12.2k
    ret->stringval = xmlStrdup(BAD_CAST val);
5336
#ifdef XP_DEBUG_OBJ_USAGE
5337
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5338
#endif
5339
12.2k
    return(ret);
5340
12.2k
}
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
350
xmlXPathWrapExternal (void *val) {
5365
350
    xmlXPathObjectPtr ret;
5366
5367
350
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5368
350
    if (ret == NULL) {
5369
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5370
0
  return(NULL);
5371
0
    }
5372
350
    memset(ret, 0 , sizeof(xmlXPathObject));
5373
350
    ret->type = XPATH_USERS;
5374
350
    ret->user = val;
5375
#ifdef XP_DEBUG_OBJ_USAGE
5376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5377
#endif
5378
350
    return(ret);
5379
350
}
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
1.82M
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5391
1.82M
    xmlXPathObjectPtr ret;
5392
5393
1.82M
    if (val == NULL)
5394
0
  return(NULL);
5395
5396
1.82M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5397
1.82M
    if (ret == NULL) {
5398
0
        xmlXPathErrMemory(NULL, "copying object\n");
5399
0
  return(NULL);
5400
0
    }
5401
1.82M
    memcpy(ret, val , sizeof(xmlXPathObject));
5402
#ifdef XP_DEBUG_OBJ_USAGE
5403
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5404
#endif
5405
1.82M
    switch (val->type) {
5406
0
  case XPATH_BOOLEAN:
5407
0
  case XPATH_NUMBER:
5408
#ifdef LIBXML_XPTR_LOCS_ENABLED
5409
  case XPATH_POINT:
5410
  case XPATH_RANGE:
5411
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5412
0
      break;
5413
0
  case XPATH_STRING:
5414
0
      ret->stringval = xmlStrdup(val->stringval);
5415
0
      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
1.82M
  case XPATH_NODESET:
5450
            /* TODO: Check memory error. */
5451
1.82M
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452
      /* Do not deallocate the copied tree value */
5453
1.82M
      ret->boolval = 0;
5454
1.82M
      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
1.82M
    }
5472
1.82M
    return(ret);
5473
1.82M
}
5474
5475
/**
5476
 * xmlXPathFreeObject:
5477
 * @obj:  the object to free
5478
 *
5479
 * Free up an xmlXPathObjectPtr object.
5480
 */
5481
void
5482
31.5M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483
31.5M
    if (obj == NULL) return;
5484
31.0M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485
22.6M
  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
22.6M
  } else {
5496
22.6M
      if (obj->nodesetval != NULL)
5497
20.7M
    xmlXPathFreeNodeSet(obj->nodesetval);
5498
22.6M
  }
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
22.6M
    } else if (obj->type == XPATH_STRING) {
5505
7.88M
  if (obj->stringval != NULL)
5506
7.88M
      xmlFree(obj->stringval);
5507
7.88M
    }
5508
#ifdef XP_DEBUG_OBJ_USAGE
5509
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510
#endif
5511
31.0M
    xmlFree(obj);
5512
31.0M
}
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
259M
{
5529
259M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5530
276k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5531
259M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5532
5533
316M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5534
5535
259M
    if (obj == NULL)
5536
0
  return;
5537
259M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5538
63.9k
   xmlXPathFreeObject(obj);
5539
259M
    } else {
5540
259M
  xmlXPathContextCachePtr cache =
5541
259M
      (xmlXPathContextCachePtr) ctxt->cache;
5542
5543
259M
  switch (obj->type) {
5544
123M
      case XPATH_NODESET:
5545
123M
      case XPATH_XSLT_TREE:
5546
123M
    if (obj->nodesetval != NULL) {
5547
112M
        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
112M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5557
112M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5558
112M
          cache->maxNodeset)))
5559
55.2M
        {
5560
55.2M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5561
55.2M
      goto obj_cached;
5562
57.3M
        } else {
5563
57.3M
      xmlXPathFreeNodeSet(obj->nodesetval);
5564
57.3M
      obj->nodesetval = NULL;
5565
57.3M
        }
5566
112M
    }
5567
68.7M
    break;
5568
68.7M
      case XPATH_STRING:
5569
36.4M
    if (obj->stringval != NULL)
5570
36.4M
        xmlFree(obj->stringval);
5571
5572
36.4M
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5573
36.4M
        XP_CACHE_ADD(cache->stringObjs, obj);
5574
36.4M
        goto obj_cached;
5575
36.4M
    }
5576
15.8k
    break;
5577
25.2M
      case XPATH_BOOLEAN:
5578
25.2M
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5579
25.2M
        XP_CACHE_ADD(cache->booleanObjs, obj);
5580
25.2M
        goto obj_cached;
5581
25.2M
    }
5582
6.78k
    break;
5583
73.8M
      case XPATH_NUMBER:
5584
73.8M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5585
73.8M
        XP_CACHE_ADD(cache->numberObjs, obj);
5586
73.8M
        goto obj_cached;
5587
73.8M
    }
5588
18.3k
    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
18.3k
      default:
5597
349
    goto free_obj;
5598
259M
  }
5599
5600
  /*
5601
  * Fallback to adding to the misc-objects slot.
5602
  */
5603
68.7M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5604
68.6M
      XP_CACHE_ADD(cache->miscObjs, obj);
5605
68.6M
  } else
5606
85.2k
      goto free_obj;
5607
5608
259M
obj_cached:
5609
5610
#ifdef XP_DEBUG_OBJ_USAGE
5611
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5612
#endif
5613
5614
259M
  if (obj->nodesetval != NULL) {
5615
55.2M
      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
55.2M
      if (tmpset->nodeNr > 1) {
5624
813k
    int i;
5625
813k
    xmlNodePtr node;
5626
5627
14.2M
    for (i = 0; i < tmpset->nodeNr; i++) {
5628
13.4M
        node = tmpset->nodeTab[i];
5629
13.4M
        if ((node != NULL) &&
5630
13.4M
      (node->type == XML_NAMESPACE_DECL))
5631
226k
        {
5632
226k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5633
226k
        }
5634
13.4M
    }
5635
54.4M
      } else if (tmpset->nodeNr == 1) {
5636
52.4M
    if ((tmpset->nodeTab[0] != NULL) &&
5637
52.4M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5638
6.04M
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5639
52.4M
      }
5640
55.2M
      tmpset->nodeNr = 0;
5641
55.2M
      memset(obj, 0, sizeof(xmlXPathObject));
5642
55.2M
      obj->nodesetval = tmpset;
5643
55.2M
  } else
5644
204M
      memset(obj, 0, sizeof(xmlXPathObject));
5645
5646
259M
  return;
5647
5648
85.6k
free_obj:
5649
  /*
5650
  * Cache is full; free the object.
5651
  */
5652
85.6k
  if (obj->nodesetval != NULL)
5653
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5654
#ifdef XP_DEBUG_OBJ_USAGE
5655
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5656
#endif
5657
85.6k
  xmlFree(obj);
5658
85.6k
    }
5659
149k
    return;
5660
259M
}
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
86.2k
xmlXPathCastBooleanToString (int val) {
5679
86.2k
    xmlChar *ret;
5680
86.2k
    if (val)
5681
63.5k
  ret = xmlStrdup((const xmlChar *) "true");
5682
22.7k
    else
5683
22.7k
  ret = xmlStrdup((const xmlChar *) "false");
5684
86.2k
    return(ret);
5685
86.2k
}
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
131k
xmlXPathCastNumberToString (double val) {
5697
131k
    xmlChar *ret;
5698
131k
    switch (xmlXPathIsInf(val)) {
5699
12.5k
    case 1:
5700
12.5k
  ret = xmlStrdup((const xmlChar *) "Infinity");
5701
12.5k
  break;
5702
1.91k
    case -1:
5703
1.91k
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5704
1.91k
  break;
5705
117k
    default:
5706
117k
  if (xmlXPathIsNaN(val)) {
5707
37.7k
      ret = xmlStrdup((const xmlChar *) "NaN");
5708
79.5k
  } else if (val == 0) {
5709
            /* Omit sign for negative zero. */
5710
50.2k
      ret = xmlStrdup((const xmlChar *) "0");
5711
50.2k
  } else {
5712
      /* could be improved */
5713
29.3k
      char buf[100];
5714
29.3k
      xmlXPathFormatNumber(val, buf, 99);
5715
29.3k
      buf[99] = 0;
5716
29.3k
      ret = xmlStrdup((const xmlChar *) buf);
5717
29.3k
  }
5718
131k
    }
5719
131k
    return(ret);
5720
131k
}
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
71.2M
xmlXPathCastNodeToString (xmlNodePtr node) {
5732
71.2M
xmlChar *ret;
5733
71.2M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5734
0
  ret = xmlStrdup((const xmlChar *) "");
5735
71.2M
    return(ret);
5736
71.2M
}
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
23.6M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5748
23.6M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5749
12.0M
  return(xmlStrdup((const xmlChar *) ""));
5750
5751
11.6M
    if (ns->nodeNr > 1)
5752
1.83M
  xmlXPathNodeSetSort(ns);
5753
11.6M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5754
23.6M
}
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
480k
xmlXPathCastToString(xmlXPathObjectPtr val) {
5767
480k
    xmlChar *ret = NULL;
5768
5769
480k
    if (val == NULL)
5770
0
  return(xmlStrdup((const xmlChar *) ""));
5771
480k
    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
34.9k
        case XPATH_NODESET:
5779
34.9k
        case XPATH_XSLT_TREE:
5780
34.9k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5781
34.9k
      break;
5782
354k
  case XPATH_STRING:
5783
354k
      return(xmlStrdup(val->stringval));
5784
22.5k
        case XPATH_BOOLEAN:
5785
22.5k
      ret = xmlXPathCastBooleanToString(val->boolval);
5786
22.5k
      break;
5787
68.4k
  case XPATH_NUMBER: {
5788
68.4k
      ret = xmlXPathCastNumberToString(val->floatval);
5789
68.4k
      break;
5790
34.9k
  }
5791
1
  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
1
      TODO
5798
1
      ret = xmlStrdup((const xmlChar *) "");
5799
1
      break;
5800
480k
    }
5801
125k
    return(ret);
5802
480k
}
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
82
xmlXPathConvertString(xmlXPathObjectPtr val) {
5815
82
    xmlChar *res = NULL;
5816
5817
82
    if (val == NULL)
5818
0
  return(xmlXPathNewCString(""));
5819
5820
82
    switch (val->type) {
5821
0
    case XPATH_UNDEFINED:
5822
#ifdef DEBUG_EXPR
5823
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5824
#endif
5825
0
  break;
5826
49
    case XPATH_NODESET:
5827
49
    case XPATH_XSLT_TREE:
5828
49
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5829
49
  break;
5830
0
    case XPATH_STRING:
5831
0
  return(val);
5832
15
    case XPATH_BOOLEAN:
5833
15
  res = xmlXPathCastBooleanToString(val->boolval);
5834
15
  break;
5835
18
    case XPATH_NUMBER:
5836
18
  res = xmlXPathCastNumberToString(val->floatval);
5837
18
  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
82
    }
5847
82
    xmlXPathFreeObject(val);
5848
82
    if (res == NULL)
5849
0
  return(xmlXPathNewCString(""));
5850
82
    return(xmlXPathWrapString(res));
5851
82
}
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
2.53M
xmlXPathCastBooleanToNumber(int val) {
5863
2.53M
    if (val)
5864
705k
  return(1.0);
5865
1.83M
    return(0.0);
5866
2.53M
}
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
79.1M
xmlXPathCastStringToNumber(const xmlChar * val) {
5878
79.1M
    return(xmlXPathStringEvalNumber(val));
5879
79.1M
}
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
27.9M
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5891
27.9M
    xmlChar *strval;
5892
27.9M
    double ret;
5893
5894
27.9M
    if (node == NULL)
5895
0
  return(xmlXPathNAN);
5896
27.9M
    strval = xmlXPathCastNodeToString(node);
5897
27.9M
    if (strval == NULL)
5898
0
  return(xmlXPathNAN);
5899
27.9M
    ret = xmlXPathCastStringToNumber(strval);
5900
27.9M
    xmlFree(strval);
5901
5902
27.9M
    return(ret);
5903
27.9M
}
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
19.8M
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5915
19.8M
    xmlChar *str;
5916
19.8M
    double ret;
5917
5918
19.8M
    if (ns == NULL)
5919
3.58M
  return(xmlXPathNAN);
5920
16.2M
    str = xmlXPathCastNodeSetToString(ns);
5921
16.2M
    ret = xmlXPathCastStringToNumber(str);
5922
16.2M
    xmlFree(str);
5923
16.2M
    return(ret);
5924
19.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
61.1M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5936
61.1M
    double ret = 0.0;
5937
5938
61.1M
    if (val == NULL)
5939
0
  return(xmlXPathNAN);
5940
61.1M
    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
19.8M
    case XPATH_NODESET:
5948
19.8M
    case XPATH_XSLT_TREE:
5949
19.8M
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5950
19.8M
  break;
5951
34.9M
    case XPATH_STRING:
5952
34.9M
  ret = xmlXPathCastStringToNumber(val->stringval);
5953
34.9M
  break;
5954
3.87M
    case XPATH_NUMBER:
5955
3.87M
  ret = val->floatval;
5956
3.87M
  break;
5957
2.53M
    case XPATH_BOOLEAN:
5958
2.53M
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5959
2.53M
  break;
5960
21
    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
21
  TODO;
5967
21
  ret = xmlXPathNAN;
5968
21
  break;
5969
61.1M
    }
5970
61.1M
    return(ret);
5971
61.1M
}
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
2.10M
xmlXPathCastNumberToBoolean (double val) {
6005
2.10M
     if (xmlXPathIsNaN(val) || (val == 0.0))
6006
919k
   return(0);
6007
1.18M
     return(1);
6008
2.10M
}
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
13.4k
xmlXPathCastStringToBoolean (const xmlChar *val) {
6020
13.4k
    if ((val == NULL) || (xmlStrlen(val) == 0))
6021
5.65k
  return(0);
6022
7.77k
    return(1);
6023
13.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
1.76M
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6035
1.76M
    if ((ns == NULL) || (ns->nodeNr == 0))
6036
974k
  return(0);
6037
786k
    return(1);
6038
1.76M
}
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
2.18M
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6050
2.18M
    int ret = 0;
6051
6052
2.18M
    if (val == NULL)
6053
0
  return(0);
6054
2.18M
    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
1.76M
    case XPATH_NODESET:
6062
1.76M
    case XPATH_XSLT_TREE:
6063
1.76M
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6064
1.76M
  break;
6065
13.4k
    case XPATH_STRING:
6066
13.4k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6067
13.4k
  break;
6068
415k
    case XPATH_NUMBER:
6069
415k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6070
415k
  break;
6071
0
    case XPATH_BOOLEAN:
6072
0
  ret = val->boolval;
6073
0
  break;
6074
10
    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
10
  TODO;
6081
10
  ret = 0;
6082
10
  break;
6083
2.18M
    }
6084
2.18M
    return(ret);
6085
2.18M
}
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
467k
xmlXPathNewContext(xmlDocPtr doc) {
6126
467k
    xmlXPathContextPtr ret;
6127
6128
467k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6129
467k
    if (ret == NULL) {
6130
0
        xmlXPathErrMemory(NULL, "creating context\n");
6131
0
  return(NULL);
6132
0
    }
6133
467k
    memset(ret, 0 , sizeof(xmlXPathContext));
6134
467k
    ret->doc = doc;
6135
467k
    ret->node = NULL;
6136
6137
467k
    ret->varHash = NULL;
6138
6139
467k
    ret->nb_types = 0;
6140
467k
    ret->max_types = 0;
6141
467k
    ret->types = NULL;
6142
6143
467k
    ret->funcHash = xmlHashCreate(0);
6144
6145
467k
    ret->nb_axis = 0;
6146
467k
    ret->max_axis = 0;
6147
467k
    ret->axis = NULL;
6148
6149
467k
    ret->nsHash = NULL;
6150
467k
    ret->user = NULL;
6151
6152
467k
    ret->contextSize = -1;
6153
467k
    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
467k
    xmlXPathRegisterAllFunctions(ret);
6163
6164
467k
    return(ret);
6165
467k
}
6166
6167
/**
6168
 * xmlXPathFreeContext:
6169
 * @ctxt:  the context to free
6170
 *
6171
 * Free up an xmlXPathContext
6172
 */
6173
void
6174
460k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175
460k
    if (ctxt == NULL) return;
6176
6177
460k
    if (ctxt->cache != NULL)
6178
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179
460k
    xmlXPathRegisteredNsCleanup(ctxt);
6180
460k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6181
460k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6182
460k
    xmlResetError(&ctxt->lastError);
6183
460k
    xmlFree(ctxt);
6184
460k
}
6185
6186
/************************************************************************
6187
 *                  *
6188
 *    Routines to handle XPath parser contexts    *
6189
 *                  *
6190
 ************************************************************************/
6191
6192
#define CHECK_CTXT(ctxt)            \
6193
3.85k
    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
225k
    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
686k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234
686k
    xmlXPathParserContextPtr ret;
6235
6236
686k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6237
686k
    if (ret == NULL) {
6238
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6239
0
  return(NULL);
6240
0
    }
6241
686k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6242
686k
    ret->cur = ret->base = str;
6243
686k
    ret->context = ctxt;
6244
6245
686k
    ret->comp = xmlXPathNewCompExpr();
6246
686k
    if (ret->comp == NULL) {
6247
0
  xmlFree(ret->valueTab);
6248
0
  xmlFree(ret);
6249
0
  return(NULL);
6250
0
    }
6251
686k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252
0
        ret->comp->dict = ctxt->dict;
6253
0
  xmlDictReference(ret->comp->dict);
6254
0
    }
6255
6256
686k
    return(ret);
6257
686k
}
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
225k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270
225k
    xmlXPathParserContextPtr ret;
6271
6272
225k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6273
225k
    if (ret == NULL) {
6274
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6275
0
  return(NULL);
6276
0
    }
6277
225k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6278
6279
    /* Allocate the value stack */
6280
225k
    ret->valueTab = (xmlXPathObjectPtr *)
6281
225k
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282
225k
    if (ret->valueTab == NULL) {
6283
0
  xmlFree(ret);
6284
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285
0
  return(NULL);
6286
0
    }
6287
225k
    ret->valueNr = 0;
6288
225k
    ret->valueMax = 10;
6289
225k
    ret->value = NULL;
6290
225k
    ret->valueFrame = 0;
6291
6292
225k
    ret->context = ctxt;
6293
225k
    ret->comp = comp;
6294
6295
225k
    return(ret);
6296
225k
}
6297
6298
/**
6299
 * xmlXPathFreeParserContext:
6300
 * @ctxt:  the context to free
6301
 *
6302
 * Free up an xmlXPathParserContext
6303
 */
6304
void
6305
912k
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6306
912k
    int i;
6307
6308
912k
    if (ctxt->valueTab != NULL) {
6309
860k
        for (i = 0; i < ctxt->valueNr; i++) {
6310
170k
            if (ctxt->context)
6311
170k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6312
0
            else
6313
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6314
170k
        }
6315
689k
        xmlFree(ctxt->valueTab);
6316
689k
    }
6317
912k
    if (ctxt->comp != NULL) {
6318
538k
#ifdef XPATH_STREAMING
6319
538k
  if (ctxt->comp->stream != NULL) {
6320
17
      xmlFreePatternList(ctxt->comp->stream);
6321
17
      ctxt->comp->stream = NULL;
6322
17
  }
6323
538k
#endif
6324
538k
  xmlXPathFreeCompExpr(ctxt->comp);
6325
538k
    }
6326
912k
    xmlFree(ctxt);
6327
912k
}
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
6.77M
xmlXPathNodeValHash(xmlNodePtr node) {
6346
6.77M
    int len = 2;
6347
6.77M
    const xmlChar * string = NULL;
6348
6.77M
    xmlNodePtr tmp = NULL;
6349
6.77M
    unsigned int ret = 0;
6350
6351
6.77M
    if (node == NULL)
6352
0
  return(0);
6353
6354
6.77M
    if (node->type == XML_DOCUMENT_NODE) {
6355
197k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6356
197k
  if (tmp == NULL)
6357
1
      node = node->children;
6358
197k
  else
6359
197k
      node = tmp;
6360
6361
197k
  if (node == NULL)
6362
0
      return(0);
6363
197k
    }
6364
6365
6.77M
    switch (node->type) {
6366
28.2k
  case XML_COMMENT_NODE:
6367
39.7k
  case XML_PI_NODE:
6368
65.5k
  case XML_CDATA_SECTION_NODE:
6369
881k
  case XML_TEXT_NODE:
6370
881k
      string = node->content;
6371
881k
      if (string == NULL)
6372
0
    return(0);
6373
881k
      if (string[0] == 0)
6374
16
    return(0);
6375
881k
      return(string[0] + (string[1] << 8));
6376
67.5k
  case XML_NAMESPACE_DECL:
6377
67.5k
      string = ((xmlNsPtr)node)->href;
6378
67.5k
      if (string == NULL)
6379
0
    return(0);
6380
67.5k
      if (string[0] == 0)
6381
0
    return(0);
6382
67.5k
      return(string[0] + (string[1] << 8));
6383
43.4k
  case XML_ATTRIBUTE_NODE:
6384
43.4k
      tmp = ((xmlAttrPtr) node)->children;
6385
43.4k
      break;
6386
5.77M
  case XML_ELEMENT_NODE:
6387
5.77M
      tmp = node->children;
6388
5.77M
      break;
6389
0
  default:
6390
0
      return(0);
6391
6.77M
    }
6392
10.9M
    while (tmp != NULL) {
6393
5.71M
  switch (tmp->type) {
6394
45.2k
      case XML_CDATA_SECTION_NODE:
6395
5.71M
      case XML_TEXT_NODE:
6396
5.71M
    string = tmp->content;
6397
5.71M
    break;
6398
0
      default:
6399
0
                string = NULL;
6400
0
    break;
6401
5.71M
  }
6402
5.71M
  if ((string != NULL) && (string[0] != 0)) {
6403
5.71M
      if (len == 1) {
6404
0
    return(ret + (string[0] << 8));
6405
0
      }
6406
5.71M
      if (string[1] == 0) {
6407
5.09M
    len = 1;
6408
5.09M
    ret = string[0];
6409
5.09M
      } else {
6410
619k
    return(string[0] + (string[1] << 8));
6411
619k
      }
6412
5.71M
  }
6413
  /*
6414
   * Skip to next node
6415
   */
6416
5.09M
  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
5.09M
  if (tmp == node)
6423
0
      break;
6424
6425
5.09M
  if (tmp->next != NULL) {
6426
0
      tmp = tmp->next;
6427
0
      continue;
6428
0
  }
6429
6430
5.09M
  do {
6431
5.09M
      tmp = tmp->parent;
6432
5.09M
      if (tmp == NULL)
6433
0
    break;
6434
5.09M
      if (tmp == node) {
6435
5.09M
    tmp = NULL;
6436
5.09M
    break;
6437
5.09M
      }
6438
0
      if (tmp->next != NULL) {
6439
0
    tmp = tmp->next;
6440
0
    break;
6441
0
      }
6442
0
  } while (tmp != NULL);
6443
5.09M
    }
6444
5.20M
    return(ret);
6445
5.82M
}
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
106k
xmlXPathStringHash(const xmlChar * string) {
6458
106k
    if (string == NULL)
6459
0
  return(0);
6460
106k
    if (string[0] == 0)
6461
2.25k
  return(0);
6462
104k
    return(string[0] + (string[1] << 8));
6463
106k
}
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
908k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6490
908k
    int i, ret = 0;
6491
908k
    xmlNodeSetPtr ns;
6492
908k
    xmlChar *str2;
6493
6494
908k
    if ((f == NULL) || (arg == NULL) ||
6495
908k
  ((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
908k
    ns = arg->nodesetval;
6501
908k
    if (ns != NULL) {
6502
8.91M
  for (i = 0;i < ns->nodeNr;i++) {
6503
8.26M
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6504
8.26M
       if (str2 != NULL) {
6505
8.26M
     valuePush(ctxt,
6506
8.26M
         xmlXPathCacheNewString(ctxt->context, str2));
6507
8.26M
     xmlFree(str2);
6508
8.26M
     xmlXPathNumberFunction(ctxt, 1);
6509
8.26M
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6510
8.26M
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6511
8.26M
     if (ret)
6512
85.5k
         break;
6513
8.26M
       }
6514
8.26M
  }
6515
741k
    }
6516
908k
    xmlXPathReleaseObject(ctxt->context, arg);
6517
908k
    xmlXPathReleaseObject(ctxt->context, f);
6518
908k
    return(ret);
6519
908k
}
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
255k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6545
255k
    int i, ret = 0;
6546
255k
    xmlNodeSetPtr ns;
6547
255k
    xmlChar *str2;
6548
6549
255k
    if ((s == NULL) || (arg == NULL) ||
6550
255k
  ((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
255k
    ns = arg->nodesetval;
6556
255k
    if (ns != NULL) {
6557
2.30M
  for (i = 0;i < ns->nodeNr;i++) {
6558
2.08M
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6559
2.08M
       if (str2 != NULL) {
6560
2.08M
     valuePush(ctxt,
6561
2.08M
         xmlXPathCacheNewString(ctxt->context, str2));
6562
2.08M
     xmlFree(str2);
6563
2.08M
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6564
2.08M
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6565
2.08M
     if (ret)
6566
3.41k
         break;
6567
2.08M
       }
6568
2.08M
  }
6569
223k
    }
6570
255k
    xmlXPathReleaseObject(ctxt->context, arg);
6571
255k
    xmlXPathReleaseObject(ctxt->context, s);
6572
255k
    return(ret);
6573
255k
}
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
3.79M
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6606
3.79M
    int i, j, init = 0;
6607
3.79M
    double val1;
6608
3.79M
    double *values2;
6609
3.79M
    int ret = 0;
6610
3.79M
    xmlNodeSetPtr ns1;
6611
3.79M
    xmlNodeSetPtr ns2;
6612
6613
3.79M
    if ((arg1 == NULL) ||
6614
3.79M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6615
0
  xmlXPathFreeObject(arg2);
6616
0
        return(0);
6617
0
    }
6618
3.79M
    if ((arg2 == NULL) ||
6619
3.79M
  ((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
3.79M
    ns1 = arg1->nodesetval;
6626
3.79M
    ns2 = arg2->nodesetval;
6627
6628
3.79M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6629
2.14M
  xmlXPathFreeObject(arg1);
6630
2.14M
  xmlXPathFreeObject(arg2);
6631
2.14M
  return(0);
6632
2.14M
    }
6633
1.64M
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6634
1.02M
  xmlXPathFreeObject(arg1);
6635
1.02M
  xmlXPathFreeObject(arg2);
6636
1.02M
  return(0);
6637
1.02M
    }
6638
6639
617k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6640
617k
    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
22.2M
    for (i = 0;i < ns1->nodeNr;i++) {
6648
21.6M
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6649
21.6M
  if (xmlXPathIsNaN(val1))
6650
18.8M
      continue;
6651
3.11G
  for (j = 0;j < ns2->nodeNr;j++) {
6652
3.11G
      if (init == 0) {
6653
5.96M
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6654
5.96M
      }
6655
3.11G
      if (xmlXPathIsNaN(values2[j]))
6656
336M
    continue;
6657
2.77G
      if (inf && strict)
6658
806M
    ret = (val1 < values2[j]);
6659
1.96G
      else if (inf && !strict)
6660
62.2k
    ret = (val1 <= values2[j]);
6661
1.96G
      else if (!inf && strict)
6662
1.96G
    ret = (val1 > values2[j]);
6663
57.0k
      else if (!inf && !strict)
6664
57.0k
    ret = (val1 >= values2[j]);
6665
2.77G
      if (ret)
6666
61.5k
    break;
6667
2.77G
  }
6668
2.76M
  if (ret)
6669
61.5k
      break;
6670
2.69M
  init = 1;
6671
2.69M
    }
6672
617k
    xmlFree(values2);
6673
617k
    xmlXPathFreeObject(arg1);
6674
617k
    xmlXPathFreeObject(arg2);
6675
617k
    return(ret);
6676
617k
}
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
2.27M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6702
2.27M
    if ((val == NULL) || (arg == NULL) ||
6703
2.27M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6704
0
        return(0);
6705
6706
2.27M
    switch(val->type) {
6707
908k
        case XPATH_NUMBER:
6708
908k
      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
255k
        case XPATH_STRING:
6713
255k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6714
1.11M
        case XPATH_BOOLEAN:
6715
1.11M
      valuePush(ctxt, arg);
6716
1.11M
      xmlXPathBooleanFunction(ctxt, 1);
6717
1.11M
      valuePush(ctxt, val);
6718
1.11M
      return(xmlXPathCompareValues(ctxt, inf, strict));
6719
8
  default:
6720
8
            xmlGenericError(xmlGenericErrorContext,
6721
8
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6722
8
                    "and object of type %d\n",
6723
8
                    val->type);
6724
8
            xmlXPathReleaseObject(ctxt->context, arg);
6725
8
            xmlXPathReleaseObject(ctxt->context, val);
6726
8
            XP_ERROR0(XPATH_INVALID_TYPE);
6727
2.27M
    }
6728
0
    return(0);
6729
2.27M
}
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
514k
{
6748
514k
    int i;
6749
514k
    xmlNodeSetPtr ns;
6750
514k
    xmlChar *str2;
6751
514k
    unsigned int hash;
6752
6753
514k
    if ((str == NULL) || (arg == NULL) ||
6754
514k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6755
0
        return (0);
6756
514k
    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
514k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6762
408k
        return (0);
6763
106k
    hash = xmlXPathStringHash(str);
6764
4.30M
    for (i = 0; i < ns->nodeNr; i++) {
6765
4.26M
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6766
61.3k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6767
61.3k
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6768
38.9k
                xmlFree(str2);
6769
38.9k
    if (neq)
6770
13
        continue;
6771
38.9k
                return (1);
6772
38.9k
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6773
0
    if (neq)
6774
0
        continue;
6775
0
                return (1);
6776
22.3k
            } else if (neq) {
6777
7.47k
    if (str2 != NULL)
6778
7.47k
        xmlFree(str2);
6779
7.47k
    return (1);
6780
7.47k
      }
6781
14.8k
            if (str2 != NULL)
6782
14.8k
                xmlFree(str2);
6783
4.19M
        } else if (neq)
6784
15.9k
      return (1);
6785
4.26M
    }
6786
44.0k
    return (0);
6787
106k
}
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.99M
    xmlXPathObjectPtr arg, double f, int neq) {
6807
3.99M
  int i, ret=0;
6808
3.99M
  xmlNodeSetPtr ns;
6809
3.99M
  xmlChar *str2;
6810
3.99M
  xmlXPathObjectPtr val;
6811
3.99M
  double v;
6812
6813
3.99M
    if ((arg == NULL) ||
6814
3.99M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6815
0
        return(0);
6816
6817
3.99M
    ns = arg->nodesetval;
6818
3.99M
    if (ns != NULL) {
6819
24.0M
  for (i=0;i<ns->nodeNr;i++) {
6820
20.2M
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6821
20.2M
      if (str2 != NULL) {
6822
20.2M
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6823
20.2M
    xmlFree(str2);
6824
20.2M
    xmlXPathNumberFunction(ctxt, 1);
6825
20.2M
    val = valuePop(ctxt);
6826
20.2M
    v = val->floatval;
6827
20.2M
    xmlXPathReleaseObject(ctxt->context, val);
6828
20.2M
    if (!xmlXPathIsNaN(v)) {
6829
3.27M
        if ((!neq) && (v==f)) {
6830
16.9k
      ret = 1;
6831
16.9k
      break;
6832
3.25M
        } else if ((neq) && (v!=f)) {
6833
28.4k
      ret = 1;
6834
28.4k
      break;
6835
28.4k
        }
6836
17.0M
    } else { /* NaN is unequal to any value */
6837
17.0M
        if (neq)
6838
448k
      ret = 1;
6839
17.0M
    }
6840
20.2M
      }
6841
20.2M
  }
6842
3.75M
    }
6843
6844
3.99M
    return(ret);
6845
3.99M
}
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.08M
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6867
2.08M
    int i, j;
6868
2.08M
    unsigned int *hashs1;
6869
2.08M
    unsigned int *hashs2;
6870
2.08M
    xmlChar **values1;
6871
2.08M
    xmlChar **values2;
6872
2.08M
    int ret = 0;
6873
2.08M
    xmlNodeSetPtr ns1;
6874
2.08M
    xmlNodeSetPtr ns2;
6875
6876
2.08M
    if ((arg1 == NULL) ||
6877
2.08M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6878
0
        return(0);
6879
2.08M
    if ((arg2 == NULL) ||
6880
2.08M
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6881
0
        return(0);
6882
6883
2.08M
    ns1 = arg1->nodesetval;
6884
2.08M
    ns2 = arg2->nodesetval;
6885
6886
2.08M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6887
920k
  return(0);
6888
1.16M
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6889
854k
  return(0);
6890
6891
    /*
6892
     * for equal, check if there is a node pertaining to both sets
6893
     */
6894
306k
    if (neq == 0)
6895
1.63M
  for (i = 0;i < ns1->nodeNr;i++)
6896
80.3M
      for (j = 0;j < ns2->nodeNr;j++)
6897
78.9M
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6898
66.3k
        return(1);
6899
6900
239k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6901
239k
    if (values1 == NULL) {
6902
        /* TODO: Propagate memory error. */
6903
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6904
0
  return(0);
6905
0
    }
6906
239k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6907
239k
    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
239k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6914
239k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6915
239k
    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
239k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6923
239k
    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
239k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932
804k
    for (i = 0;i < ns1->nodeNr;i++) {
6933
670k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934
3.15M
  for (j = 0;j < ns2->nodeNr;j++) {
6935
2.59M
      if (i == 0)
6936
1.84M
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937
2.59M
      if (hashs1[i] != hashs2[j]) {
6938
2.24M
    if (neq) {
6939
18.8k
        ret = 1;
6940
18.8k
        break;
6941
18.8k
    }
6942
2.24M
      }
6943
348k
      else {
6944
348k
    if (values1[i] == NULL)
6945
250k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946
348k
    if (values2[j] == NULL)
6947
245k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948
348k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949
348k
    if (ret)
6950
86.7k
        break;
6951
348k
      }
6952
2.59M
  }
6953
670k
  if (ret)
6954
105k
      break;
6955
670k
    }
6956
1.89M
    for (i = 0;i < ns1->nodeNr;i++)
6957
1.65M
  if (values1[i] != NULL)
6958
250k
      xmlFree(values1[i]);
6959
3.24M
    for (j = 0;j < ns2->nodeNr;j++)
6960
3.00M
  if (values2[j] != NULL)
6961
245k
      xmlFree(values2[j]);
6962
239k
    xmlFree(values1);
6963
239k
    xmlFree(values2);
6964
239k
    xmlFree(hashs1);
6965
239k
    xmlFree(hashs2);
6966
239k
    return(ret);
6967
239k
}
6968
6969
static int
6970
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971
8.42M
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972
8.42M
    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
8.42M
    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.09M
        case XPATH_BOOLEAN:
6985
2.09M
      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
672k
    case XPATH_BOOLEAN:
6993
#ifdef DEBUG_EXPR
6994
        xmlGenericError(xmlGenericErrorContext,
6995
          "Equal: %d boolean %d \n",
6996
          arg1->boolval, arg2->boolval);
6997
#endif
6998
672k
        ret = (arg1->boolval == arg2->boolval);
6999
672k
        break;
7000
1.28M
    case XPATH_NUMBER:
7001
1.28M
        ret = (arg1->boolval ==
7002
1.28M
         xmlXPathCastNumberToBoolean(arg2->floatval));
7003
1.28M
        break;
7004
137k
    case XPATH_STRING:
7005
137k
        if ((arg2->stringval == NULL) ||
7006
137k
      (arg2->stringval[0] == 0)) ret = 0;
7007
136k
        else
7008
136k
      ret = 1;
7009
137k
        ret = (arg1->boolval == ret);
7010
137k
        break;
7011
20
    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
20
        TODO
7018
20
        break;
7019
0
    case XPATH_NODESET:
7020
0
    case XPATH_XSLT_TREE:
7021
0
        break;
7022
2.09M
      }
7023
2.09M
      break;
7024
5.05M
        case XPATH_NUMBER:
7025
5.05M
      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
409k
    case XPATH_BOOLEAN:
7033
409k
        ret = (arg2->boolval==
7034
409k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7035
409k
        break;
7036
493k
    case XPATH_STRING:
7037
493k
        valuePush(ctxt, arg2);
7038
493k
        xmlXPathNumberFunction(ctxt, 1);
7039
493k
        arg2 = valuePop(ctxt);
7040
                    /* Falls through. */
7041
4.64M
    case XPATH_NUMBER:
7042
        /* Hand check NaN and Infinity equalities */
7043
4.64M
        if (xmlXPathIsNaN(arg1->floatval) ||
7044
4.64M
          xmlXPathIsNaN(arg2->floatval)) {
7045
815k
            ret = 0;
7046
3.82M
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047
12.4k
            if (xmlXPathIsInf(arg2->floatval) == 1)
7048
258
          ret = 1;
7049
12.1k
      else
7050
12.1k
          ret = 0;
7051
3.81M
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052
13.8k
      if (xmlXPathIsInf(arg2->floatval) == -1)
7053
4
          ret = 1;
7054
13.8k
      else
7055
13.8k
          ret = 0;
7056
3.80M
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057
9.03k
      if (xmlXPathIsInf(arg1->floatval) == 1)
7058
0
          ret = 1;
7059
9.03k
      else
7060
9.03k
          ret = 0;
7061
3.79M
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062
506
      if (xmlXPathIsInf(arg1->floatval) == -1)
7063
0
          ret = 1;
7064
506
      else
7065
506
          ret = 0;
7066
3.79M
        } else {
7067
3.79M
            ret = (arg1->floatval == arg2->floatval);
7068
3.79M
        }
7069
4.64M
        break;
7070
4
    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
4
        TODO
7077
4
        break;
7078
0
    case XPATH_NODESET:
7079
0
    case XPATH_XSLT_TREE:
7080
0
        break;
7081
5.05M
      }
7082
5.05M
      break;
7083
5.05M
        case XPATH_STRING:
7084
1.27M
      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
15.5k
    case XPATH_BOOLEAN:
7092
15.5k
        if ((arg1->stringval == NULL) ||
7093
15.5k
      (arg1->stringval[0] == 0)) ret = 0;
7094
15.3k
        else
7095
15.3k
      ret = 1;
7096
15.5k
        ret = (arg2->boolval == ret);
7097
15.5k
        break;
7098
60.0k
    case XPATH_STRING:
7099
60.0k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7100
60.0k
        break;
7101
1.20M
    case XPATH_NUMBER:
7102
1.20M
        valuePush(ctxt, arg1);
7103
1.20M
        xmlXPathNumberFunction(ctxt, 1);
7104
1.20M
        arg1 = valuePop(ctxt);
7105
        /* Hand check NaN and Infinity equalities */
7106
1.20M
        if (xmlXPathIsNaN(arg1->floatval) ||
7107
1.20M
          xmlXPathIsNaN(arg2->floatval)) {
7108
1.20M
            ret = 0;
7109
1.20M
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7110
35
      if (xmlXPathIsInf(arg2->floatval) == 1)
7111
0
          ret = 1;
7112
35
      else
7113
35
          ret = 0;
7114
964
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7115
1
      if (xmlXPathIsInf(arg2->floatval) == -1)
7116
0
          ret = 1;
7117
1
      else
7118
1
          ret = 0;
7119
963
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7120
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7121
0
          ret = 1;
7122
0
      else
7123
0
          ret = 0;
7124
963
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7125
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7126
0
          ret = 1;
7127
0
      else
7128
0
          ret = 0;
7129
963
        } else {
7130
963
            ret = (arg1->floatval == arg2->floatval);
7131
963
        }
7132
1.20M
        break;
7133
0
    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
0
        TODO
7140
0
        break;
7141
0
    case XPATH_NODESET:
7142
0
    case XPATH_XSLT_TREE:
7143
0
        break;
7144
1.27M
      }
7145
1.27M
      break;
7146
1.27M
        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
16
      TODO
7153
16
      break;
7154
0
  case XPATH_NODESET:
7155
0
  case XPATH_XSLT_TREE:
7156
0
      break;
7157
8.42M
    }
7158
8.42M
    xmlXPathReleaseObject(ctxt->context, arg1);
7159
8.42M
    xmlXPathReleaseObject(ctxt->context, arg2);
7160
8.42M
    return(ret);
7161
8.42M
}
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
14.0M
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7173
14.0M
    xmlXPathObjectPtr arg1, arg2, argtmp;
7174
14.0M
    int ret = 0;
7175
7176
14.0M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7177
14.0M
    arg2 = valuePop(ctxt);
7178
14.0M
    arg1 = valuePop(ctxt);
7179
14.0M
    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
14.0M
    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
14.0M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7200
14.0M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7201
  /*
7202
   *Hack it to assure arg1 is the nodeset
7203
   */
7204
7.02M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7205
2.03M
    argtmp = arg2;
7206
2.03M
    arg2 = arg1;
7207
2.03M
    arg1 = argtmp;
7208
2.03M
  }
7209
7.02M
  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
1.89M
      case XPATH_NODESET:
7217
1.89M
      case XPATH_XSLT_TREE:
7218
1.89M
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7219
1.89M
    break;
7220
1.00M
      case XPATH_BOOLEAN:
7221
1.00M
    if ((arg1->nodesetval == NULL) ||
7222
1.00M
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7223
209k
    else
7224
209k
        ret = 1;
7225
1.00M
    ret = (ret == arg2->boolval);
7226
1.00M
    break;
7227
3.73M
      case XPATH_NUMBER:
7228
3.73M
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7229
3.73M
    break;
7230
401k
      case XPATH_STRING:
7231
401k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7232
401k
    break;
7233
20
      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
20
    TODO
7240
20
    break;
7241
7.02M
  }
7242
7.02M
  xmlXPathReleaseObject(ctxt->context, arg1);
7243
7.02M
  xmlXPathReleaseObject(ctxt->context, arg2);
7244
7.02M
  return(ret);
7245
7.02M
    }
7246
7247
7.05M
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248
14.0M
}
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
2.00M
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260
2.00M
    xmlXPathObjectPtr arg1, arg2, argtmp;
7261
2.00M
    int ret = 0;
7262
7263
2.00M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264
2.00M
    arg2 = valuePop(ctxt);
7265
2.00M
    arg1 = valuePop(ctxt);
7266
2.00M
    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
2.00M
    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
2.00M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287
2.00M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288
  /*
7289
   *Hack it to assure arg1 is the nodeset
7290
   */
7291
638k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292
182k
    argtmp = arg2;
7293
182k
    arg2 = arg1;
7294
182k
    arg1 = argtmp;
7295
182k
  }
7296
638k
  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
189k
      case XPATH_NODESET:
7304
189k
      case XPATH_XSLT_TREE:
7305
189k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306
189k
    break;
7307
75.7k
      case XPATH_BOOLEAN:
7308
75.7k
    if ((arg1->nodesetval == NULL) ||
7309
75.7k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7310
12.4k
    else
7311
12.4k
        ret = 1;
7312
75.7k
    ret = (ret != arg2->boolval);
7313
75.7k
    break;
7314
260k
      case XPATH_NUMBER:
7315
260k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316
260k
    break;
7317
112k
      case XPATH_STRING:
7318
112k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319
112k
    break;
7320
0
      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
0
    TODO
7327
0
    break;
7328
638k
  }
7329
638k
  xmlXPathReleaseObject(ctxt->context, arg1);
7330
638k
  xmlXPathReleaseObject(ctxt->context, arg2);
7331
638k
  return(ret);
7332
638k
    }
7333
7334
1.36M
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7335
2.00M
}
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
18.4M
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7363
18.4M
    int ret = 0, arg1i = 0, arg2i = 0;
7364
18.4M
    xmlXPathObjectPtr arg1, arg2;
7365
7366
18.4M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7367
18.4M
    arg2 = valuePop(ctxt);
7368
18.4M
    arg1 = valuePop(ctxt);
7369
18.4M
    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
18.4M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7378
18.4M
      (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
6.07M
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7385
6.07M
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7386
3.79M
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7387
3.79M
  } else {
7388
2.27M
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7389
680k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7390
680k
                                arg1, arg2);
7391
1.59M
      } else {
7392
1.59M
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7393
1.59M
                                arg2, arg1);
7394
1.59M
      }
7395
2.27M
  }
7396
6.07M
  return(ret);
7397
6.07M
    }
7398
7399
12.4M
    if (arg1->type != XPATH_NUMBER) {
7400
3.52M
  valuePush(ctxt, arg1);
7401
3.52M
  xmlXPathNumberFunction(ctxt, 1);
7402
3.52M
  arg1 = valuePop(ctxt);
7403
3.52M
    }
7404
12.4M
    if (arg1->type != XPATH_NUMBER) {
7405
0
  xmlXPathFreeObject(arg1);
7406
0
  xmlXPathFreeObject(arg2);
7407
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7408
0
    }
7409
12.4M
    if (arg2->type != XPATH_NUMBER) {
7410
3.20M
  valuePush(ctxt, arg2);
7411
3.20M
  xmlXPathNumberFunction(ctxt, 1);
7412
3.20M
  arg2 = valuePop(ctxt);
7413
3.20M
    }
7414
12.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
12.4M
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7425
10.7M
  ret=0;
7426
10.7M
    } else {
7427
1.64M
  arg1i=xmlXPathIsInf(arg1->floatval);
7428
1.64M
  arg2i=xmlXPathIsInf(arg2->floatval);
7429
1.64M
  if (inf && strict) {
7430
457k
      if ((arg1i == -1 && arg2i != -1) ||
7431
457k
    (arg2i == 1 && arg1i != 1)) {
7432
17.4k
    ret = 1;
7433
439k
      } else if (arg1i == 0 && arg2i == 0) {
7434
439k
    ret = (arg1->floatval < arg2->floatval);
7435
439k
      } else {
7436
48
    ret = 0;
7437
48
      }
7438
457k
  }
7439
1.19M
  else if (inf && !strict) {
7440
353k
      if (arg1i == -1 || arg2i == 1) {
7441
5.82k
    ret = 1;
7442
347k
      } else if (arg1i == 0 && arg2i == 0) {
7443
347k
    ret = (arg1->floatval <= arg2->floatval);
7444
347k
      } else {
7445
146
    ret = 0;
7446
146
      }
7447
353k
  }
7448
838k
  else if (!inf && strict) {
7449
639k
      if ((arg1i == 1 && arg2i != 1) ||
7450
639k
    (arg2i == -1 && arg1i != -1)) {
7451
14.5k
    ret = 1;
7452
625k
      } else if (arg1i == 0 && arg2i == 0) {
7453
624k
    ret = (arg1->floatval > arg2->floatval);
7454
624k
      } else {
7455
274
    ret = 0;
7456
274
      }
7457
639k
  }
7458
198k
  else if (!inf && !strict) {
7459
198k
      if (arg1i == 1 || arg2i == -1) {
7460
12.1k
    ret = 1;
7461
186k
      } else if (arg1i == 0 && arg2i == 0) {
7462
186k
    ret = (arg1->floatval >= arg2->floatval);
7463
186k
      } else {
7464
156
    ret = 0;
7465
156
      }
7466
198k
  }
7467
1.64M
    }
7468
12.4M
    xmlXPathReleaseObject(ctxt->context, arg1);
7469
12.4M
    xmlXPathReleaseObject(ctxt->context, arg2);
7470
12.4M
    return(ret);
7471
12.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.14M
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7483
1.14M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7484
1.14M
    CAST_TO_NUMBER;
7485
1.14M
    CHECK_TYPE(XPATH_NUMBER);
7486
1.14M
    ctxt->value->floatval = -ctxt->value->floatval;
7487
1.14M
}
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
669k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7499
669k
    xmlXPathObjectPtr arg;
7500
669k
    double val;
7501
7502
669k
    arg = valuePop(ctxt);
7503
669k
    if (arg == NULL)
7504
669k
  XP_ERROR(XPATH_INVALID_OPERAND);
7505
669k
    val = xmlXPathCastToNumber(arg);
7506
669k
    xmlXPathReleaseObject(ctxt->context, arg);
7507
669k
    CAST_TO_NUMBER;
7508
669k
    CHECK_TYPE(XPATH_NUMBER);
7509
669k
    ctxt->value->floatval += val;
7510
669k
}
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
1.43M
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7522
1.43M
    xmlXPathObjectPtr arg;
7523
1.43M
    double val;
7524
7525
1.43M
    arg = valuePop(ctxt);
7526
1.43M
    if (arg == NULL)
7527
1.43M
  XP_ERROR(XPATH_INVALID_OPERAND);
7528
1.43M
    val = xmlXPathCastToNumber(arg);
7529
1.43M
    xmlXPathReleaseObject(ctxt->context, arg);
7530
1.43M
    CAST_TO_NUMBER;
7531
1.43M
    CHECK_TYPE(XPATH_NUMBER);
7532
1.43M
    ctxt->value->floatval -= val;
7533
1.43M
}
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
13.8M
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7545
13.8M
    xmlXPathObjectPtr arg;
7546
13.8M
    double val;
7547
7548
13.8M
    arg = valuePop(ctxt);
7549
13.8M
    if (arg == NULL)
7550
13.8M
  XP_ERROR(XPATH_INVALID_OPERAND);
7551
13.8M
    val = xmlXPathCastToNumber(arg);
7552
13.8M
    xmlXPathReleaseObject(ctxt->context, arg);
7553
13.8M
    CAST_TO_NUMBER;
7554
13.8M
    CHECK_TYPE(XPATH_NUMBER);
7555
13.8M
    ctxt->value->floatval *= val;
7556
13.8M
}
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
90.7k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7569
90.7k
    xmlXPathObjectPtr arg;
7570
90.7k
    double val;
7571
7572
90.7k
    arg = valuePop(ctxt);
7573
90.7k
    if (arg == NULL)
7574
90.7k
  XP_ERROR(XPATH_INVALID_OPERAND);
7575
90.7k
    val = xmlXPathCastToNumber(arg);
7576
90.7k
    xmlXPathReleaseObject(ctxt->context, arg);
7577
90.7k
    CAST_TO_NUMBER;
7578
90.7k
    CHECK_TYPE(XPATH_NUMBER);
7579
90.7k
    ctxt->value->floatval /= val;
7580
90.7k
}
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
93.4k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7592
93.4k
    xmlXPathObjectPtr arg;
7593
93.4k
    double arg1, arg2;
7594
7595
93.4k
    arg = valuePop(ctxt);
7596
93.4k
    if (arg == NULL)
7597
93.4k
  XP_ERROR(XPATH_INVALID_OPERAND);
7598
93.4k
    arg2 = xmlXPathCastToNumber(arg);
7599
93.4k
    xmlXPathReleaseObject(ctxt->context, arg);
7600
93.4k
    CAST_TO_NUMBER;
7601
93.4k
    CHECK_TYPE(XPATH_NUMBER);
7602
93.4k
    arg1 = ctxt->value->floatval;
7603
93.4k
    if (arg2 == 0)
7604
4.40k
  ctxt->value->floatval = xmlXPathNAN;
7605
89.0k
    else {
7606
89.0k
  ctxt->value->floatval = fmod(arg1, arg2);
7607
89.0k
    }
7608
93.4k
}
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
1.28M
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7654
1.28M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7655
1.28M
    if (cur == NULL)
7656
641k
        return(ctxt->context->node);
7657
641k
    return(NULL);
7658
1.28M
}
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
32.7M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7672
32.7M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7673
32.7M
    if (cur == NULL) {
7674
9.85M
  if (ctxt->context->node == NULL) return(NULL);
7675
9.85M
  switch (ctxt->context->node->type) {
7676
5.34M
            case XML_ELEMENT_NODE:
7677
9.38M
            case XML_TEXT_NODE:
7678
9.44M
            case XML_CDATA_SECTION_NODE:
7679
9.44M
            case XML_ENTITY_REF_NODE:
7680
9.44M
            case XML_ENTITY_NODE:
7681
9.53M
            case XML_PI_NODE:
7682
9.65M
            case XML_COMMENT_NODE:
7683
9.65M
            case XML_NOTATION_NODE:
7684
9.65M
            case XML_DTD_NODE:
7685
9.65M
    return(ctxt->context->node->children);
7686
93.7k
            case XML_DOCUMENT_NODE:
7687
93.7k
            case XML_DOCUMENT_TYPE_NODE:
7688
93.7k
            case XML_DOCUMENT_FRAG_NODE:
7689
93.7k
            case XML_HTML_DOCUMENT_NODE:
7690
93.7k
    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
3.74k
            case XML_ATTRIBUTE_NODE:
7695
114k
      case XML_NAMESPACE_DECL:
7696
114k
      case XML_XINCLUDE_START:
7697
114k
      case XML_XINCLUDE_END:
7698
114k
    return(NULL);
7699
9.85M
  }
7700
0
  return(NULL);
7701
9.85M
    }
7702
22.8M
    if ((cur->type == XML_DOCUMENT_NODE) ||
7703
22.8M
        (cur->type == XML_HTML_DOCUMENT_NODE))
7704
0
  return(NULL);
7705
22.8M
    return(cur->next);
7706
22.8M
}
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
195M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7720
195M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7721
195M
    if (cur == NULL) {
7722
88.2M
  cur = ctxt->context->node;
7723
88.2M
  if (cur == NULL) return(NULL);
7724
  /*
7725
  * Get the first element child.
7726
  */
7727
88.2M
  switch (cur->type) {
7728
45.7M
            case XML_ELEMENT_NODE:
7729
45.7M
      case XML_DOCUMENT_FRAG_NODE:
7730
45.7M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7731
45.7M
            case XML_ENTITY_NODE:
7732
45.7M
    cur = cur->children;
7733
45.7M
    if (cur != NULL) {
7734
37.1M
        if (cur->type == XML_ELEMENT_NODE)
7735
0
      return(cur);
7736
37.1M
        do {
7737
37.1M
      cur = cur->next;
7738
37.1M
        } while ((cur != NULL) &&
7739
37.1M
      (cur->type != XML_ELEMENT_NODE));
7740
37.1M
        return(cur);
7741
37.1M
    }
7742
8.62M
    return(NULL);
7743
7.82M
            case XML_DOCUMENT_NODE:
7744
7.82M
            case XML_HTML_DOCUMENT_NODE:
7745
7.82M
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7746
34.7M
      default:
7747
34.7M
    return(NULL);
7748
88.2M
  }
7749
0
  return(NULL);
7750
88.2M
    }
7751
    /*
7752
    * Get the next sibling element node.
7753
    */
7754
107M
    switch (cur->type) {
7755
107M
  case XML_ELEMENT_NODE:
7756
107M
  case XML_TEXT_NODE:
7757
107M
  case XML_ENTITY_REF_NODE:
7758
107M
  case XML_ENTITY_NODE:
7759
107M
  case XML_CDATA_SECTION_NODE:
7760
107M
  case XML_PI_NODE:
7761
107M
  case XML_COMMENT_NODE:
7762
107M
  case XML_XINCLUDE_END:
7763
107M
      break;
7764
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7765
0
  default:
7766
0
      return(NULL);
7767
107M
    }
7768
107M
    if (cur->next != NULL) {
7769
100M
  if (cur->next->type == XML_ELEMENT_NODE)
7770
60.4M
      return(cur->next);
7771
39.7M
  cur = cur->next;
7772
63.7M
  do {
7773
63.7M
      cur = cur->next;
7774
63.7M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7775
39.7M
  return(cur);
7776
100M
    }
7777
6.87M
    return(NULL);
7778
107M
}
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
485M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865
485M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866
485M
    if (cur == NULL) {
7867
18.8M
  if (ctxt->context->node == NULL)
7868
0
      return(NULL);
7869
18.8M
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870
18.8M
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871
196k
      return(NULL);
7872
7873
18.6M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874
5.12M
      return(ctxt->context->doc->children);
7875
13.5M
        return(ctxt->context->node->children);
7876
18.6M
    }
7877
7878
466M
    if (cur->type == XML_NAMESPACE_DECL)
7879
0
        return(NULL);
7880
466M
    if (cur->children != NULL) {
7881
  /*
7882
   * Do not descend on entities declarations
7883
   */
7884
157M
  if (cur->children->type != XML_ENTITY_DECL) {
7885
157M
      cur = cur->children;
7886
      /*
7887
       * Skip DTDs
7888
       */
7889
157M
      if (cur->type != XML_DTD_NODE)
7890
157M
    return(cur);
7891
157M
  }
7892
157M
    }
7893
7894
308M
    if (cur == ctxt->context->node) return(NULL);
7895
7896
305M
    while (cur->next != NULL) {
7897
141M
  cur = cur->next;
7898
141M
  if ((cur->type != XML_ENTITY_DECL) &&
7899
141M
      (cur->type != XML_DTD_NODE))
7900
141M
      return(cur);
7901
141M
    }
7902
7903
170M
    do {
7904
170M
        cur = cur->parent;
7905
170M
  if (cur == NULL) break;
7906
170M
  if (cur == ctxt->context->node) return(NULL);
7907
149M
  if (cur->next != NULL) {
7908
143M
      cur = cur->next;
7909
143M
      return(cur);
7910
143M
  }
7911
149M
    } while (cur != NULL);
7912
0
    return(cur);
7913
164M
}
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
212M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930
212M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931
212M
    if (cur == NULL)
7932
12.7M
        return(ctxt->context->node);
7933
7934
199M
    if (ctxt->context->node == NULL)
7935
0
        return(NULL);
7936
199M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7937
199M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7938
201k
        return(NULL);
7939
7940
199M
    return(xmlXPathNextDescendant(ctxt, cur));
7941
199M
}
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
37.7M
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955
37.7M
    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
37.7M
    if (cur == NULL) {
7962
19.0M
  if (ctxt->context->node == NULL) return(NULL);
7963
19.0M
  switch (ctxt->context->node->type) {
7964
10.3M
            case XML_ELEMENT_NODE:
7965
18.5M
            case XML_TEXT_NODE:
7966
18.5M
            case XML_CDATA_SECTION_NODE:
7967
18.5M
            case XML_ENTITY_REF_NODE:
7968
18.5M
            case XML_ENTITY_NODE:
7969
18.6M
            case XML_PI_NODE:
7970
18.7M
            case XML_COMMENT_NODE:
7971
18.7M
            case XML_NOTATION_NODE:
7972
18.7M
            case XML_DTD_NODE:
7973
18.7M
      case XML_ELEMENT_DECL:
7974
18.7M
      case XML_ATTRIBUTE_DECL:
7975
18.7M
      case XML_XINCLUDE_START:
7976
18.7M
      case XML_XINCLUDE_END:
7977
18.7M
      case XML_ENTITY_DECL:
7978
18.7M
    if (ctxt->context->node->parent == NULL)
7979
0
        return((xmlNodePtr) ctxt->context->doc);
7980
18.7M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981
18.7M
        ((ctxt->context->node->parent->name[0] == ' ') ||
7982
10.9M
         (xmlStrEqual(ctxt->context->node->parent->name,
7983
10.9M
         BAD_CAST "fake node libxslt"))))
7984
0
        return(NULL);
7985
18.7M
    return(ctxt->context->node->parent);
7986
12.9k
            case XML_ATTRIBUTE_NODE: {
7987
12.9k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989
12.9k
    return(att->parent);
7990
18.7M
      }
7991
226k
            case XML_DOCUMENT_NODE:
7992
226k
            case XML_DOCUMENT_TYPE_NODE:
7993
226k
            case XML_DOCUMENT_FRAG_NODE:
7994
226k
            case XML_HTML_DOCUMENT_NODE:
7995
226k
                return(NULL);
7996
82.0k
      case XML_NAMESPACE_DECL: {
7997
82.0k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7998
7999
82.0k
    if ((ns->next != NULL) &&
8000
82.0k
        (ns->next->type != XML_NAMESPACE_DECL))
8001
82.0k
        return((xmlNodePtr) ns->next);
8002
0
                return(NULL);
8003
82.0k
      }
8004
19.0M
  }
8005
19.0M
    }
8006
18.7M
    return(NULL);
8007
37.7M
}
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
30.6M
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8025
30.6M
    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
30.6M
    if (cur == NULL) {
8032
8.87M
  if (ctxt->context->node == NULL) return(NULL);
8033
8.87M
  switch (ctxt->context->node->type) {
8034
4.26M
            case XML_ELEMENT_NODE:
8035
8.69M
            case XML_TEXT_NODE:
8036
8.71M
            case XML_CDATA_SECTION_NODE:
8037
8.71M
            case XML_ENTITY_REF_NODE:
8038
8.71M
            case XML_ENTITY_NODE:
8039
8.75M
            case XML_PI_NODE:
8040
8.79M
            case XML_COMMENT_NODE:
8041
8.79M
      case XML_DTD_NODE:
8042
8.79M
      case XML_ELEMENT_DECL:
8043
8.79M
      case XML_ATTRIBUTE_DECL:
8044
8.79M
      case XML_ENTITY_DECL:
8045
8.79M
            case XML_NOTATION_NODE:
8046
8.79M
      case XML_XINCLUDE_START:
8047
8.79M
      case XML_XINCLUDE_END:
8048
8.79M
    if (ctxt->context->node->parent == NULL)
8049
0
        return((xmlNodePtr) ctxt->context->doc);
8050
8.79M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8051
8.79M
        ((ctxt->context->node->parent->name[0] == ' ') ||
8052
4.75M
         (xmlStrEqual(ctxt->context->node->parent->name,
8053
4.75M
         BAD_CAST "fake node libxslt"))))
8054
0
        return(NULL);
8055
8.79M
    return(ctxt->context->node->parent);
8056
6.58k
            case XML_ATTRIBUTE_NODE: {
8057
6.58k
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8058
8059
6.58k
    return(tmp->parent);
8060
8.79M
      }
8061
33.9k
            case XML_DOCUMENT_NODE:
8062
33.9k
            case XML_DOCUMENT_TYPE_NODE:
8063
33.9k
            case XML_DOCUMENT_FRAG_NODE:
8064
33.9k
            case XML_HTML_DOCUMENT_NODE:
8065
33.9k
                return(NULL);
8066
33.1k
      case XML_NAMESPACE_DECL: {
8067
33.1k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8068
8069
33.1k
    if ((ns->next != NULL) &&
8070
33.1k
        (ns->next->type != XML_NAMESPACE_DECL))
8071
33.1k
        return((xmlNodePtr) ns->next);
8072
    /* Bad, how did that namespace end up here ? */
8073
0
                return(NULL);
8074
33.1k
      }
8075
8.87M
  }
8076
0
  return(NULL);
8077
8.87M
    }
8078
21.7M
    if (cur == ctxt->context->doc->children)
8079
44.3k
  return((xmlNodePtr) ctxt->context->doc);
8080
21.7M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8081
10.3M
  return(NULL);
8082
11.3M
    switch (cur->type) {
8083
8.65M
  case XML_ELEMENT_NODE:
8084
10.1M
  case XML_TEXT_NODE:
8085
10.1M
  case XML_CDATA_SECTION_NODE:
8086
10.1M
  case XML_ENTITY_REF_NODE:
8087
10.1M
  case XML_ENTITY_NODE:
8088
10.2M
  case XML_PI_NODE:
8089
10.2M
  case XML_COMMENT_NODE:
8090
10.2M
  case XML_NOTATION_NODE:
8091
10.2M
  case XML_DTD_NODE:
8092
10.2M
        case XML_ELEMENT_DECL:
8093
10.2M
        case XML_ATTRIBUTE_DECL:
8094
10.2M
        case XML_ENTITY_DECL:
8095
10.2M
  case XML_XINCLUDE_START:
8096
10.2M
  case XML_XINCLUDE_END:
8097
10.2M
      if (cur->parent == NULL)
8098
0
    return(NULL);
8099
10.2M
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8100
10.2M
    ((cur->parent->name[0] == ' ') ||
8101
2.87M
     (xmlStrEqual(cur->parent->name,
8102
2.87M
            BAD_CAST "fake node libxslt"))))
8103
0
    return(NULL);
8104
10.2M
      return(cur->parent);
8105
5.22k
  case XML_ATTRIBUTE_NODE: {
8106
5.22k
      xmlAttrPtr att = (xmlAttrPtr) cur;
8107
8108
5.22k
      return(att->parent);
8109
10.2M
  }
8110
20.6k
  case XML_NAMESPACE_DECL: {
8111
20.6k
      xmlNsPtr ns = (xmlNsPtr) cur;
8112
8113
20.6k
      if ((ns->next != NULL) &&
8114
20.6k
          (ns->next->type != XML_NAMESPACE_DECL))
8115
20.6k
          return((xmlNodePtr) ns->next);
8116
      /* Bad, how did that namespace end up here ? */
8117
0
            return(NULL);
8118
20.6k
  }
8119
1.09M
  case XML_DOCUMENT_NODE:
8120
1.09M
  case XML_DOCUMENT_TYPE_NODE:
8121
1.09M
  case XML_DOCUMENT_FRAG_NODE:
8122
1.09M
  case XML_HTML_DOCUMENT_NODE:
8123
1.09M
      return(NULL);
8124
11.3M
    }
8125
0
    return(NULL);
8126
11.3M
}
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
10.2M
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8143
10.2M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8144
10.2M
    if (cur == NULL)
8145
2.72M
        return(ctxt->context->node);
8146
7.50M
    return(xmlXPathNextAncestor(ctxt, cur));
8147
10.2M
}
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
2.48M
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8162
2.48M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163
2.48M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8164
2.48M
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8165
26.2k
  return(NULL);
8166
2.45M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8167
0
        return(NULL);
8168
2.45M
    if (cur == NULL)
8169
94.6k
        return(ctxt->context->node->next);
8170
2.36M
    return(cur->next);
8171
2.45M
}
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
7.24M
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8187
7.24M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8188
7.24M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8189
7.24M
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8190
10.1k
  return(NULL);
8191
7.23M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8192
0
        return(NULL);
8193
7.23M
    if (cur == NULL)
8194
233k
        return(ctxt->context->node->prev);
8195
6.99M
    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
6.99M
    return(cur->prev);
8201
6.99M
}
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
33.8M
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8218
33.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219
33.8M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8220
33.8M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8221
7.61M
        return(cur->children);
8222
8223
26.2M
    if (cur == NULL) {
8224
1.55M
        cur = ctxt->context->node;
8225
1.55M
        if (cur->type == XML_ATTRIBUTE_NODE) {
8226
1.46k
            cur = cur->parent;
8227
1.55M
        } else if (cur->type == XML_NAMESPACE_DECL) {
8228
7.12k
            xmlNsPtr ns = (xmlNsPtr) cur;
8229
8230
7.12k
            if ((ns->next == NULL) ||
8231
7.12k
                (ns->next->type == XML_NAMESPACE_DECL))
8232
0
                return (NULL);
8233
7.12k
            cur = (xmlNodePtr) ns->next;
8234
7.12k
        }
8235
1.55M
    }
8236
26.2M
    if (cur == NULL) return(NULL) ; /* ERROR */
8237
26.2M
    if (cur->next != NULL) return(cur->next) ;
8238
11.6M
    do {
8239
11.6M
        cur = cur->parent;
8240
11.6M
        if (cur == NULL) break;
8241
11.5M
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8242
10.1M
        if (cur->next != NULL) return(cur->next);
8243
10.1M
    } while (cur != NULL);
8244
54.8k
    return(cur);
8245
10.2M
}
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
140M
{
8344
140M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8345
140M
    if (cur == NULL) {
8346
1.00M
        cur = ctxt->context->node;
8347
1.00M
        if (cur == NULL)
8348
0
            return (NULL);
8349
1.00M
        if (cur->type == XML_ATTRIBUTE_NODE) {
8350
21.0k
            cur = cur->parent;
8351
979k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8352
15.5k
            xmlNsPtr ns = (xmlNsPtr) cur;
8353
8354
15.5k
            if ((ns->next == NULL) ||
8355
15.5k
                (ns->next->type == XML_NAMESPACE_DECL))
8356
0
                return (NULL);
8357
15.5k
            cur = (xmlNodePtr) ns->next;
8358
15.5k
        }
8359
1.00M
        ctxt->ancestor = cur->parent;
8360
1.00M
    }
8361
140M
    if (cur->type == XML_NAMESPACE_DECL)
8362
0
        return(NULL);
8363
140M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8364
0
  cur = cur->prev;
8365
141M
    while (cur->prev == NULL) {
8366
70.4M
        cur = cur->parent;
8367
70.4M
        if (cur == NULL)
8368
621k
            return (NULL);
8369
69.8M
        if (cur == ctxt->context->doc->children)
8370
377k
            return (NULL);
8371
69.4M
        if (cur != ctxt->ancestor)
8372
68.2M
            return (cur);
8373
1.19M
        ctxt->ancestor = cur->parent;
8374
1.19M
    }
8375
70.7M
    cur = cur->prev;
8376
139M
    while (cur->last != NULL)
8377
68.6M
        cur = cur->last;
8378
70.7M
    return (cur);
8379
140M
}
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
13.9M
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8397
13.9M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8398
13.9M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8399
9.23M
    if (cur == NULL) {
8400
3.52M
        if (ctxt->context->tmpNsList != NULL)
8401
87.7k
      xmlFree(ctxt->context->tmpNsList);
8402
3.52M
  ctxt->context->tmpNsList =
8403
3.52M
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8404
3.52M
  ctxt->context->tmpNsNr = 0;
8405
3.52M
  if (ctxt->context->tmpNsList != NULL) {
8406
3.68M
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8407
2.34M
    ctxt->context->tmpNsNr++;
8408
2.34M
      }
8409
1.34M
  }
8410
3.52M
  return((xmlNodePtr) xmlXPathXMLNamespace);
8411
3.52M
    }
8412
5.70M
    if (ctxt->context->tmpNsNr > 0) {
8413
2.27M
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8414
3.42M
    } else {
8415
3.42M
  if (ctxt->context->tmpNsList != NULL)
8416
1.24M
      xmlFree(ctxt->context->tmpNsList);
8417
3.42M
  ctxt->context->tmpNsList = NULL;
8418
3.42M
  return(NULL);
8419
3.42M
    }
8420
5.70M
}
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
24.8M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8434
24.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8435
24.8M
    if (ctxt->context->node == NULL)
8436
0
  return(NULL);
8437
24.8M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8438
10.9M
  return(NULL);
8439
13.9M
    if (cur == NULL) {
8440
9.79M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8441
0
      return(NULL);
8442
9.79M
        return((xmlNodePtr)ctxt->context->node->properties);
8443
9.79M
    }
8444
4.17M
    return((xmlNodePtr)cur->next);
8445
13.9M
}
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
17.9M
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8470
17.9M
    if ((ctxt == NULL) || (ctxt->context == NULL))
8471
0
  return;
8472
17.9M
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8473
17.9M
  (xmlNodePtr) ctxt->context->doc));
8474
17.9M
}
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.14M
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8495
6.42M
    CHECK_ARITY(0);
8496
6.42M
    if (ctxt->context->contextSize >= 0) {
8497
2.14M
  valuePush(ctxt,
8498
2.14M
      xmlXPathCacheNewFloat(ctxt->context,
8499
2.14M
    (double) ctxt->context->contextSize));
8500
#ifdef DEBUG_EXPR
8501
  xmlGenericError(xmlGenericErrorContext,
8502
    "last() : %d\n", ctxt->context->contextSize);
8503
#endif
8504
2.14M
    } else {
8505
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8506
0
    }
8507
6.42M
}
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
29
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522
79
    CHECK_ARITY(0);
8523
79
    if (ctxt->context->proximityPosition >= 0) {
8524
25
  valuePush(ctxt,
8525
25
        xmlXPathCacheNewFloat(ctxt->context,
8526
25
    (double) ctxt->context->proximityPosition));
8527
#ifdef DEBUG_EXPR
8528
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8529
    ctxt->context->proximityPosition);
8530
#endif
8531
25
    } else {
8532
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8533
0
    }
8534
79
}
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
134
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546
134
    xmlXPathObjectPtr cur;
8547
8548
370
    CHECK_ARITY(1);
8549
370
    if ((ctxt->value == NULL) ||
8550
118
  ((ctxt->value->type != XPATH_NODESET) &&
8551
118
   (ctxt->value->type != XPATH_XSLT_TREE)))
8552
102
  XP_ERROR(XPATH_INVALID_TYPE);
8553
102
    cur = valuePop(ctxt);
8554
8555
102
    if ((cur == NULL) || (cur->nodesetval == NULL))
8556
16
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8557
86
    else
8558
86
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8559
86
      (double) cur->nodesetval->nodeNr));
8560
102
    xmlXPathReleaseObject(ctxt->context, cur);
8561
102
}
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
276k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8574
276k
    xmlNodeSetPtr ret;
8575
276k
    const xmlChar *cur = ids;
8576
276k
    xmlChar *ID;
8577
276k
    xmlAttrPtr attr;
8578
276k
    xmlNodePtr elem = NULL;
8579
8580
276k
    if (ids == NULL) return(NULL);
8581
8582
276k
    ret = xmlXPathNodeSetCreate(NULL);
8583
276k
    if (ret == NULL)
8584
0
        return(ret);
8585
8586
411k
    while (IS_BLANK_CH(*cur)) cur++;
8587
564k
    while (*cur != 0) {
8588
3.59M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8589
3.30M
      cur++;
8590
8591
287k
        ID = xmlStrndup(ids, cur - ids);
8592
287k
  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
287k
      attr = xmlGetID(doc, ID);
8601
287k
      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
287k
      xmlFree(ID);
8613
287k
  }
8614
8615
963k
  while (IS_BLANK_CH(*cur)) cur++;
8616
287k
  ids = cur;
8617
287k
    }
8618
276k
    return(ret);
8619
276k
}
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
144k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8641
144k
    xmlChar *tokens;
8642
144k
    xmlNodeSetPtr ret;
8643
144k
    xmlXPathObjectPtr obj;
8644
8645
434k
    CHECK_ARITY(1);
8646
434k
    obj = valuePop(ctxt);
8647
434k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8648
144k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8649
45.2k
  xmlNodeSetPtr ns;
8650
45.2k
  int i;
8651
8652
        /* TODO: Check memory error. */
8653
45.2k
  ret = xmlXPathNodeSetCreate(NULL);
8654
8655
45.2k
  if (obj->nodesetval != NULL) {
8656
221k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8657
176k
    tokens =
8658
176k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8659
176k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8660
                /* TODO: Check memory error. */
8661
176k
    ret = xmlXPathNodeSetMerge(ret, ns);
8662
176k
    xmlXPathFreeNodeSet(ns);
8663
176k
    if (tokens != NULL)
8664
176k
        xmlFree(tokens);
8665
176k
      }
8666
44.5k
  }
8667
45.2k
  xmlXPathReleaseObject(ctxt->context, obj);
8668
45.2k
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8669
45.2k
  return;
8670
45.2k
    }
8671
99.6k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8672
99.6k
    if (obj == NULL) return;
8673
99.6k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8674
99.6k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8675
99.6k
    xmlXPathReleaseObject(ctxt->context, obj);
8676
99.6k
    return;
8677
99.6k
}
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
3.19k
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8694
3.19k
    xmlXPathObjectPtr cur;
8695
8696
3.19k
    if (ctxt == NULL) return;
8697
8698
3.19k
    if (nargs == 0) {
8699
15
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8700
15
      ctxt->context->node));
8701
15
  nargs = 1;
8702
15
    }
8703
8704
9.56k
    CHECK_ARITY(1);
8705
9.56k
    if ((ctxt->value == NULL) ||
8706
3.18k
  ((ctxt->value->type != XPATH_NODESET) &&
8707
3.18k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8708
3.16k
  XP_ERROR(XPATH_INVALID_TYPE);
8709
3.16k
    cur = valuePop(ctxt);
8710
8711
3.16k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8712
63
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
3.10k
    } else {
8714
3.10k
  int i = 0; /* Should be first in document order !!!!! */
8715
3.10k
  switch (cur->nodesetval->nodeTab[i]->type) {
8716
10
  case XML_ELEMENT_NODE:
8717
12
  case XML_ATTRIBUTE_NODE:
8718
737
  case XML_PI_NODE:
8719
737
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8720
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8721
737
      else
8722
737
    valuePush(ctxt,
8723
737
          xmlXPathCacheNewString(ctxt->context,
8724
737
      cur->nodesetval->nodeTab[i]->name));
8725
737
      break;
8726
174
  case XML_NAMESPACE_DECL:
8727
174
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8728
174
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8729
174
      break;
8730
2.19k
  default:
8731
2.19k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8732
3.10k
  }
8733
3.10k
    }
8734
3.16k
    xmlXPathReleaseObject(ctxt->context, cur);
8735
3.16k
}
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
121
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8753
121
    xmlXPathObjectPtr cur;
8754
8755
121
    if (ctxt == NULL) return;
8756
8757
121
    if (nargs == 0) {
8758
16
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8759
16
      ctxt->context->node));
8760
16
  nargs = 1;
8761
16
    }
8762
333
    CHECK_ARITY(1);
8763
333
    if ((ctxt->value == NULL) ||
8764
106
  ((ctxt->value->type != XPATH_NODESET) &&
8765
106
   (ctxt->value->type != XPATH_XSLT_TREE)))
8766
88
  XP_ERROR(XPATH_INVALID_TYPE);
8767
88
    cur = valuePop(ctxt);
8768
8769
88
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8770
37
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8771
51
    } else {
8772
51
  int i = 0; /* Should be first in document order !!!!! */
8773
51
  switch (cur->nodesetval->nodeTab[i]->type) {
8774
15
  case XML_ELEMENT_NODE:
8775
15
  case XML_ATTRIBUTE_NODE:
8776
15
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8777
14
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8778
1
      else
8779
1
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8780
1
        cur->nodesetval->nodeTab[i]->ns->href));
8781
15
      break;
8782
36
  default:
8783
36
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784
51
  }
8785
51
    }
8786
88
    xmlXPathReleaseObject(ctxt->context, cur);
8787
88
}
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
14.8k
{
8814
14.8k
    xmlXPathObjectPtr cur;
8815
8816
14.8k
    if (nargs == 0) {
8817
2.01k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8818
2.01k
      ctxt->context->node));
8819
2.01k
        nargs = 1;
8820
2.01k
    }
8821
8822
44.5k
    CHECK_ARITY(1);
8823
44.5k
    if ((ctxt->value == NULL) ||
8824
14.8k
        ((ctxt->value->type != XPATH_NODESET) &&
8825
14.8k
         (ctxt->value->type != XPATH_XSLT_TREE)))
8826
14.8k
        XP_ERROR(XPATH_INVALID_TYPE);
8827
14.8k
    cur = valuePop(ctxt);
8828
8829
14.8k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8830
8.71k
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8831
8.71k
    } else {
8832
6.11k
        int i = 0;              /* Should be first in document order !!!!! */
8833
8834
6.11k
        switch (cur->nodesetval->nodeTab[i]->type) {
8835
3.05k
            case XML_ELEMENT_NODE:
8836
3.05k
            case XML_ATTRIBUTE_NODE:
8837
3.05k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8838
0
        valuePush(ctxt,
8839
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8840
3.05k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8841
3.05k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8842
1.76k
        valuePush(ctxt,
8843
1.76k
            xmlXPathCacheNewString(ctxt->context,
8844
1.76k
          cur->nodesetval->nodeTab[i]->name));
8845
1.76k
    } else {
8846
1.29k
        xmlChar *fullname;
8847
8848
1.29k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8849
1.29k
             cur->nodesetval->nodeTab[i]->ns->prefix,
8850
1.29k
             NULL, 0);
8851
1.29k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8852
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8853
1.29k
        if (fullname == NULL) {
8854
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8855
0
        }
8856
1.29k
        valuePush(ctxt, xmlXPathCacheWrapString(
8857
1.29k
      ctxt->context, fullname));
8858
1.29k
                }
8859
3.05k
                break;
8860
3.05k
            default:
8861
3.05k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8862
3.05k
        cur->nodesetval->nodeTab[i]));
8863
3.05k
                xmlXPathLocalNameFunction(ctxt, 1);
8864
6.11k
        }
8865
6.11k
    }
8866
14.8k
    xmlXPathReleaseObject(ctxt->context, cur);
8867
14.8k
}
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
14.8M
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908
14.8M
    xmlXPathObjectPtr cur;
8909
8910
14.8M
    if (ctxt == NULL) return;
8911
14.8M
    if (nargs == 0) {
8912
15
    valuePush(ctxt,
8913
15
  xmlXPathCacheWrapString(ctxt->context,
8914
15
      xmlXPathCastNodeToString(ctxt->context->node)));
8915
15
  return;
8916
15
    }
8917
8918
59.5M
    CHECK_ARITY(1);
8919
59.5M
    cur = valuePop(ctxt);
8920
59.5M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8921
14.8M
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8922
14.8M
}
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
62
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8938
62
    xmlXPathObjectPtr cur;
8939
8940
62
    if (nargs == 0) {
8941
15
        if ((ctxt == NULL) || (ctxt->context == NULL))
8942
0
      return;
8943
15
  if (ctxt->context->node == NULL) {
8944
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8945
15
  } else {
8946
15
      xmlChar *content;
8947
8948
15
      content = xmlXPathCastNodeToString(ctxt->context->node);
8949
15
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8950
15
    xmlUTF8Strlen(content)));
8951
15
      xmlFree(content);
8952
15
  }
8953
15
  return;
8954
15
    }
8955
154
    CHECK_ARITY(1);
8956
154
    CAST_TO_STRING;
8957
154
    CHECK_TYPE(XPATH_STRING);
8958
30
    cur = valuePop(ctxt);
8959
30
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960
30
  xmlUTF8Strlen(cur->stringval)));
8961
30
    xmlXPathReleaseObject(ctxt->context, cur);
8962
30
}
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
845
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975
845
    xmlXPathObjectPtr cur, newobj;
8976
845
    xmlChar *tmp;
8977
8978
845
    if (ctxt == NULL) return;
8979
845
    if (nargs < 2) {
8980
15
  CHECK_ARITY(2);
8981
15
    }
8982
8983
830
    CAST_TO_STRING;
8984
830
    cur = valuePop(ctxt);
8985
830
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8986
0
  xmlXPathReleaseObject(ctxt->context, cur);
8987
0
  return;
8988
0
    }
8989
830
    nargs--;
8990
8991
34.1k
    while (nargs > 0) {
8992
33.3k
  CAST_TO_STRING;
8993
33.3k
  newobj = valuePop(ctxt);
8994
33.3k
  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
33.3k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
9000
33.3k
  newobj->stringval = cur->stringval;
9001
33.3k
  cur->stringval = tmp;
9002
33.3k
  xmlXPathReleaseObject(ctxt->context, newobj);
9003
33.3k
  nargs--;
9004
33.3k
    }
9005
830
    valuePush(ctxt, cur);
9006
830
}
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
89
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
89
    xmlXPathObjectPtr hay, needle;
9021
9022
241
    CHECK_ARITY(2);
9023
241
    CAST_TO_STRING;
9024
241
    CHECK_TYPE(XPATH_STRING);
9025
76
    needle = valuePop(ctxt);
9026
76
    CAST_TO_STRING;
9027
76
    hay = valuePop(ctxt);
9028
9029
76
    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
76
    if (xmlStrstr(hay->stringval, needle->stringval))
9035
40
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9036
36
    else
9037
36
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
76
    xmlXPathReleaseObject(ctxt->context, hay);
9039
76
    xmlXPathReleaseObject(ctxt->context, needle);
9040
76
}
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
83
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9054
83
    xmlXPathObjectPtr hay, needle;
9055
83
    int n;
9056
9057
243
    CHECK_ARITY(2);
9058
243
    CAST_TO_STRING;
9059
243
    CHECK_TYPE(XPATH_STRING);
9060
80
    needle = valuePop(ctxt);
9061
80
    CAST_TO_STRING;
9062
80
    hay = valuePop(ctxt);
9063
9064
80
    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
80
    n = xmlStrlen(needle->stringval);
9070
80
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9071
55
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9072
25
    else
9073
25
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9074
80
    xmlXPathReleaseObject(ctxt->context, hay);
9075
80
    xmlXPathReleaseObject(ctxt->context, needle);
9076
80
}
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
620
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9108
620
    xmlXPathObjectPtr str, start, len;
9109
620
    double le=0, in;
9110
620
    int i = 1, j = INT_MAX;
9111
9112
620
    if (nargs < 2) {
9113
15
  CHECK_ARITY(2);
9114
15
    }
9115
605
    if (nargs > 3) {
9116
19
  CHECK_ARITY(3);
9117
19
    }
9118
    /*
9119
     * take care of possible last (position) argument
9120
    */
9121
586
    if (nargs == 3) {
9122
158
  CAST_TO_NUMBER;
9123
158
  CHECK_TYPE(XPATH_NUMBER);
9124
158
  len = valuePop(ctxt);
9125
158
  le = len->floatval;
9126
158
  xmlXPathReleaseObject(ctxt->context, len);
9127
158
    }
9128
9129
586
    CAST_TO_NUMBER;
9130
586
    CHECK_TYPE(XPATH_NUMBER);
9131
586
    start = valuePop(ctxt);
9132
586
    in = start->floatval;
9133
586
    xmlXPathReleaseObject(ctxt->context, start);
9134
586
    CAST_TO_STRING;
9135
586
    CHECK_TYPE(XPATH_STRING);
9136
586
    str = valuePop(ctxt);
9137
9138
586
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9139
83
        i = INT_MAX;
9140
503
    } else if (in >= 1.0) {
9141
382
        i = (int)in;
9142
382
        if (in - floor(in) >= 0.5)
9143
4
            i += 1;
9144
382
    }
9145
9146
586
    if (nargs == 3) {
9147
158
        double rin, rle, end;
9148
9149
158
        rin = floor(in);
9150
158
        if (in - rin >= 0.5)
9151
2
            rin += 1.0;
9152
9153
158
        rle = floor(le);
9154
158
        if (le - rle >= 0.5)
9155
0
            rle += 1.0;
9156
9157
158
        end = rin + rle;
9158
158
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9159
61
            j = 1;
9160
97
        } else if (end < INT_MAX) {
9161
84
            j = (int)end;
9162
84
        }
9163
158
    }
9164
9165
586
    if (i < j) {
9166
474
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9167
474
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9168
474
  xmlFree(ret);
9169
474
    } else {
9170
112
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9171
112
    }
9172
9173
586
    xmlXPathReleaseObject(ctxt->context, str);
9174
586
}
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
87
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9191
87
  xmlXPathObjectPtr str;
9192
87
  xmlXPathObjectPtr find;
9193
87
  xmlBufPtr target;
9194
87
  const xmlChar *point;
9195
87
  int offset;
9196
9197
235
  CHECK_ARITY(2);
9198
235
  CAST_TO_STRING;
9199
235
  find = valuePop(ctxt);
9200
235
  CAST_TO_STRING;
9201
235
  str = valuePop(ctxt);
9202
9203
235
  target = xmlBufCreate();
9204
235
  if (target) {
9205
74
    point = xmlStrstr(str->stringval, find->stringval);
9206
74
    if (point) {
9207
35
      offset = point - str->stringval;
9208
35
      xmlBufAdd(target, str->stringval, offset);
9209
35
    }
9210
74
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211
74
  xmlBufContent(target)));
9212
74
    xmlBufFree(target);
9213
74
  }
9214
235
  xmlXPathReleaseObject(ctxt->context, str);
9215
235
  xmlXPathReleaseObject(ctxt->context, find);
9216
235
}
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
161
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234
161
  xmlXPathObjectPtr str;
9235
161
  xmlXPathObjectPtr find;
9236
161
  xmlBufPtr target;
9237
161
  const xmlChar *point;
9238
161
  int offset;
9239
9240
449
  CHECK_ARITY(2);
9241
449
  CAST_TO_STRING;
9242
449
  find = valuePop(ctxt);
9243
449
  CAST_TO_STRING;
9244
449
  str = valuePop(ctxt);
9245
9246
449
  target = xmlBufCreate();
9247
449
  if (target) {
9248
144
    point = xmlStrstr(str->stringval, find->stringval);
9249
144
    if (point) {
9250
101
      offset = point - str->stringval + xmlStrlen(find->stringval);
9251
101
      xmlBufAdd(target, &str->stringval[offset],
9252
101
       xmlStrlen(str->stringval) - offset);
9253
101
    }
9254
144
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9255
144
  xmlBufContent(target)));
9256
144
    xmlBufFree(target);
9257
144
  }
9258
449
  xmlXPathReleaseObject(ctxt->context, str);
9259
449
  xmlXPathReleaseObject(ctxt->context, find);
9260
449
}
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
821
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9278
821
    xmlChar *source, *target;
9279
821
    int blank;
9280
9281
821
    if (ctxt == NULL) return;
9282
821
    if (nargs == 0) {
9283
        /* Use current context node */
9284
16
        valuePush(ctxt,
9285
16
            xmlXPathCacheWrapString(ctxt->context,
9286
16
                xmlXPathCastNodeToString(ctxt->context->node)));
9287
16
        nargs = 1;
9288
16
    }
9289
9290
2.42k
    CHECK_ARITY(1);
9291
2.42k
    CAST_TO_STRING;
9292
2.42k
    CHECK_TYPE(XPATH_STRING);
9293
804
    source = ctxt->value->stringval;
9294
804
    if (source == NULL)
9295
0
        return;
9296
804
    target = source;
9297
9298
    /* Skip leading whitespaces */
9299
804
    while (IS_BLANK_CH(*source))
9300
72.4k
        source++;
9301
9302
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9303
804
    blank = 0;
9304
431k
    while (*source) {
9305
430k
        if (IS_BLANK_CH(*source)) {
9306
203k
      blank = 1;
9307
227k
        } else {
9308
227k
            if (blank) {
9309
3.36k
                *target++ = 0x20;
9310
3.36k
                blank = 0;
9311
3.36k
            }
9312
227k
            *target++ = *source;
9313
227k
        }
9314
430k
        source++;
9315
430k
    }
9316
804
    *target = 0;
9317
804
}
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
2.40k
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342
2.40k
    xmlXPathObjectPtr str;
9343
2.40k
    xmlXPathObjectPtr from;
9344
2.40k
    xmlXPathObjectPtr to;
9345
2.40k
    xmlBufPtr target;
9346
2.40k
    int offset, max;
9347
2.40k
    xmlChar ch;
9348
2.40k
    const xmlChar *point;
9349
2.40k
    xmlChar *cptr;
9350
9351
7.11k
    CHECK_ARITY(3);
9352
9353
7.11k
    CAST_TO_STRING;
9354
7.11k
    to = valuePop(ctxt);
9355
7.11k
    CAST_TO_STRING;
9356
7.11k
    from = valuePop(ctxt);
9357
7.11k
    CAST_TO_STRING;
9358
7.11k
    str = valuePop(ctxt);
9359
9360
7.11k
    target = xmlBufCreate();
9361
7.11k
    if (target) {
9362
2.35k
  max = xmlUTF8Strlen(to->stringval);
9363
2.06M
  for (cptr = str->stringval; (ch=*cptr); ) {
9364
2.05M
      offset = xmlUTF8Strloc(from->stringval, cptr);
9365
2.05M
      if (offset >= 0) {
9366
165k
    if (offset < max) {
9367
137k
        point = xmlUTF8Strpos(to->stringval, offset);
9368
137k
        if (point)
9369
130k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9370
137k
    }
9371
165k
      } else
9372
1.89M
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9373
9374
      /* Step to next character in input */
9375
2.05M
      cptr++;
9376
2.05M
      if ( ch & 0x80 ) {
9377
    /* if not simple ascii, verify proper format */
9378
5.14k
    if ( (ch & 0xc0) != 0xc0 ) {
9379
231
        xmlGenericError(xmlGenericErrorContext,
9380
231
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                    /* not asserting an XPath error is probably better */
9382
231
        break;
9383
231
    }
9384
    /* then skip over remaining bytes for this char */
9385
13.0k
    while ( (ch <<= 1) & 0x80 )
9386
8.45k
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9387
295
      xmlGenericError(xmlGenericErrorContext,
9388
295
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9389
                        /* not asserting an XPath error is probably better */
9390
295
      break;
9391
295
        }
9392
4.91k
    if (ch & 0x80) /* must have had error encountered */
9393
295
        break;
9394
4.91k
      }
9395
2.05M
  }
9396
2.35k
    }
9397
7.11k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9398
7.11k
  xmlBufContent(target)));
9399
7.11k
    xmlBufFree(target);
9400
7.11k
    xmlXPathReleaseObject(ctxt->context, str);
9401
7.11k
    xmlXPathReleaseObject(ctxt->context, from);
9402
7.11k
    xmlXPathReleaseObject(ctxt->context, to);
9403
7.11k
}
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
3.08M
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420
3.08M
    xmlXPathObjectPtr cur;
9421
9422
9.24M
    CHECK_ARITY(1);
9423
9.24M
    cur = valuePop(ctxt);
9424
9.24M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9425
3.08M
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9426
3.08M
    valuePush(ctxt, cur);
9427
3.08M
}
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
117
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9441
329
    CHECK_ARITY(1);
9442
329
    CAST_TO_BOOLEAN;
9443
329
    CHECK_TYPE(XPATH_BOOLEAN);
9444
106
    ctxt->value->boolval = ! ctxt->value->boolval;
9445
106
}
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
5.09k
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457
15.2k
    CHECK_ARITY(0);
9458
15.2k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9459
15.2k
}
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
320
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9471
920
    CHECK_ARITY(0);
9472
920
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9473
920
}
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
458
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498
458
    xmlXPathObjectPtr val = NULL;
9499
458
    const xmlChar *theLang = NULL;
9500
458
    const xmlChar *lang;
9501
458
    int ret = 0;
9502
458
    int i;
9503
9504
1.34k
    CHECK_ARITY(1);
9505
1.34k
    CAST_TO_STRING;
9506
1.34k
    CHECK_TYPE(XPATH_STRING);
9507
444
    val = valuePop(ctxt);
9508
444
    lang = val->stringval;
9509
444
    theLang = xmlNodeGetLang(ctxt->context->node);
9510
444
    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
444
not_equal:
9518
444
    if (theLang != NULL)
9519
0
  xmlFree((void *)theLang);
9520
9521
444
    xmlXPathReleaseObject(ctxt->context, val);
9522
444
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9523
444
}
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
45.0M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
45.0M
    xmlXPathObjectPtr cur;
9536
45.0M
    double res;
9537
9538
45.0M
    if (ctxt == NULL) return;
9539
45.0M
    if (nargs == 0) {
9540
62
  if (ctxt->context->node == NULL) {
9541
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9542
62
  } else {
9543
62
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9544
9545
62
      res = xmlXPathStringEvalNumber(content);
9546
62
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9547
62
      xmlFree(content);
9548
62
  }
9549
62
  return;
9550
62
    }
9551
9552
180M
    CHECK_ARITY(1);
9553
180M
    cur = valuePop(ctxt);
9554
180M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9555
180M
}
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
12.1k
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9569
12.1k
    xmlXPathObjectPtr cur;
9570
12.1k
    int i;
9571
12.1k
    double res = 0.0;
9572
9573
36.2k
    CHECK_ARITY(1);
9574
36.2k
    if ((ctxt->value == NULL) ||
9575
12.0k
  ((ctxt->value->type != XPATH_NODESET) &&
9576
12.0k
   (ctxt->value->type != XPATH_XSLT_TREE)))
9577
12.0k
  XP_ERROR(XPATH_INVALID_TYPE);
9578
12.0k
    cur = valuePop(ctxt);
9579
9580
12.0k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9581
248k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9582
244k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9583
244k
  }
9584
3.52k
    }
9585
12.0k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9586
12.0k
    xmlXPathReleaseObject(ctxt->context, cur);
9587
12.0k
}
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
79
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601
207
    CHECK_ARITY(1);
9602
207
    CAST_TO_NUMBER;
9603
207
    CHECK_TYPE(XPATH_NUMBER);
9604
9605
64
    ctxt->value->floatval = floor(ctxt->value->floatval);
9606
64
}
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
52
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9620
130
    CHECK_ARITY(1);
9621
130
    CAST_TO_NUMBER;
9622
130
    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
39
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9629
39
#endif
9630
39
}
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
86
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9645
86
    double f;
9646
9647
232
    CHECK_ARITY(1);
9648
232
    CAST_TO_NUMBER;
9649
232
    CHECK_TYPE(XPATH_NUMBER);
9650
9651
73
    f = ctxt->value->floatval;
9652
9653
73
    if ((f >= -0.5) && (f < 0.5)) {
9654
        /* Handles negative zero. */
9655
22
        ctxt->value->floatval *= 0.0;
9656
22
    }
9657
51
    else {
9658
51
        double rounded = floor(f);
9659
51
        if (f - rounded >= 0.5)
9660
2
            rounded += 1.0;
9661
51
        ctxt->value->floatval = rounded;
9662
51
    }
9663
73
}
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
49.1M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9696
49.1M
    unsigned char c;
9697
49.1M
    unsigned int val;
9698
49.1M
    const xmlChar *cur;
9699
9700
49.1M
    if (ctxt == NULL)
9701
0
  return(0);
9702
49.1M
    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
49.1M
    c = *cur;
9716
49.1M
    if (c & 0x80) {
9717
1.44M
  if ((cur[1] & 0xc0) != 0x80)
9718
21.4k
      goto encoding_error;
9719
1.42M
  if ((c & 0xe0) == 0xe0) {
9720
9721
27.9k
      if ((cur[2] & 0xc0) != 0x80)
9722
722
    goto encoding_error;
9723
27.2k
      if ((c & 0xf0) == 0xf0) {
9724
3.91k
    if (((c & 0xf8) != 0xf0) ||
9725
3.91k
        ((cur[3] & 0xc0) != 0x80))
9726
240
        goto encoding_error;
9727
    /* 4-byte code */
9728
3.67k
    *len = 4;
9729
3.67k
    val = (cur[0] & 0x7) << 18;
9730
3.67k
    val |= (cur[1] & 0x3f) << 12;
9731
3.67k
    val |= (cur[2] & 0x3f) << 6;
9732
3.67k
    val |= cur[3] & 0x3f;
9733
23.3k
      } else {
9734
        /* 3-byte code */
9735
23.3k
    *len = 3;
9736
23.3k
    val = (cur[0] & 0xf) << 12;
9737
23.3k
    val |= (cur[1] & 0x3f) << 6;
9738
23.3k
    val |= cur[2] & 0x3f;
9739
23.3k
      }
9740
1.39M
  } else {
9741
    /* 2-byte code */
9742
1.39M
      *len = 2;
9743
1.39M
      val = (cur[0] & 0x1f) << 6;
9744
1.39M
      val |= cur[1] & 0x3f;
9745
1.39M
  }
9746
1.42M
  if (!IS_CHAR(val)) {
9747
226
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9748
0
  }
9749
1.42M
  return(val);
9750
47.6M
    } else {
9751
  /* 1-byte code */
9752
47.6M
  *len = 1;
9753
47.6M
  return(*cur);
9754
47.6M
    }
9755
22.4k
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
22.4k
    *len = 0;
9764
22.4k
    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
3.15M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9783
3.15M
    const xmlChar *in;
9784
3.15M
    xmlChar *ret;
9785
3.15M
    int count = 0;
9786
9787
3.15M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9788
    /*
9789
     * Accelerator for simple ASCII names
9790
     */
9791
3.15M
    in = ctxt->cur;
9792
3.15M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9793
3.15M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9794
3.15M
  (*in == '_')) {
9795
2.86M
  in++;
9796
14.9M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9797
14.9M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9798
14.9M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9799
14.9M
         (*in == '_') || (*in == '.') ||
9800
14.9M
         (*in == '-'))
9801
12.0M
      in++;
9802
2.86M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9803
2.86M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9804
2.86M
            (*in == '@') || (*in == '*')) {
9805
1.58M
      count = in - ctxt->cur;
9806
1.58M
      if (count == 0)
9807
0
    return(NULL);
9808
1.58M
      ret = xmlStrndup(ctxt->cur, count);
9809
1.58M
      ctxt->cur = in;
9810
1.58M
      return(ret);
9811
1.58M
  }
9812
2.86M
    }
9813
1.56M
    return(xmlXPathParseNameComplex(ctxt, 0));
9814
3.15M
}
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
354k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9836
354k
    xmlChar *ret = NULL;
9837
9838
354k
    *prefix = NULL;
9839
354k
    ret = xmlXPathParseNCName(ctxt);
9840
354k
    if (ret && CUR == ':') {
9841
144k
        *prefix = ret;
9842
144k
  NEXT;
9843
144k
  ret = xmlXPathParseNCName(ctxt);
9844
144k
    }
9845
354k
    return(ret);
9846
354k
}
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
465k
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9864
465k
    const xmlChar *in;
9865
465k
    xmlChar *ret;
9866
465k
    size_t count = 0;
9867
9868
465k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9869
    /*
9870
     * Accelerator for simple ASCII names
9871
     */
9872
465k
    in = ctxt->cur;
9873
465k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874
465k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9875
465k
  (*in == '_') || (*in == ':')) {
9876
97.8k
  in++;
9877
4.19M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878
4.19M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9879
4.19M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9880
4.19M
         (*in == '_') || (*in == '-') ||
9881
4.19M
         (*in == ':') || (*in == '.'))
9882
4.09M
      in++;
9883
97.8k
  if ((*in > 0) && (*in < 0x80)) {
9884
44.9k
      count = in - ctxt->cur;
9885
44.9k
            if (count > XML_MAX_NAME_LENGTH) {
9886
5
                ctxt->cur = in;
9887
5
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9888
0
            }
9889
44.9k
      ret = xmlStrndup(ctxt->cur, count);
9890
44.9k
      ctxt->cur = in;
9891
44.9k
      return(ret);
9892
44.9k
  }
9893
97.8k
    }
9894
420k
    return(xmlXPathParseNameComplex(ctxt, 1));
9895
465k
}
9896
9897
static xmlChar *
9898
1.98M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9899
1.98M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9900
1.98M
    int len = 0, l;
9901
1.98M
    int c;
9902
9903
    /*
9904
     * Handler for more complex cases
9905
     */
9906
1.98M
    c = CUR_CHAR(l);
9907
1.98M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9908
1.98M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9909
1.98M
        (c == '*') || /* accelerators */
9910
1.98M
  (!IS_LETTER(c) && (c != '_') &&
9911
1.75M
         ((!qualified) || (c != ':')))) {
9912
616k
  return(NULL);
9913
616k
    }
9914
9915
8.02M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9916
8.02M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9917
7.98M
            (c == '.') || (c == '-') ||
9918
7.98M
      (c == '_') || ((qualified) && (c == ':')) ||
9919
7.98M
      (IS_COMBINING(c)) ||
9920
7.98M
      (IS_EXTENDER(c)))) {
9921
6.65M
  COPY_BUF(l,buf,len,c);
9922
6.65M
  NEXTL(l);
9923
6.65M
  c = CUR_CHAR(l);
9924
6.65M
  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
9.58k
      xmlChar *buffer;
9930
9.58k
      int max = len * 2;
9931
9932
9.58k
            if (len > XML_MAX_NAME_LENGTH) {
9933
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9934
0
            }
9935
9.58k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9936
9.58k
      if (buffer == NULL) {
9937
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9938
0
      }
9939
9.58k
      memcpy(buffer, buf, len);
9940
5.05M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9941
5.05M
       (c == '.') || (c == '-') ||
9942
5.05M
       (c == '_') || ((qualified) && (c == ':')) ||
9943
5.05M
       (IS_COMBINING(c)) ||
9944
5.05M
       (IS_EXTENDER(c))) {
9945
5.04M
    if (len + 10 > max) {
9946
9.92k
                    xmlChar *tmp;
9947
9.92k
                    if (max > XML_MAX_NAME_LENGTH) {
9948
17
                        xmlFree(buffer);
9949
17
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9950
0
                    }
9951
9.91k
        max *= 2;
9952
9.91k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9953
9.91k
        if (tmp == NULL) {
9954
0
                        xmlFree(buffer);
9955
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9956
0
        }
9957
9.91k
                    buffer = tmp;
9958
9.91k
    }
9959
5.04M
    COPY_BUF(l,buffer,len,c);
9960
5.04M
    NEXTL(l);
9961
5.04M
    c = CUR_CHAR(l);
9962
5.04M
      }
9963
9.57k
      buffer[len] = 0;
9964
9.57k
      return(buffer);
9965
9.58k
  }
9966
6.65M
    }
9967
1.36M
    if (len == 0)
9968
0
  return(NULL);
9969
1.36M
    return(xmlStrndup(buf, len));
9970
1.36M
}
9971
9972
673k
#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
79.1M
xmlXPathStringEvalNumber(const xmlChar *str) {
9992
79.1M
    const xmlChar *cur = str;
9993
79.1M
    double ret;
9994
79.1M
    int ok = 0;
9995
79.1M
    int isneg = 0;
9996
79.1M
    int exponent = 0;
9997
79.1M
    int is_exponent_negative = 0;
9998
79.1M
#ifdef __GNUC__
9999
79.1M
    unsigned long tmp = 0;
10000
79.1M
    double temp;
10001
79.1M
#endif
10002
79.1M
    if (cur == NULL) return(0);
10003
80.9M
    while (IS_BLANK_CH(*cur)) cur++;
10004
79.1M
    if (*cur == '-') {
10005
5.97M
  isneg = 1;
10006
5.97M
  cur++;
10007
5.97M
    }
10008
79.1M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
10009
68.3M
        return(xmlXPathNAN);
10010
68.3M
    }
10011
10012
10.7M
#ifdef __GNUC__
10013
    /*
10014
     * tmp/temp is a workaround against a gcc compiler bug
10015
     * http://veillard.com/gcc.bug
10016
     */
10017
10.7M
    ret = 0;
10018
23.8M
    while ((*cur >= '0') && (*cur <= '9')) {
10019
13.1M
  ret = ret * 10;
10020
13.1M
  tmp = (*cur - '0');
10021
13.1M
  ok = 1;
10022
13.1M
  cur++;
10023
13.1M
  temp = (double) tmp;
10024
13.1M
  ret = ret + temp;
10025
13.1M
    }
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
10.7M
    if (*cur == '.') {
10036
759k
  int v, frac = 0, max;
10037
759k
  double fraction = 0;
10038
10039
759k
        cur++;
10040
759k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10041
189k
      return(xmlXPathNAN);
10042
189k
  }
10043
843k
        while (*cur == '0') {
10044
274k
      frac = frac + 1;
10045
274k
      cur++;
10046
274k
        }
10047
569k
        max = frac + MAX_FRAC;
10048
1.14M
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10049
574k
      v = (*cur - '0');
10050
574k
      fraction = fraction * 10 + v;
10051
574k
      frac = frac + 1;
10052
574k
      cur++;
10053
574k
  }
10054
569k
  fraction /= pow(10.0, frac);
10055
569k
  ret = ret + fraction;
10056
870k
  while ((*cur >= '0') && (*cur <= '9'))
10057
300k
      cur++;
10058
569k
    }
10059
10.5M
    if ((*cur == 'e') || (*cur == 'E')) {
10060
593k
      cur++;
10061
593k
      if (*cur == '-') {
10062
157k
  is_exponent_negative = 1;
10063
157k
  cur++;
10064
436k
      } else if (*cur == '+') {
10065
108k
        cur++;
10066
108k
      }
10067
904k
      while ((*cur >= '0') && (*cur <= '9')) {
10068
310k
        if (exponent < 1000000)
10069
280k
    exponent = exponent * 10 + (*cur - '0');
10070
310k
  cur++;
10071
310k
      }
10072
593k
    }
10073
10.5M
    while (IS_BLANK_CH(*cur)) cur++;
10074
10.5M
    if (*cur != 0) return(xmlXPathNAN);
10075
8.67M
    if (isneg) ret = -ret;
10076
8.67M
    if (is_exponent_negative) exponent = -exponent;
10077
8.67M
    ret *= pow(10.0, (double)exponent);
10078
8.67M
    return(ret);
10079
10.5M
}
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
413k
{
10095
413k
    double ret = 0.0;
10096
413k
    int ok = 0;
10097
413k
    int exponent = 0;
10098
413k
    int is_exponent_negative = 0;
10099
413k
    xmlXPathObjectPtr num;
10100
413k
#ifdef __GNUC__
10101
413k
    unsigned long tmp = 0;
10102
413k
    double temp;
10103
413k
#endif
10104
10105
413k
    CHECK_ERROR;
10106
412k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10107
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10108
0
    }
10109
412k
#ifdef __GNUC__
10110
    /*
10111
     * tmp/temp is a workaround against a gcc compiler bug
10112
     * http://veillard.com/gcc.bug
10113
     */
10114
412k
    ret = 0;
10115
2.84M
    while ((CUR >= '0') && (CUR <= '9')) {
10116
2.43M
  ret = ret * 10;
10117
2.43M
  tmp = (CUR - '0');
10118
2.43M
        ok = 1;
10119
2.43M
        NEXT;
10120
2.43M
  temp = (double) tmp;
10121
2.43M
  ret = ret + temp;
10122
2.43M
    }
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
412k
    if (CUR == '.') {
10132
103k
  int v, frac = 0, max;
10133
103k
  double fraction = 0;
10134
10135
103k
        NEXT;
10136
103k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10137
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10138
0
        }
10139
174k
        while (CUR == '0') {
10140
71.0k
            frac = frac + 1;
10141
71.0k
            NEXT;
10142
71.0k
        }
10143
103k
        max = frac + MAX_FRAC;
10144
202k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10145
98.7k
      v = (CUR - '0');
10146
98.7k
      fraction = fraction * 10 + v;
10147
98.7k
      frac = frac + 1;
10148
98.7k
            NEXT;
10149
98.7k
        }
10150
103k
        fraction /= pow(10.0, frac);
10151
103k
        ret = ret + fraction;
10152
186k
        while ((CUR >= '0') && (CUR <= '9'))
10153
83.5k
            NEXT;
10154
103k
    }
10155
412k
    if ((CUR == 'e') || (CUR == 'E')) {
10156
34.7k
        NEXT;
10157
34.7k
        if (CUR == '-') {
10158
4.36k
            is_exponent_negative = 1;
10159
4.36k
            NEXT;
10160
30.4k
        } else if (CUR == '+') {
10161
7.40k
      NEXT;
10162
7.40k
  }
10163
148k
        while ((CUR >= '0') && (CUR <= '9')) {
10164
114k
            if (exponent < 1000000)
10165
53.3k
                exponent = exponent * 10 + (CUR - '0');
10166
114k
            NEXT;
10167
114k
        }
10168
34.7k
        if (is_exponent_negative)
10169
4.36k
            exponent = -exponent;
10170
34.7k
        ret *= pow(10.0, (double) exponent);
10171
34.7k
    }
10172
412k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10173
412k
    if (num == NULL) {
10174
0
  ctxt->error = XPATH_MEMORY_ERROR;
10175
412k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10176
412k
                              NULL) == -1) {
10177
0
        xmlXPathReleaseObject(ctxt->context, num);
10178
0
    }
10179
412k
}
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
3.34k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10194
3.34k
    const xmlChar *q;
10195
3.34k
    xmlChar *ret = NULL;
10196
10197
3.34k
    if (CUR == '"') {
10198
1.26k
        NEXT;
10199
1.26k
  q = CUR_PTR;
10200
315k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10201
314k
      NEXT;
10202
1.26k
  if (!IS_CHAR_CH(CUR)) {
10203
623
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10204
642
  } else {
10205
642
      ret = xmlStrndup(q, CUR_PTR - q);
10206
642
      NEXT;
10207
642
        }
10208
2.08k
    } else if (CUR == '\'') {
10209
1.99k
        NEXT;
10210
1.99k
  q = CUR_PTR;
10211
423k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10212
421k
      NEXT;
10213
1.99k
  if (!IS_CHAR_CH(CUR)) {
10214
616
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10215
1.38k
  } else {
10216
1.38k
      ret = xmlStrndup(q, CUR_PTR - q);
10217
1.38k
      NEXT;
10218
1.38k
        }
10219
1.99k
    } else {
10220
85
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10221
0
    }
10222
2.02k
    return(ret);
10223
3.34k
}
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
318k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10238
318k
    const xmlChar *q;
10239
318k
    xmlChar *ret = NULL;
10240
318k
    xmlXPathObjectPtr lit;
10241
10242
318k
    if (CUR == '"') {
10243
10.3k
        NEXT;
10244
10.3k
  q = CUR_PTR;
10245
498k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10246
487k
      NEXT;
10247
10.3k
  if (!IS_CHAR_CH(CUR)) {
10248
708
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10249
9.59k
  } else {
10250
9.59k
      ret = xmlStrndup(q, CUR_PTR - q);
10251
9.59k
      NEXT;
10252
9.59k
        }
10253
308k
    } else if (CUR == '\'') {
10254
308k
        NEXT;
10255
308k
  q = CUR_PTR;
10256
133M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10257
133M
      NEXT;
10258
308k
  if (!IS_CHAR_CH(CUR)) {
10259
1.09k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10260
307k
  } else {
10261
307k
      ret = xmlStrndup(q, CUR_PTR - q);
10262
307k
      NEXT;
10263
307k
        }
10264
308k
    } else {
10265
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10266
0
    }
10267
316k
    if (ret == NULL) return;
10268
316k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10269
316k
    if (lit == NULL) {
10270
0
  ctxt->error = XPATH_MEMORY_ERROR;
10271
316k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10272
316k
                              NULL) == -1) {
10273
0
        xmlXPathReleaseObject(ctxt->context, lit);
10274
0
    }
10275
316k
    xmlFree(ret);
10276
316k
}
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
63.8k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10297
63.8k
    xmlChar *name;
10298
63.8k
    xmlChar *prefix;
10299
10300
63.8k
    SKIP_BLANKS;
10301
63.8k
    if (CUR != '$') {
10302
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10303
0
    }
10304
63.8k
    NEXT;
10305
63.8k
    name = xmlXPathParseQName(ctxt, &prefix);
10306
63.8k
    if (name == NULL) {
10307
1.78k
        xmlFree(prefix);
10308
1.78k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10309
0
    }
10310
62.1k
    ctxt->comp->last = -1;
10311
62.1k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10312
0
        xmlFree(prefix);
10313
0
        xmlFree(name);
10314
0
    }
10315
62.1k
    SKIP_BLANKS;
10316
62.1k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10317
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10318
0
    }
10319
62.1k
}
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
298k
xmlXPathIsNodeType(const xmlChar *name) {
10336
298k
    if (name == NULL)
10337
0
  return(0);
10338
10339
298k
    if (xmlStrEqual(name, BAD_CAST "node"))
10340
5.20k
  return(1);
10341
293k
    if (xmlStrEqual(name, BAD_CAST "text"))
10342
1.44k
  return(1);
10343
291k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10344
913
  return(1);
10345
290k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10346
75
  return(1);
10347
290k
    return(0);
10348
290k
}
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
290k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10362
290k
    xmlChar *name;
10363
290k
    xmlChar *prefix;
10364
290k
    int nbargs = 0;
10365
290k
    int sort = 1;
10366
10367
290k
    name = xmlXPathParseQName(ctxt, &prefix);
10368
290k
    if (name == NULL) {
10369
53
  xmlFree(prefix);
10370
53
  XP_ERROR(XPATH_EXPR_ERROR);
10371
0
    }
10372
290k
    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
290k
    if (CUR != '(') {
10383
103
  xmlFree(name);
10384
103
  xmlFree(prefix);
10385
103
  XP_ERROR(XPATH_EXPR_ERROR);
10386
0
    }
10387
290k
    NEXT;
10388
290k
    SKIP_BLANKS;
10389
10390
    /*
10391
    * Optimization for count(): we don't need the node-set to be sorted.
10392
    */
10393
290k
    if ((prefix == NULL) && (name[0] == 'c') &&
10394
290k
  xmlStrEqual(name, BAD_CAST "count"))
10395
182
    {
10396
182
  sort = 0;
10397
182
    }
10398
290k
    ctxt->comp->last = -1;
10399
290k
    if (CUR != ')') {
10400
591k
  while (CUR != 0) {
10401
587k
      int op1 = ctxt->comp->last;
10402
587k
      ctxt->comp->last = -1;
10403
587k
      xmlXPathCompileExpr(ctxt, sort);
10404
587k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10405
31.3k
    xmlFree(name);
10406
31.3k
    xmlFree(prefix);
10407
31.3k
    return;
10408
31.3k
      }
10409
556k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10410
556k
      nbargs++;
10411
556k
      if (CUR == ')') break;
10412
334k
      if (CUR != ',') {
10413
4.47k
    xmlFree(name);
10414
4.47k
    xmlFree(prefix);
10415
4.47k
    XP_ERROR(XPATH_EXPR_ERROR);
10416
0
      }
10417
330k
      NEXT;
10418
330k
      SKIP_BLANKS;
10419
330k
  }
10420
261k
    }
10421
254k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10422
0
        xmlFree(prefix);
10423
0
        xmlFree(name);
10424
0
    }
10425
254k
    NEXT;
10426
254k
    SKIP_BLANKS;
10427
254k
}
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
1.17M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10443
1.17M
    SKIP_BLANKS;
10444
1.17M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10445
1.11M
    else if (CUR == '(') {
10446
88.2k
  NEXT;
10447
88.2k
  SKIP_BLANKS;
10448
88.2k
  xmlXPathCompileExpr(ctxt, 1);
10449
88.2k
  CHECK_ERROR;
10450
73.4k
  if (CUR != ')') {
10451
1.32k
      XP_ERROR(XPATH_EXPR_ERROR);
10452
0
  }
10453
72.1k
  NEXT;
10454
72.1k
  SKIP_BLANKS;
10455
1.02M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10456
413k
  xmlXPathCompNumber(ctxt);
10457
609k
    } else if ((CUR == '\'') || (CUR == '"')) {
10458
318k
  xmlXPathCompLiteral(ctxt);
10459
318k
    } else {
10460
290k
  xmlXPathCompFunctionCall(ctxt);
10461
290k
    }
10462
1.15M
    SKIP_BLANKS;
10463
1.15M
}
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
1.17M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10482
1.17M
    xmlXPathCompPrimaryExpr(ctxt);
10483
1.17M
    CHECK_ERROR;
10484
1.11M
    SKIP_BLANKS;
10485
10486
3.80M
    while (CUR == '[') {
10487
2.68M
  xmlXPathCompPredicate(ctxt, 1);
10488
2.68M
  SKIP_BLANKS;
10489
2.68M
    }
10490
10491
10492
1.11M
}
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
26.5M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10513
26.5M
    int l;
10514
26.5M
    int c;
10515
26.5M
    const xmlChar *cur;
10516
26.5M
    xmlChar *ret;
10517
10518
26.5M
    cur = ctxt->cur;
10519
10520
26.5M
    c = CUR_CHAR(l);
10521
26.5M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10522
26.5M
  (!IS_LETTER(c) && (c != '_') &&
10523
26.5M
         (c != ':'))) {
10524
25.5M
  return(NULL);
10525
25.5M
    }
10526
10527
9.85M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10528
9.85M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10529
9.56M
            (c == '.') || (c == '-') ||
10530
9.56M
      (c == '_') || (c == ':') ||
10531
9.56M
      (IS_COMBINING(c)) ||
10532
9.56M
      (IS_EXTENDER(c)))) {
10533
8.86M
  NEXTL(l);
10534
8.86M
  c = CUR_CHAR(l);
10535
8.86M
    }
10536
992k
    ret = xmlStrndup(cur, ctxt->cur - cur);
10537
992k
    ctxt->cur = cur;
10538
992k
    return(ret);
10539
26.5M
}
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
29.3M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10561
29.3M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10562
29.3M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10563
10564
29.3M
    SKIP_BLANKS;
10565
29.3M
    if ((CUR == '$') || (CUR == '(') ||
10566
29.3M
  (IS_ASCII_DIGIT(CUR)) ||
10567
29.3M
        (CUR == '\'') || (CUR == '"') ||
10568
29.3M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10569
883k
  lc = 0;
10570
28.4M
    } else if (CUR == '*') {
10571
  /* relative or absolute location path */
10572
921k
  lc = 1;
10573
27.5M
    } else if (CUR == '/') {
10574
  /* relative or absolute location path */
10575
813k
  lc = 1;
10576
26.7M
    } else if (CUR == '@') {
10577
  /* relative abbreviated attribute location path */
10578
31.2k
  lc = 1;
10579
26.7M
    } else if (CUR == '.') {
10580
  /* relative abbreviated attribute location path */
10581
127k
  lc = 1;
10582
26.5M
    } 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
26.5M
  SKIP_BLANKS;
10595
26.5M
  name = xmlXPathScanName(ctxt);
10596
26.5M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10597
#ifdef DEBUG_STEP
10598
      xmlGenericError(xmlGenericErrorContext,
10599
        "PathExpr: Axis\n");
10600
#endif
10601
22.3k
      lc = 1;
10602
22.3k
      xmlFree(name);
10603
26.5M
  } else if (name != NULL) {
10604
969k
      int len =xmlStrlen(name);
10605
10606
10607
1.53M
      while (NXT(len) != 0) {
10608
1.52M
    if (NXT(len) == '/') {
10609
        /* element name */
10610
#ifdef DEBUG_STEP
10611
        xmlGenericError(xmlGenericErrorContext,
10612
          "PathExpr: AbbrRelLocation\n");
10613
#endif
10614
194k
        lc = 1;
10615
194k
        break;
10616
1.33M
    } else if (IS_BLANK_CH(NXT(len))) {
10617
        /* ignore blanks */
10618
567k
        ;
10619
767k
    } else if (NXT(len) == ':') {
10620
#ifdef DEBUG_STEP
10621
        xmlGenericError(xmlGenericErrorContext,
10622
          "PathExpr: AbbrRelLocation\n");
10623
#endif
10624
1.53k
        lc = 1;
10625
1.53k
        break;
10626
765k
    } else if ((NXT(len) == '(')) {
10627
        /* Node Type or Function */
10628
298k
        if (xmlXPathIsNodeType(name)) {
10629
#ifdef DEBUG_STEP
10630
            xmlGenericError(xmlGenericErrorContext,
10631
        "PathExpr: Type search\n");
10632
#endif
10633
7.64k
      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
290k
        } else {
10640
#ifdef DEBUG_STEP
10641
            xmlGenericError(xmlGenericErrorContext,
10642
        "PathExpr: function call\n");
10643
#endif
10644
290k
      lc = 0;
10645
290k
        }
10646
298k
                    break;
10647
467k
    } else if ((NXT(len) == '[')) {
10648
        /* element name */
10649
#ifdef DEBUG_STEP
10650
        xmlGenericError(xmlGenericErrorContext,
10651
          "PathExpr: AbbrRelLocation\n");
10652
#endif
10653
16.8k
        lc = 1;
10654
16.8k
        break;
10655
450k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10656
450k
         (NXT(len) == '=')) {
10657
161k
        lc = 1;
10658
161k
        break;
10659
289k
    } else {
10660
289k
        lc = 1;
10661
289k
        break;
10662
289k
    }
10663
567k
    len++;
10664
567k
      }
10665
969k
      if (NXT(len) == 0) {
10666
#ifdef DEBUG_STEP
10667
    xmlGenericError(xmlGenericErrorContext,
10668
      "PathExpr: AbbrRelLocation\n");
10669
#endif
10670
    /* element name */
10671
7.48k
    lc = 1;
10672
7.48k
      }
10673
969k
      xmlFree(name);
10674
25.5M
  } else {
10675
      /* make sure all cases are covered explicitly */
10676
25.5M
      XP_ERROR(XPATH_EXPR_ERROR);
10677
0
  }
10678
26.5M
    }
10679
10680
3.76M
    if (lc) {
10681
2.59M
  if (CUR == '/') {
10682
813k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10683
1.78M
  } else {
10684
1.78M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10685
1.78M
  }
10686
2.59M
  xmlXPathCompLocationPath(ctxt);
10687
2.59M
    } else {
10688
1.17M
  xmlXPathCompFilterExpr(ctxt);
10689
1.17M
  CHECK_ERROR;
10690
1.11M
  if ((CUR == '/') && (NXT(1) == '/')) {
10691
32.2k
      SKIP(2);
10692
32.2k
      SKIP_BLANKS;
10693
10694
32.2k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10695
32.2k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10696
10697
32.2k
      xmlXPathCompRelativeLocationPath(ctxt);
10698
1.08M
  } else if (CUR == '/') {
10699
30.9k
      xmlXPathCompRelativeLocationPath(ctxt);
10700
30.9k
  }
10701
1.11M
    }
10702
3.70M
    SKIP_BLANKS;
10703
3.70M
}
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
3.10M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10717
3.10M
    xmlXPathCompPathExpr(ctxt);
10718
3.10M
    CHECK_ERROR;
10719
2.93M
    SKIP_BLANKS;
10720
29.1M
    while (CUR == '|') {
10721
26.2M
  int op1 = ctxt->comp->last;
10722
26.2M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723
10724
26.2M
  NEXT;
10725
26.2M
  SKIP_BLANKS;
10726
26.2M
  xmlXPathCompPathExpr(ctxt);
10727
10728
26.2M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10729
10730
26.2M
  SKIP_BLANKS;
10731
26.2M
    }
10732
2.93M
}
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
3.10M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10746
3.10M
    int minus = 0;
10747
3.10M
    int found = 0;
10748
10749
3.10M
    SKIP_BLANKS;
10750
3.52M
    while (CUR == '-') {
10751
420k
        minus = 1 - minus;
10752
420k
  found = 1;
10753
420k
  NEXT;
10754
420k
  SKIP_BLANKS;
10755
420k
    }
10756
10757
3.10M
    xmlXPathCompUnionExpr(ctxt);
10758
3.10M
    CHECK_ERROR;
10759
2.92M
    if (found) {
10760
127k
  if (minus)
10761
110k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10762
16.5k
  else
10763
16.5k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10764
127k
    }
10765
2.92M
}
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
2.03M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10782
2.03M
    xmlXPathCompUnaryExpr(ctxt);
10783
2.03M
    CHECK_ERROR;
10784
1.86M
    SKIP_BLANKS;
10785
2.92M
    while ((CUR == '*') ||
10786
2.92M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10787
2.92M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10788
1.06M
  int op = -1;
10789
1.06M
  int op1 = ctxt->comp->last;
10790
10791
1.06M
        if (CUR == '*') {
10792
1.05M
      op = 0;
10793
1.05M
      NEXT;
10794
1.05M
  } else if (CUR == 'd') {
10795
9.71k
      op = 1;
10796
9.71k
      SKIP(3);
10797
9.71k
  } else if (CUR == 'm') {
10798
4.32k
      op = 2;
10799
4.32k
      SKIP(3);
10800
4.32k
  }
10801
1.06M
  SKIP_BLANKS;
10802
1.06M
        xmlXPathCompUnaryExpr(ctxt);
10803
1.06M
  CHECK_ERROR;
10804
1.05M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10805
1.05M
  SKIP_BLANKS;
10806
1.05M
    }
10807
1.86M
}
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
1.90M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10822
10823
1.90M
    xmlXPathCompMultiplicativeExpr(ctxt);
10824
1.90M
    CHECK_ERROR;
10825
1.72M
    SKIP_BLANKS;
10826
1.85M
    while ((CUR == '+') || (CUR == '-')) {
10827
136k
  int plus;
10828
136k
  int op1 = ctxt->comp->last;
10829
10830
136k
        if (CUR == '+') plus = 1;
10831
84.1k
  else plus = 0;
10832
136k
  NEXT;
10833
136k
  SKIP_BLANKS;
10834
136k
        xmlXPathCompMultiplicativeExpr(ctxt);
10835
136k
  CHECK_ERROR;
10836
128k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10837
128k
  SKIP_BLANKS;
10838
128k
    }
10839
1.72M
}
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
1.51M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10861
1.51M
    xmlXPathCompAdditiveExpr(ctxt);
10862
1.51M
    CHECK_ERROR;
10863
1.34M
    SKIP_BLANKS;
10864
1.71M
    while ((CUR == '<') || (CUR == '>')) {
10865
382k
  int inf, strict;
10866
382k
  int op1 = ctxt->comp->last;
10867
10868
382k
        if (CUR == '<') inf = 1;
10869
204k
  else inf = 0;
10870
382k
  if (NXT(1) == '=') strict = 0;
10871
317k
  else strict = 1;
10872
382k
  NEXT;
10873
382k
  if (!strict) NEXT;
10874
382k
  SKIP_BLANKS;
10875
382k
        xmlXPathCompAdditiveExpr(ctxt);
10876
382k
  CHECK_ERROR;
10877
371k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10878
371k
  SKIP_BLANKS;
10879
371k
    }
10880
1.34M
}
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
1.20M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10900
1.20M
    xmlXPathCompRelationalExpr(ctxt);
10901
1.20M
    CHECK_ERROR;
10902
1.03M
    SKIP_BLANKS;
10903
1.33M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10904
317k
  int eq;
10905
317k
  int op1 = ctxt->comp->last;
10906
10907
317k
        if (CUR == '=') eq = 1;
10908
39.6k
  else eq = 0;
10909
317k
  NEXT;
10910
317k
  if (!eq) NEXT;
10911
317k
  SKIP_BLANKS;
10912
317k
        xmlXPathCompRelationalExpr(ctxt);
10913
317k
  CHECK_ERROR;
10914
299k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10915
299k
  SKIP_BLANKS;
10916
299k
    }
10917
1.03M
}
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
1.18M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10931
1.18M
    xmlXPathCompEqualityExpr(ctxt);
10932
1.18M
    CHECK_ERROR;
10933
1.00M
    SKIP_BLANKS;
10934
1.02M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10935
13.3k
  int op1 = ctxt->comp->last;
10936
13.3k
        SKIP(3);
10937
13.3k
  SKIP_BLANKS;
10938
13.3k
        xmlXPathCompEqualityExpr(ctxt);
10939
13.3k
  CHECK_ERROR;
10940
10.8k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10941
10.8k
  SKIP_BLANKS;
10942
10.8k
    }
10943
1.00M
}
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
14.4M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10957
14.4M
    xmlXPathContextPtr xpctxt = ctxt->context;
10958
10959
14.4M
    if (xpctxt != NULL) {
10960
14.4M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10961
13.3M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10962
        /*
10963
         * Parsing a single '(' pushes about 10 functions on the call stack
10964
         * before recursing!
10965
         */
10966
1.15M
        xpctxt->depth += 10;
10967
1.15M
    }
10968
10969
1.15M
    xmlXPathCompAndExpr(ctxt);
10970
1.15M
    CHECK_ERROR;
10971
971k
    SKIP_BLANKS;
10972
1.00M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10973
38.4k
  int op1 = ctxt->comp->last;
10974
38.4k
        SKIP(2);
10975
38.4k
  SKIP_BLANKS;
10976
38.4k
        xmlXPathCompAndExpr(ctxt);
10977
38.4k
  CHECK_ERROR;
10978
35.4k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10979
35.4k
  SKIP_BLANKS;
10980
35.4k
    }
10981
968k
    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
510k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10989
510k
    }
10990
10991
968k
    if (xpctxt != NULL)
10992
968k
        xpctxt->depth -= 10;
10993
968k
}
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
13.5M
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11007
13.5M
    int op1 = ctxt->comp->last;
11008
11009
13.5M
    SKIP_BLANKS;
11010
13.5M
    if (CUR != '[') {
11011
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11012
0
    }
11013
13.5M
    NEXT;
11014
13.5M
    SKIP_BLANKS;
11015
11016
13.5M
    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
13.5M
    if (! filter)
11027
10.8M
  xmlXPathCompileExpr(ctxt, 0);
11028
2.68M
    else
11029
2.68M
  xmlXPathCompileExpr(ctxt, 1);
11030
13.5M
    CHECK_ERROR;
11031
11032
166k
    if (CUR != ']') {
11033
2.27k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11034
0
    }
11035
11036
164k
    if (filter)
11037
46.7k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11038
117k
    else
11039
117k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11040
11041
164k
    NEXT;
11042
164k
    SKIP_BLANKS;
11043
164k
}
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
3.53M
         xmlChar *name) {
11070
3.53M
    int blanks;
11071
11072
3.53M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11073
0
  STRANGE;
11074
0
  return(NULL);
11075
0
    }
11076
3.53M
    *type = (xmlXPathTypeVal) 0;
11077
3.53M
    *test = (xmlXPathTestVal) 0;
11078
3.53M
    *prefix = NULL;
11079
3.53M
    SKIP_BLANKS;
11080
11081
3.53M
    if ((name == NULL) && (CUR == '*')) {
11082
  /*
11083
   * All elements
11084
   */
11085
1.30M
  NEXT;
11086
1.30M
  *test = NODE_TEST_ALL;
11087
1.30M
  return(NULL);
11088
1.30M
    }
11089
11090
2.22M
    if (name == NULL)
11091
168k
  name = xmlXPathParseNCName(ctxt);
11092
2.22M
    if (name == NULL) {
11093
9.95k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11094
0
    }
11095
11096
2.21M
    blanks = IS_BLANK_CH(CUR);
11097
2.21M
    SKIP_BLANKS;
11098
2.21M
    if (CUR == '(') {
11099
73.0k
  NEXT;
11100
  /*
11101
   * NodeType or PI search
11102
   */
11103
73.0k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11104
5.03k
      *type = NODE_TYPE_COMMENT;
11105
68.0k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11106
32.6k
      *type = NODE_TYPE_NODE;
11107
35.3k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11108
5.65k
      *type = NODE_TYPE_PI;
11109
29.7k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11110
28.0k
      *type = NODE_TYPE_TEXT;
11111
1.70k
  else {
11112
1.70k
      if (name != NULL)
11113
1.70k
    xmlFree(name);
11114
1.70k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11115
0
  }
11116
11117
71.3k
  *test = NODE_TEST_TYPE;
11118
11119
71.3k
  SKIP_BLANKS;
11120
71.3k
  if (*type == NODE_TYPE_PI) {
11121
      /*
11122
       * Specific case: search a PI by name.
11123
       */
11124
5.65k
      if (name != NULL)
11125
5.65k
    xmlFree(name);
11126
5.65k
      name = NULL;
11127
5.65k
      if (CUR != ')') {
11128
3.34k
    name = xmlXPathParseLiteral(ctxt);
11129
3.34k
                if (name == NULL) {
11130
1.32k
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11131
0
                }
11132
2.02k
    *test = NODE_TEST_PI;
11133
2.02k
    SKIP_BLANKS;
11134
2.02k
      }
11135
5.65k
  }
11136
70.0k
  if (CUR != ')') {
11137
1.77k
      if (name != NULL)
11138
1.77k
    xmlFree(name);
11139
1.77k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11140
0
  }
11141
68.2k
  NEXT;
11142
68.2k
  return(name);
11143
70.0k
    }
11144
2.14M
    *test = NODE_TEST_NAME;
11145
2.14M
    if ((!blanks) && (CUR == ':')) {
11146
107k
  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
107k
  *prefix = name;
11164
107k
#endif
11165
11166
107k
  if (CUR == '*') {
11167
      /*
11168
       * All elements
11169
       */
11170
16.5k
      NEXT;
11171
16.5k
      *test = NODE_TEST_ALL;
11172
16.5k
      return(NULL);
11173
16.5k
  }
11174
11175
91.1k
  name = xmlXPathParseNCName(ctxt);
11176
91.1k
  if (name == NULL) {
11177
3.21k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11178
0
  }
11179
91.1k
    }
11180
2.12M
    return(name);
11181
2.14M
}
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
2.16M
xmlXPathIsAxisName(const xmlChar *name) {
11205
2.16M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11206
2.16M
    switch (name[0]) {
11207
204k
  case 'a':
11208
204k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11209
8.36k
    ret = AXIS_ANCESTOR;
11210
204k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11211
4.15k
    ret = AXIS_ANCESTOR_OR_SELF;
11212
204k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11213
6.59k
    ret = AXIS_ATTRIBUTE;
11214
204k
      break;
11215
156k
  case 'c':
11216
156k
      if (xmlStrEqual(name, BAD_CAST "child"))
11217
3.76k
    ret = AXIS_CHILD;
11218
156k
      break;
11219
84.5k
  case 'd':
11220
84.5k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11221
741
    ret = AXIS_DESCENDANT;
11222
84.5k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11223
3.56k
    ret = AXIS_DESCENDANT_OR_SELF;
11224
84.5k
      break;
11225
31.7k
  case 'f':
11226
31.7k
      if (xmlStrEqual(name, BAD_CAST "following"))
11227
5.05k
    ret = AXIS_FOLLOWING;
11228
31.7k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11229
3.31k
    ret = AXIS_FOLLOWING_SIBLING;
11230
31.7k
      break;
11231
121k
  case 'n':
11232
121k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11233
37.0k
    ret = AXIS_NAMESPACE;
11234
121k
      break;
11235
65.2k
  case 'p':
11236
65.2k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11237
3.39k
    ret = AXIS_PARENT;
11238
65.2k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11239
9.16k
    ret = AXIS_PRECEDING;
11240
65.2k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11241
5.01k
    ret = AXIS_PRECEDING_SIBLING;
11242
65.2k
      break;
11243
75.3k
  case 's':
11244
75.3k
      if (xmlStrEqual(name, BAD_CAST "self"))
11245
13.4k
    ret = AXIS_SELF;
11246
75.3k
      break;
11247
2.16M
    }
11248
2.16M
    return(ret);
11249
2.16M
}
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
4.02M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11285
#ifdef LIBXML_XPTR_LOCS_ENABLED
11286
    int rangeto = 0;
11287
    int op2 = -1;
11288
#endif
11289
11290
4.02M
    SKIP_BLANKS;
11291
4.02M
    if ((CUR == '.') && (NXT(1) == '.')) {
11292
43.9k
  SKIP(2);
11293
43.9k
  SKIP_BLANKS;
11294
43.9k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11295
43.9k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11296
3.97M
    } else if (CUR == '.') {
11297
338k
  NEXT;
11298
338k
  SKIP_BLANKS;
11299
3.64M
    } else {
11300
3.64M
  xmlChar *name = NULL;
11301
3.64M
  xmlChar *prefix = NULL;
11302
3.64M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11303
3.64M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11304
3.64M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11305
3.64M
  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
3.64M
  if (CUR == '*') {
11338
1.24M
      axis = AXIS_CHILD;
11339
2.39M
  } else {
11340
2.39M
      if (name == NULL)
11341
2.39M
    name = xmlXPathParseNCName(ctxt);
11342
2.39M
      if (name != NULL) {
11343
2.16M
    axis = xmlXPathIsAxisName(name);
11344
2.16M
    if (axis != 0) {
11345
103k
        SKIP_BLANKS;
11346
103k
        if ((CUR == ':') && (NXT(1) == ':')) {
11347
82.1k
      SKIP(2);
11348
82.1k
      xmlFree(name);
11349
82.1k
      name = NULL;
11350
82.1k
        } else {
11351
      /* an element name can conflict with an axis one :-\ */
11352
21.4k
      axis = AXIS_CHILD;
11353
21.4k
        }
11354
2.05M
    } else {
11355
2.05M
        axis = AXIS_CHILD;
11356
2.05M
    }
11357
2.16M
      } else if (CUR == '@') {
11358
144k
    NEXT;
11359
144k
    axis = AXIS_ATTRIBUTE;
11360
144k
      } else {
11361
89.9k
    axis = AXIS_CHILD;
11362
89.9k
      }
11363
2.39M
  }
11364
11365
3.64M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11366
105k
            xmlFree(name);
11367
105k
            return;
11368
105k
        }
11369
11370
3.53M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11371
3.53M
  if (test == 0)
11372
11.6k
      return;
11373
11374
3.52M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11375
3.52M
      (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
3.52M
  op1 = ctxt->comp->last;
11399
3.52M
  ctxt->comp->last = -1;
11400
11401
3.52M
  SKIP_BLANKS;
11402
14.4M
  while (CUR == '[') {
11403
10.8M
      xmlXPathCompPredicate(ctxt, 0);
11404
10.8M
  }
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
3.52M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11412
3.52M
                           test, type, (void *)prefix, (void *)name) == -1) {
11413
0
            xmlFree(prefix);
11414
0
            xmlFree(name);
11415
0
        }
11416
3.52M
    }
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
4.02M
}
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
2.60M
(xmlXPathParserContextPtr ctxt) {
11443
2.60M
    SKIP_BLANKS;
11444
2.60M
    if ((CUR == '/') && (NXT(1) == '/')) {
11445
16.7k
  SKIP(2);
11446
16.7k
  SKIP_BLANKS;
11447
16.7k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11448
16.7k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11449
2.59M
    } else if (CUR == '/') {
11450
87.8k
      NEXT;
11451
87.8k
  SKIP_BLANKS;
11452
87.8k
    }
11453
2.60M
    xmlXPathCompStep(ctxt);
11454
2.60M
    CHECK_ERROR;
11455
2.56M
    SKIP_BLANKS;
11456
3.97M
    while (CUR == '/') {
11457
1.41M
  if ((CUR == '/') && (NXT(1) == '/')) {
11458
493k
      SKIP(2);
11459
493k
      SKIP_BLANKS;
11460
493k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11461
493k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11462
493k
      xmlXPathCompStep(ctxt);
11463
920k
  } else if (CUR == '/') {
11464
920k
      NEXT;
11465
920k
      SKIP_BLANKS;
11466
920k
      xmlXPathCompStep(ctxt);
11467
920k
  }
11468
1.41M
  SKIP_BLANKS;
11469
1.41M
    }
11470
2.56M
}
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
2.59M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11495
2.59M
    SKIP_BLANKS;
11496
2.59M
    if (CUR != '/') {
11497
1.78M
        xmlXPathCompRelativeLocationPath(ctxt);
11498
1.78M
    } else {
11499
1.61M
  while (CUR == '/') {
11500
825k
      if ((CUR == '/') && (NXT(1) == '/')) {
11501
460k
    SKIP(2);
11502
460k
    SKIP_BLANKS;
11503
460k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11504
460k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11505
460k
    xmlXPathCompRelativeLocationPath(ctxt);
11506
460k
      } else if (CUR == '/') {
11507
365k
    NEXT;
11508
365k
    SKIP_BLANKS;
11509
365k
    if ((CUR != 0 ) &&
11510
365k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11511
363k
         (CUR == '@') || (CUR == '*')))
11512
305k
        xmlXPathCompRelativeLocationPath(ctxt);
11513
365k
      }
11514
825k
      CHECK_ERROR;
11515
825k
  }
11516
813k
    }
11517
2.59M
}
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
9.95M
{
11635
9.95M
    xmlXPathContextPtr xpctxt;
11636
9.95M
    xmlNodePtr oldnode;
11637
9.95M
    xmlDocPtr olddoc;
11638
9.95M
    xmlXPathStepOpPtr filterOp;
11639
9.95M
    int oldcs, oldpp;
11640
9.95M
    int i, j, pos;
11641
11642
9.95M
    if ((set == NULL) || (set->nodeNr == 0))
11643
683k
        return;
11644
11645
    /*
11646
    * Check if the node set contains a sufficient number of nodes for
11647
    * the requested range.
11648
    */
11649
9.26M
    if (set->nodeNr < minPos) {
11650
88.8k
        xmlXPathNodeSetClear(set, hasNsNodes);
11651
88.8k
        return;
11652
88.8k
    }
11653
11654
9.18M
    xpctxt = ctxt->context;
11655
9.18M
    oldnode = xpctxt->node;
11656
9.18M
    olddoc = xpctxt->doc;
11657
9.18M
    oldcs = xpctxt->contextSize;
11658
9.18M
    oldpp = xpctxt->proximityPosition;
11659
9.18M
    filterOp = &ctxt->comp->steps[filterOpIndex];
11660
11661
9.18M
    xpctxt->contextSize = set->nodeNr;
11662
11663
47.4M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11664
42.5M
        xmlNodePtr node = set->nodeTab[i];
11665
42.5M
        int res;
11666
11667
42.5M
        xpctxt->node = node;
11668
42.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
42.5M
        if ((node->type != XML_NAMESPACE_DECL) &&
11677
42.5M
            (node->doc != NULL))
11678
40.6M
            xpctxt->doc = node->doc;
11679
11680
42.5M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11681
11682
42.5M
        if (ctxt->error != XPATH_EXPRESSION_OK)
11683
7.74k
            break;
11684
42.5M
        if (res < 0) {
11685
            /* Shouldn't happen */
11686
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11687
0
            break;
11688
0
        }
11689
11690
42.5M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11691
22.2M
            if (i != j) {
11692
203k
                set->nodeTab[j] = node;
11693
203k
                set->nodeTab[i] = NULL;
11694
203k
            }
11695
11696
22.2M
            j += 1;
11697
22.2M
        } else {
11698
            /* Remove the entry from the initial node set. */
11699
20.3M
            set->nodeTab[i] = NULL;
11700
20.3M
            if (node->type == XML_NAMESPACE_DECL)
11701
1.60M
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11702
20.3M
        }
11703
11704
42.5M
        if (res != 0) {
11705
22.2M
            if (pos == maxPos) {
11706
4.25M
                i += 1;
11707
4.25M
                break;
11708
4.25M
            }
11709
11710
17.9M
            pos += 1;
11711
17.9M
        }
11712
42.5M
    }
11713
11714
    /* Free remaining nodes. */
11715
9.18M
    if (hasNsNodes) {
11716
5.50M
        for (; i < set->nodeNr; i++) {
11717
4.42M
            xmlNodePtr node = set->nodeTab[i];
11718
4.42M
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11719
12.5k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11720
4.42M
        }
11721
1.08M
    }
11722
11723
9.18M
    set->nodeNr = j;
11724
11725
    /* If too many elements were removed, shrink table to preserve memory. */
11726
9.18M
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11727
9.18M
        (set->nodeNr < set->nodeMax / 2)) {
11728
103k
        xmlNodePtr *tmp;
11729
103k
        int nodeMax = set->nodeNr;
11730
11731
103k
        if (nodeMax < XML_NODESET_DEFAULT)
11732
103k
            nodeMax = XML_NODESET_DEFAULT;
11733
103k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11734
103k
                nodeMax * sizeof(xmlNodePtr));
11735
103k
        if (tmp == NULL) {
11736
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11737
103k
        } else {
11738
103k
            set->nodeTab = tmp;
11739
103k
            set->nodeMax = nodeMax;
11740
103k
        }
11741
103k
    }
11742
11743
9.18M
    xpctxt->node = oldnode;
11744
9.18M
    xpctxt->doc = olddoc;
11745
9.18M
    xpctxt->contextSize = oldcs;
11746
9.18M
    xpctxt->proximityPosition = oldpp;
11747
9.18M
}
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
9.12M
{
11888
9.12M
    if (op->ch1 != -1) {
11889
142k
  xmlXPathCompExprPtr comp = ctxt->comp;
11890
  /*
11891
  * Process inner predicates first.
11892
  */
11893
142k
  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
142k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11899
142k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11900
142k
        ctxt->context->depth += 1;
11901
142k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11902
142k
                                    1, set->nodeNr, hasNsNodes);
11903
142k
        ctxt->context->depth -= 1;
11904
142k
  CHECK_ERROR;
11905
142k
    }
11906
11907
9.12M
    if (op->ch2 != -1)
11908
9.12M
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11909
9.12M
}
11910
11911
static int
11912
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11913
          xmlXPathStepOpPtr op,
11914
          int *maxPos)
11915
4.68M
{
11916
11917
4.68M
    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
4.68M
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11933
0
  return(0);
11934
11935
4.68M
    if (op->ch2 != -1) {
11936
4.68M
  exprOp = &ctxt->comp->steps[op->ch2];
11937
4.68M
    } else
11938
0
  return(0);
11939
11940
4.68M
    if ((exprOp != NULL) &&
11941
4.68M
  (exprOp->op == XPATH_OP_VALUE) &&
11942
4.68M
  (exprOp->value4 != NULL) &&
11943
4.68M
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11944
496k
    {
11945
496k
        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
496k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11959
492k
      *maxPos = (int) floatval;
11960
492k
            if (floatval == (double) *maxPos)
11961
485k
                return(1);
11962
492k
        }
11963
496k
    }
11964
4.20M
    return(0);
11965
4.68M
}
11966
11967
static int
11968
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11969
                           xmlXPathStepOpPtr op,
11970
         xmlNodePtr * first, xmlNodePtr * last,
11971
         int toBool)
11972
70.6M
{
11973
11974
70.6M
#define XP_TEST_HIT \
11975
531M
    if (hasAxisRange != 0) { \
11976
3.03M
  if (++pos == maxPos) { \
11977
2.34M
      if (addNode(seq, cur) < 0) \
11978
2.34M
          ctxt->error = XPATH_MEMORY_ERROR; \
11979
2.34M
      goto axis_range_end; } \
11980
528M
    } else { \
11981
528M
  if (addNode(seq, cur) < 0) \
11982
528M
      ctxt->error = XPATH_MEMORY_ERROR; \
11983
528M
  if (breakOnFirstHit) goto first_hit; }
11984
11985
70.6M
#define XP_TEST_HIT_NS \
11986
70.6M
    if (hasAxisRange != 0) { \
11987
256k
  if (++pos == maxPos) { \
11988
94.1k
      hasNsNodes = 1; \
11989
94.1k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11990
94.1k
          ctxt->error = XPATH_MEMORY_ERROR; \
11991
94.1k
  goto axis_range_end; } \
11992
4.78M
    } else { \
11993
4.78M
  hasNsNodes = 1; \
11994
4.78M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11995
4.78M
      ctxt->error = XPATH_MEMORY_ERROR; \
11996
4.78M
  if (breakOnFirstHit) goto first_hit; }
11997
11998
70.6M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999
70.6M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000
70.6M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001
70.6M
    const xmlChar *prefix = op->value4;
12002
70.6M
    const xmlChar *name = op->value5;
12003
70.6M
    const xmlChar *URI = NULL;
12004
12005
#ifdef DEBUG_STEP
12006
    int nbMatches = 0, prevMatches = 0;
12007
#endif
12008
70.6M
    int total = 0, hasNsNodes = 0;
12009
    /* The popped object holding the context nodes */
12010
70.6M
    xmlXPathObjectPtr obj;
12011
    /* The set of context nodes for the node tests */
12012
70.6M
    xmlNodeSetPtr contextSeq;
12013
70.6M
    int contextIdx;
12014
70.6M
    xmlNodePtr contextNode;
12015
    /* The final resulting node set wrt to all context nodes */
12016
70.6M
    xmlNodeSetPtr outSeq;
12017
    /*
12018
    * The temporary resulting node set wrt 1 context node.
12019
    * Used to feed predicate evaluation.
12020
    */
12021
70.6M
    xmlNodeSetPtr seq;
12022
70.6M
    xmlNodePtr cur;
12023
    /* First predicate operator */
12024
70.6M
    xmlXPathStepOpPtr predOp;
12025
70.6M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12026
70.6M
    int hasPredicateRange, hasAxisRange, pos;
12027
70.6M
    int breakOnFirstHit;
12028
12029
70.6M
    xmlXPathTraversalFunction next = NULL;
12030
70.6M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12031
70.6M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12032
70.6M
    xmlNodePtr oldContextNode;
12033
70.6M
    xmlXPathContextPtr xpctxt = ctxt->context;
12034
12035
12036
70.6M
    CHECK_TYPE0(XPATH_NODESET);
12037
70.6M
    obj = valuePop(ctxt);
12038
    /*
12039
    * Setup namespaces.
12040
    */
12041
70.6M
    if (prefix != NULL) {
12042
1.60M
        URI = xmlXPathNsLookup(xpctxt, prefix);
12043
1.60M
        if (URI == NULL) {
12044
3.82k
      xmlXPathReleaseObject(xpctxt, obj);
12045
3.82k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12046
0
  }
12047
1.60M
    }
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
70.6M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12062
70.6M
    switch (axis) {
12063
210k
        case AXIS_ANCESTOR:
12064
210k
            first = NULL;
12065
210k
            next = xmlXPathNextAncestor;
12066
210k
            break;
12067
146k
        case AXIS_ANCESTOR_OR_SELF:
12068
146k
            first = NULL;
12069
146k
            next = xmlXPathNextAncestorOrSelf;
12070
146k
            break;
12071
3.01M
        case AXIS_ATTRIBUTE:
12072
3.01M
            first = NULL;
12073
3.01M
      last = NULL;
12074
3.01M
            next = xmlXPathNextAttribute;
12075
3.01M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12076
3.01M
            break;
12077
46.2M
        case AXIS_CHILD:
12078
46.2M
      last = NULL;
12079
46.2M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12080
46.2M
    (type == NODE_TYPE_NODE))
12081
45.6M
      {
12082
    /*
12083
    * Optimization if an element node type is 'element'.
12084
    */
12085
45.6M
    next = xmlXPathNextChildElement;
12086
45.6M
      } else
12087
601k
    next = xmlXPathNextChild;
12088
46.2M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12089
46.2M
            break;
12090
9.93M
        case AXIS_DESCENDANT:
12091
9.93M
      last = NULL;
12092
9.93M
            next = xmlXPathNextDescendant;
12093
9.93M
            break;
12094
6.02M
        case AXIS_DESCENDANT_OR_SELF:
12095
6.02M
      last = NULL;
12096
6.02M
            next = xmlXPathNextDescendantOrSelf;
12097
6.02M
            break;
12098
88.2k
        case AXIS_FOLLOWING:
12099
88.2k
      last = NULL;
12100
88.2k
            next = xmlXPathNextFollowing;
12101
88.2k
            break;
12102
57.9k
        case AXIS_FOLLOWING_SIBLING:
12103
57.9k
      last = NULL;
12104
57.9k
            next = xmlXPathNextFollowingSibling;
12105
57.9k
            break;
12106
318k
        case AXIS_NAMESPACE:
12107
318k
            first = NULL;
12108
318k
      last = NULL;
12109
318k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12110
318k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12111
318k
            break;
12112
3.45M
        case AXIS_PARENT:
12113
3.45M
            first = NULL;
12114
3.45M
            next = xmlXPathNextParent;
12115
3.45M
            break;
12116
578k
        case AXIS_PRECEDING:
12117
578k
            first = NULL;
12118
578k
            next = xmlXPathNextPrecedingInternal;
12119
578k
            break;
12120
55.4k
        case AXIS_PRECEDING_SIBLING:
12121
55.4k
            first = NULL;
12122
55.4k
            next = xmlXPathNextPrecedingSibling;
12123
55.4k
            break;
12124
543k
        case AXIS_SELF:
12125
543k
            first = NULL;
12126
543k
      last = NULL;
12127
543k
            next = xmlXPathNextSelf;
12128
543k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12129
543k
            break;
12130
70.6M
    }
12131
12132
#ifdef DEBUG_STEP
12133
    xmlXPathDebugDumpStepAxis(op,
12134
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12135
#endif
12136
12137
70.6M
    if (next == NULL) {
12138
0
  xmlXPathReleaseObject(xpctxt, obj);
12139
0
        return(0);
12140
0
    }
12141
70.6M
    contextSeq = obj->nodesetval;
12142
70.6M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12143
14.1M
  xmlXPathReleaseObject(xpctxt, obj);
12144
14.1M
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12145
14.1M
        return(0);
12146
14.1M
    }
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
56.5M
    maxPos = 0;
12166
56.5M
    predOp = NULL;
12167
56.5M
    hasPredicateRange = 0;
12168
56.5M
    hasAxisRange = 0;
12169
56.5M
    if (op->ch2 != -1) {
12170
  /*
12171
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12172
  */
12173
4.68M
  predOp = &ctxt->comp->steps[op->ch2];
12174
4.68M
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12175
485k
      if (predOp->ch1 != -1) {
12176
    /*
12177
    * Use the next inner predicate operator.
12178
    */
12179
54.1k
    predOp = &ctxt->comp->steps[predOp->ch1];
12180
54.1k
    hasPredicateRange = 1;
12181
431k
      } else {
12182
    /*
12183
    * There's no other predicate than the [n] predicate.
12184
    */
12185
431k
    predOp = NULL;
12186
431k
    hasAxisRange = 1;
12187
431k
      }
12188
485k
  }
12189
4.68M
    }
12190
56.5M
    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
56.5M
    oldContextNode = xpctxt->node;
12205
56.5M
    addNode = xmlXPathNodeSetAddUnique;
12206
56.5M
    outSeq = NULL;
12207
56.5M
    seq = NULL;
12208
56.5M
    contextNode = NULL;
12209
56.5M
    contextIdx = 0;
12210
12211
12212
245M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12213
245M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12214
192M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12215
12216
192M
  if (seq == NULL) {
12217
58.5M
      seq = xmlXPathNodeSetCreate(NULL);
12218
58.5M
      if (seq == NULL) {
12219
                /* TODO: Propagate memory error. */
12220
0
    total = 0;
12221
0
    goto error;
12222
0
      }
12223
58.5M
  }
12224
  /*
12225
  * Traverse the axis and test the nodes.
12226
  */
12227
192M
  pos = 0;
12228
192M
  cur = NULL;
12229
192M
  hasNsNodes = 0;
12230
1.02G
        do {
12231
1.02G
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12232
1.43k
                goto error;
12233
12234
1.02G
            cur = next(ctxt, cur);
12235
1.02G
            if (cur == NULL)
12236
186M
                break;
12237
12238
      /*
12239
      * QUESTION TODO: What does the "first" and "last" stuff do?
12240
      */
12241
834M
            if ((first != NULL) && (*first != NULL)) {
12242
97.0k
    if (*first == cur)
12243
5.79k
        break;
12244
91.2k
    if (((total % 256) == 0) &&
12245
91.2k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12246
91.2k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12247
#else
12248
        (xmlXPathCmpNodes(*first, cur) >= 0))
12249
#endif
12250
10.4k
    {
12251
10.4k
        break;
12252
10.4k
    }
12253
91.2k
      }
12254
834M
      if ((last != NULL) && (*last != NULL)) {
12255
302k
    if (*last == cur)
12256
4.67k
        break;
12257
297k
    if (((total % 256) == 0) &&
12258
297k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12259
297k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12260
#else
12261
        (xmlXPathCmpNodes(cur, *last) >= 0))
12262
#endif
12263
23.9k
    {
12264
23.9k
        break;
12265
23.9k
    }
12266
297k
      }
12267
12268
834M
            total++;
12269
12270
#ifdef DEBUG_STEP
12271
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12272
#endif
12273
12274
834M
      switch (test) {
12275
0
                case NODE_TEST_NONE:
12276
0
        total = 0;
12277
0
                    STRANGE
12278
0
        goto error;
12279
437M
                case NODE_TEST_TYPE:
12280
437M
        if (type == NODE_TYPE_NODE) {
12281
420M
      switch (cur->type) {
12282
17.2M
          case XML_DOCUMENT_NODE:
12283
17.2M
          case XML_HTML_DOCUMENT_NODE:
12284
207M
          case XML_ELEMENT_NODE:
12285
207M
          case XML_ATTRIBUTE_NODE:
12286
212M
          case XML_PI_NODE:
12287
217M
          case XML_COMMENT_NODE:
12288
220M
          case XML_CDATA_SECTION_NODE:
12289
419M
          case XML_TEXT_NODE:
12290
419M
        XP_TEST_HIT
12291
418M
        break;
12292
418M
          case XML_NAMESPACE_DECL: {
12293
667k
        if (axis == AXIS_NAMESPACE) {
12294
494k
            XP_TEST_HIT_NS
12295
494k
        } else {
12296
172k
                              hasNsNodes = 1;
12297
172k
            XP_TEST_HIT
12298
172k
        }
12299
664k
        break;
12300
667k
                            }
12301
664k
          default:
12302
0
        break;
12303
420M
      }
12304
420M
        } else if (cur->type == (xmlElementType) type) {
12305
6.89M
      if (cur->type == XML_NAMESPACE_DECL)
12306
0
          XP_TEST_HIT_NS
12307
6.89M
      else
12308
6.89M
          XP_TEST_HIT
12309
10.4M
        } else if ((type == NODE_TYPE_TEXT) &&
12310
10.4M
       (cur->type == XML_CDATA_SECTION_NODE))
12311
116k
        {
12312
116k
      XP_TEST_HIT
12313
116k
        }
12314
436M
        break;
12315
436M
                case NODE_TEST_PI:
12316
7.69k
                    if ((cur->type == XML_PI_NODE) &&
12317
7.69k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12318
0
        {
12319
0
      XP_TEST_HIT
12320
0
                    }
12321
7.69k
                    break;
12322
172M
                case NODE_TEST_ALL:
12323
172M
                    if (axis == AXIS_ATTRIBUTE) {
12324
3.47M
                        if (cur->type == XML_ATTRIBUTE_NODE)
12325
3.47M
      {
12326
3.47M
                            if (prefix == NULL)
12327
3.45M
          {
12328
3.45M
        XP_TEST_HIT
12329
3.45M
                            } else if ((cur->ns != NULL) &&
12330
22.3k
        (xmlStrEqual(URI, cur->ns->href)))
12331
0
          {
12332
0
        XP_TEST_HIT
12333
0
                            }
12334
3.47M
                        }
12335
168M
                    } else if (axis == AXIS_NAMESPACE) {
12336
4.27M
                        if (cur->type == XML_NAMESPACE_DECL)
12337
4.27M
      {
12338
4.27M
          XP_TEST_HIT_NS
12339
4.27M
                        }
12340
164M
                    } else {
12341
164M
                        if (cur->type == XML_ELEMENT_NODE) {
12342
99.5M
                            if (prefix == NULL)
12343
96.9M
          {
12344
96.9M
        XP_TEST_HIT
12345
12346
96.9M
                            } else if ((cur->ns != NULL) &&
12347
2.58M
        (xmlStrEqual(URI, cur->ns->href)))
12348
735k
          {
12349
735k
        XP_TEST_HIT
12350
735k
                            }
12351
99.5M
                        }
12352
164M
                    }
12353
167M
                    break;
12354
167M
                case NODE_TEST_NS:{
12355
0
                        TODO;
12356
0
                        break;
12357
172M
                    }
12358
224M
                case NODE_TEST_NAME:
12359
224M
                    if (axis == AXIS_ATTRIBUTE) {
12360
2.46M
                        if (cur->type != XML_ATTRIBUTE_NODE)
12361
0
          break;
12362
222M
        } else if (axis == AXIS_NAMESPACE) {
12363
1.03M
                        if (cur->type != XML_NAMESPACE_DECL)
12364
0
          break;
12365
221M
        } else {
12366
221M
            if (cur->type != XML_ELEMENT_NODE)
12367
108M
          break;
12368
221M
        }
12369
116M
                    switch (cur->type) {
12370
112M
                        case XML_ELEMENT_NODE:
12371
112M
                            if (xmlStrEqual(name, cur->name)) {
12372
3.96M
                                if (prefix == NULL) {
12373
3.78M
                                    if (cur->ns == NULL)
12374
2.44M
            {
12375
2.44M
          XP_TEST_HIT
12376
2.44M
                                    }
12377
3.78M
                                } else {
12378
179k
                                    if ((cur->ns != NULL) &&
12379
179k
                                        (xmlStrEqual(URI, cur->ns->href)))
12380
70.3k
            {
12381
70.3k
          XP_TEST_HIT
12382
70.3k
                                    }
12383
179k
                                }
12384
3.96M
                            }
12385
112M
                            break;
12386
112M
                        case XML_ATTRIBUTE_NODE:{
12387
2.46M
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389
2.46M
                                if (xmlStrEqual(name, attr->name)) {
12390
857k
                                    if (prefix == NULL) {
12391
850k
                                        if ((attr->ns == NULL) ||
12392
850k
                                            (attr->ns->prefix == NULL))
12393
850k
          {
12394
850k
              XP_TEST_HIT
12395
850k
                                        }
12396
850k
                                    } else {
12397
6.57k
                                        if ((attr->ns != NULL) &&
12398
6.57k
                                            (xmlStrEqual(URI,
12399
0
                attr->ns->href)))
12400
0
          {
12401
0
              XP_TEST_HIT
12402
0
                                        }
12403
6.57k
                                    }
12404
857k
                                }
12405
2.43M
                                break;
12406
2.46M
                            }
12407
2.43M
                        case XML_NAMESPACE_DECL:
12408
1.03M
                            if (cur->type == XML_NAMESPACE_DECL) {
12409
1.03M
                                xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411
1.03M
                                if ((ns->prefix != NULL) && (name != NULL)
12412
1.03M
                                    && (xmlStrEqual(ns->prefix, name)))
12413
274k
        {
12414
274k
            XP_TEST_HIT_NS
12415
274k
                                }
12416
1.03M
                            }
12417
1.02M
                            break;
12418
1.02M
                        default:
12419
0
                            break;
12420
116M
                    }
12421
116M
                    break;
12422
834M
      } /* switch(test) */
12423
834M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12424
12425
186M
  goto apply_predicates;
12426
12427
186M
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
2.43M
  if (outSeq == NULL) {
12435
336k
      outSeq = seq;
12436
336k
      seq = NULL;
12437
336k
  } else
12438
            /* TODO: Check memory error. */
12439
2.10M
      outSeq = mergeAndClear(outSeq, seq);
12440
  /*
12441
  * Break if only a true/false result was requested.
12442
  */
12443
2.43M
  if (toBool)
12444
14.6k
      break;
12445
2.42M
  continue;
12446
12447
3.95M
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
3.95M
  if (outSeq == NULL) {
12453
3.95M
      outSeq = seq;
12454
3.95M
      seq = NULL;
12455
3.95M
  } else
12456
            /* TODO: Check memory error. */
12457
0
      outSeq = mergeAndClear(outSeq, seq);
12458
3.95M
  break;
12459
12460
#ifdef DEBUG_STEP
12461
  if (seq != NULL)
12462
      nbMatches += seq->nodeNr;
12463
#endif
12464
12465
186M
apply_predicates: /* --------------------------------------------------- */
12466
186M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12467
0
      goto error;
12468
12469
        /*
12470
  * Apply predicates.
12471
  */
12472
186M
        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
8.98M
      if (hasPredicateRange != 0)
12502
231k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12503
231k
              hasNsNodes);
12504
8.74M
      else
12505
8.74M
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12506
8.74M
              hasNsNodes);
12507
12508
8.98M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12509
5.87k
    total = 0;
12510
5.87k
    goto error;
12511
5.87k
      }
12512
8.98M
        }
12513
12514
186M
        if (seq->nodeNr > 0) {
12515
      /*
12516
      * Add to result set.
12517
      */
12518
63.3M
      if (outSeq == NULL) {
12519
15.0M
    outSeq = seq;
12520
15.0M
    seq = NULL;
12521
48.3M
      } else {
12522
                /* TODO: Check memory error. */
12523
48.3M
    outSeq = mergeAndClear(outSeq, seq);
12524
48.3M
      }
12525
12526
63.3M
            if (toBool)
12527
69.3k
                break;
12528
63.3M
  }
12529
186M
    }
12530
12531
56.5M
error:
12532
56.5M
    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
56.5M
    xmlXPathReleaseObject(xpctxt, obj);
12544
12545
    /*
12546
    * Ensure we return at least an empty set.
12547
    */
12548
56.5M
    if (outSeq == NULL) {
12549
37.2M
  if ((seq != NULL) && (seq->nodeNr == 0))
12550
37.2M
      outSeq = seq;
12551
894
  else
12552
            /* TODO: Check memory error. */
12553
894
      outSeq = xmlXPathNodeSetCreate(NULL);
12554
37.2M
    }
12555
56.5M
    if ((seq != NULL) && (seq != outSeq)) {
12556
2.02M
   xmlXPathFreeNodeSet(seq);
12557
2.02M
    }
12558
    /*
12559
    * Hand over the result. Better to push the set also in
12560
    * case of errors.
12561
    */
12562
56.5M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563
    /*
12564
    * Reset the context node.
12565
    */
12566
56.5M
    xpctxt->node = oldContextNode;
12567
    /*
12568
    * When traversing the namespace axis in "toBool" mode, it's
12569
    * possible that tmpNsList wasn't freed.
12570
    */
12571
56.5M
    if (xpctxt->tmpNsList != NULL) {
12572
12.2k
        xmlFree(xpctxt->tmpNsList);
12573
12.2k
        xpctxt->tmpNsList = NULL;
12574
12.2k
    }
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
56.5M
    return(total);
12583
56.5M
}
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
457k
{
12604
457k
    int total = 0, cur;
12605
457k
    xmlXPathCompExprPtr comp;
12606
457k
    xmlXPathObjectPtr arg1, arg2;
12607
12608
457k
    CHECK_ERROR0;
12609
457k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12610
4
        return(0);
12611
457k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12612
457k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12613
457k
    ctxt->context->depth += 1;
12614
457k
    comp = ctxt->comp;
12615
457k
    switch (op->op) {
12616
0
        case XPATH_OP_END:
12617
0
            break;
12618
50.3k
        case XPATH_OP_UNION:
12619
50.3k
            total =
12620
50.3k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12621
50.3k
                                        first);
12622
50.3k
      CHECK_ERROR0;
12623
45.2k
            if ((ctxt->value != NULL)
12624
45.2k
                && (ctxt->value->type == XPATH_NODESET)
12625
45.2k
                && (ctxt->value->nodesetval != NULL)
12626
45.2k
                && (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
23.5k
    if (ctxt->value->nodesetval->nodeNr > 1)
12638
11.5k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12639
23.5k
                *first = ctxt->value->nodesetval->nodeTab[0];
12640
23.5k
            }
12641
45.2k
            cur =
12642
45.2k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12643
45.2k
                                        first);
12644
45.2k
      CHECK_ERROR0;
12645
12646
44.8k
            arg2 = valuePop(ctxt);
12647
44.8k
            arg1 = valuePop(ctxt);
12648
44.8k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12649
44.8k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12650
74
          xmlXPathReleaseObject(ctxt->context, arg1);
12651
74
          xmlXPathReleaseObject(ctxt->context, arg2);
12652
74
                XP_ERROR0(XPATH_INVALID_TYPE);
12653
0
            }
12654
44.7k
            if ((ctxt->context->opLimit != 0) &&
12655
44.7k
                (((arg1->nodesetval != NULL) &&
12656
44.7k
                  (xmlXPathCheckOpLimit(ctxt,
12657
32.6k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12658
44.7k
                 ((arg2->nodesetval != NULL) &&
12659
44.7k
                  (xmlXPathCheckOpLimit(ctxt,
12660
34.2k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12661
1
          xmlXPathReleaseObject(ctxt->context, arg1);
12662
1
          xmlXPathReleaseObject(ctxt->context, arg2);
12663
1
                break;
12664
1
            }
12665
12666
            /* TODO: Check memory error. */
12667
44.7k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668
44.7k
                                                    arg2->nodesetval);
12669
44.7k
            valuePush(ctxt, arg1);
12670
44.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
12671
            /* optimizer */
12672
44.7k
      if (total > cur)
12673
28.1k
    xmlXPathCompSwap(op);
12674
44.7k
            total += cur;
12675
44.7k
            break;
12676
8.16k
        case XPATH_OP_ROOT:
12677
8.16k
            xmlXPathRoot(ctxt);
12678
8.16k
            break;
12679
2.22k
        case XPATH_OP_NODE:
12680
2.22k
            if (op->ch1 != -1)
12681
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12682
2.22k
      CHECK_ERROR0;
12683
2.22k
            if (op->ch2 != -1)
12684
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12685
2.22k
      CHECK_ERROR0;
12686
2.22k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12687
2.22k
    ctxt->context->node));
12688
2.22k
            break;
12689
129k
        case XPATH_OP_COLLECT:{
12690
129k
                if (op->ch1 == -1)
12691
0
                    break;
12692
12693
129k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12694
129k
    CHECK_ERROR0;
12695
12696
129k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12697
129k
                break;
12698
129k
            }
12699
90
        case XPATH_OP_VALUE:
12700
90
            valuePush(ctxt,
12701
90
                      xmlXPathCacheObjectCopy(ctxt->context,
12702
90
      (xmlXPathObjectPtr) op->value4));
12703
90
            break;
12704
110k
        case XPATH_OP_SORT:
12705
110k
            if (op->ch1 != -1)
12706
110k
                total +=
12707
110k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12708
110k
                                            first);
12709
110k
      CHECK_ERROR0;
12710
110k
            if ((ctxt->value != NULL)
12711
110k
                && (ctxt->value->type == XPATH_NODESET)
12712
110k
                && (ctxt->value->nodesetval != NULL)
12713
110k
    && (ctxt->value->nodesetval->nodeNr > 1))
12714
26.1k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12715
110k
            break;
12716
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12717
147k
  case XPATH_OP_FILTER:
12718
147k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12719
147k
            break;
12720
0
#endif
12721
9.38k
        default:
12722
9.38k
            total += xmlXPathCompOpEval(ctxt, op);
12723
9.38k
            break;
12724
457k
    }
12725
12726
451k
    ctxt->context->depth -= 1;
12727
451k
    return(total);
12728
457k
}
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
410k
{
12745
410k
    int total = 0, cur;
12746
410k
    xmlXPathCompExprPtr comp;
12747
410k
    xmlXPathObjectPtr arg1, arg2;
12748
12749
410k
    CHECK_ERROR0;
12750
410k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12751
1
        return(0);
12752
410k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12753
410k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12754
410k
    ctxt->context->depth += 1;
12755
410k
    comp = ctxt->comp;
12756
410k
    switch (op->op) {
12757
0
        case XPATH_OP_END:
12758
0
            break;
12759
64.5k
        case XPATH_OP_UNION:
12760
64.5k
            total =
12761
64.5k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12762
64.5k
      CHECK_ERROR0;
12763
63.3k
            if ((ctxt->value != NULL)
12764
63.3k
                && (ctxt->value->type == XPATH_NODESET)
12765
63.3k
                && (ctxt->value->nodesetval != NULL)
12766
63.3k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767
                /*
12768
                 * limit tree traversing to first node in the result
12769
                 */
12770
19.5k
    if (ctxt->value->nodesetval->nodeNr > 1)
12771
11.2k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12772
19.5k
                *last =
12773
19.5k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12774
19.5k
                                                     nodesetval->nodeNr -
12775
19.5k
                                                     1];
12776
19.5k
            }
12777
63.3k
            cur =
12778
63.3k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12779
63.3k
      CHECK_ERROR0;
12780
63.1k
            if ((ctxt->value != NULL)
12781
63.1k
                && (ctxt->value->type == XPATH_NODESET)
12782
63.1k
                && (ctxt->value->nodesetval != NULL)
12783
63.1k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12784
16.9k
            }
12785
12786
63.1k
            arg2 = valuePop(ctxt);
12787
63.1k
            arg1 = valuePop(ctxt);
12788
63.1k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12789
63.1k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12790
59
          xmlXPathReleaseObject(ctxt->context, arg1);
12791
59
          xmlXPathReleaseObject(ctxt->context, arg2);
12792
59
                XP_ERROR0(XPATH_INVALID_TYPE);
12793
0
            }
12794
63.0k
            if ((ctxt->context->opLimit != 0) &&
12795
63.0k
                (((arg1->nodesetval != NULL) &&
12796
63.0k
                  (xmlXPathCheckOpLimit(ctxt,
12797
46.7k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12798
63.0k
                 ((arg2->nodesetval != NULL) &&
12799
63.0k
                  (xmlXPathCheckOpLimit(ctxt,
12800
48.4k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12801
4
          xmlXPathReleaseObject(ctxt->context, arg1);
12802
4
          xmlXPathReleaseObject(ctxt->context, arg2);
12803
4
                break;
12804
4
            }
12805
12806
            /* TODO: Check memory error. */
12807
63.0k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12808
63.0k
                                                    arg2->nodesetval);
12809
63.0k
            valuePush(ctxt, arg1);
12810
63.0k
      xmlXPathReleaseObject(ctxt->context, arg2);
12811
            /* optimizer */
12812
63.0k
      if (total > cur)
12813
21.5k
    xmlXPathCompSwap(op);
12814
63.0k
            total += cur;
12815
63.0k
            break;
12816
2.37k
        case XPATH_OP_ROOT:
12817
2.37k
            xmlXPathRoot(ctxt);
12818
2.37k
            break;
12819
3.22k
        case XPATH_OP_NODE:
12820
3.22k
            if (op->ch1 != -1)
12821
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822
3.22k
      CHECK_ERROR0;
12823
3.22k
            if (op->ch2 != -1)
12824
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12825
3.22k
      CHECK_ERROR0;
12826
3.22k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12827
3.22k
    ctxt->context->node));
12828
3.22k
            break;
12829
173k
        case XPATH_OP_COLLECT:{
12830
173k
                if (op->ch1 == -1)
12831
0
                    break;
12832
12833
173k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12834
173k
    CHECK_ERROR0;
12835
12836
173k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12837
173k
                break;
12838
173k
            }
12839
68
        case XPATH_OP_VALUE:
12840
68
            valuePush(ctxt,
12841
68
                      xmlXPathCacheObjectCopy(ctxt->context,
12842
68
      (xmlXPathObjectPtr) op->value4));
12843
68
            break;
12844
141k
        case XPATH_OP_SORT:
12845
141k
            if (op->ch1 != -1)
12846
141k
                total +=
12847
141k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12848
141k
                                           last);
12849
141k
      CHECK_ERROR0;
12850
140k
            if ((ctxt->value != NULL)
12851
140k
                && (ctxt->value->type == XPATH_NODESET)
12852
140k
                && (ctxt->value->nodesetval != NULL)
12853
140k
    && (ctxt->value->nodesetval->nodeNr > 1))
12854
11.6k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12855
140k
            break;
12856
25.8k
        default:
12857
25.8k
            total += xmlXPathCompOpEval(ctxt, op);
12858
25.8k
            break;
12859
410k
    }
12860
12861
408k
    ctxt->context->depth -= 1;
12862
408k
    return (total);
12863
410k
}
12864
12865
#ifdef XP_OPTIMIZED_FILTER_FIRST
12866
static int
12867
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12868
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12869
147k
{
12870
147k
    int total = 0;
12871
147k
    xmlXPathCompExprPtr comp;
12872
147k
    xmlNodeSetPtr set;
12873
12874
147k
    CHECK_ERROR0;
12875
147k
    comp = ctxt->comp;
12876
    /*
12877
    * Optimization for ()[last()] selection i.e. the last elem
12878
    */
12879
147k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12880
147k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12881
147k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12882
75.3k
  int f = comp->steps[op->ch2].ch1;
12883
12884
75.3k
  if ((f != -1) &&
12885
75.3k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12886
75.3k
      (comp->steps[f].value5 == NULL) &&
12887
75.3k
      (comp->steps[f].value == 0) &&
12888
75.3k
      (comp->steps[f].value4 != NULL) &&
12889
75.3k
      (xmlStrEqual
12890
24.8k
      (comp->steps[f].value4, BAD_CAST "last"))) {
12891
20.0k
      xmlNodePtr last = NULL;
12892
12893
20.0k
      total +=
12894
20.0k
    xmlXPathCompOpEvalLast(ctxt,
12895
20.0k
        &comp->steps[op->ch1],
12896
20.0k
        &last);
12897
20.0k
      CHECK_ERROR0;
12898
      /*
12899
      * The nodeset should be in document order,
12900
      * Keep only the last value
12901
      */
12902
20.0k
      if ((ctxt->value != NULL) &&
12903
20.0k
    (ctxt->value->type == XPATH_NODESET) &&
12904
20.0k
    (ctxt->value->nodesetval != NULL) &&
12905
20.0k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12906
20.0k
    (ctxt->value->nodesetval->nodeNr > 1)) {
12907
3.13k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12908
3.13k
    *first = *(ctxt->value->nodesetval->nodeTab);
12909
3.13k
      }
12910
20.0k
      return (total);
12911
20.0k
  }
12912
75.3k
    }
12913
12914
126k
    if (op->ch1 != -1)
12915
126k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12916
126k
    CHECK_ERROR0;
12917
126k
    if (op->ch2 == -1)
12918
0
  return (total);
12919
126k
    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
126k
    CHECK_TYPE0(XPATH_NODESET);
12940
126k
    set = ctxt->value->nodesetval;
12941
126k
    if (set != NULL) {
12942
121k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12943
121k
        if (set->nodeNr > 0)
12944
11.3k
            *first = set->nodeTab[0];
12945
121k
    }
12946
12947
126k
    return (total);
12948
126k
}
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
193M
{
12962
193M
    int total = 0;
12963
193M
    int equal, ret;
12964
193M
    xmlXPathCompExprPtr comp;
12965
193M
    xmlXPathObjectPtr arg1, arg2;
12966
12967
193M
    CHECK_ERROR0;
12968
193M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12969
248
        return(0);
12970
193M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12971
193M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12972
193M
    ctxt->context->depth += 1;
12973
193M
    comp = ctxt->comp;
12974
193M
    switch (op->op) {
12975
0
        case XPATH_OP_END:
12976
0
            break;
12977
118k
        case XPATH_OP_AND:
12978
118k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12979
118k
      CHECK_ERROR0;
12980
116k
            xmlXPathBooleanFunction(ctxt, 1);
12981
116k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12982
68.2k
                break;
12983
48.1k
            arg2 = valuePop(ctxt);
12984
48.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12985
48.1k
      if (ctxt->error) {
12986
417
    xmlXPathFreeObject(arg2);
12987
417
    break;
12988
417
      }
12989
47.7k
            xmlXPathBooleanFunction(ctxt, 1);
12990
47.7k
            if (ctxt->value != NULL)
12991
47.7k
                ctxt->value->boolval &= arg2->boolval;
12992
47.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
12993
47.7k
            break;
12994
1.12M
        case XPATH_OP_OR:
12995
1.12M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996
1.12M
      CHECK_ERROR0;
12997
1.11M
            xmlXPathBooleanFunction(ctxt, 1);
12998
1.11M
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12999
429k
                break;
13000
687k
            arg2 = valuePop(ctxt);
13001
687k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13002
687k
      if (ctxt->error) {
13003
1.48k
    xmlXPathFreeObject(arg2);
13004
1.48k
    break;
13005
1.48k
      }
13006
685k
            xmlXPathBooleanFunction(ctxt, 1);
13007
685k
            if (ctxt->value != NULL)
13008
685k
                ctxt->value->boolval |= arg2->boolval;
13009
685k
      xmlXPathReleaseObject(ctxt->context, arg2);
13010
685k
            break;
13011
16.1M
        case XPATH_OP_EQUAL:
13012
16.1M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013
16.1M
      CHECK_ERROR0;
13014
16.0M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13015
16.0M
      CHECK_ERROR0;
13016
16.0M
      if (op->value)
13017
14.0M
    equal = xmlXPathEqualValues(ctxt);
13018
2.00M
      else
13019
2.00M
    equal = xmlXPathNotEqualValues(ctxt);
13020
16.0M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13021
16.0M
            break;
13022
7.05M
        case XPATH_OP_CMP:
13023
7.05M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
7.05M
      CHECK_ERROR0;
13025
7.03M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13026
7.03M
      CHECK_ERROR0;
13027
7.03M
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13028
7.03M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13029
7.03M
            break;
13030
4.06M
        case XPATH_OP_PLUS:
13031
4.06M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13032
4.06M
      CHECK_ERROR0;
13033
4.05M
            if (op->ch2 != -1) {
13034
2.11M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13035
2.11M
      }
13036
4.05M
      CHECK_ERROR0;
13037
4.05M
            if (op->value == 0)
13038
1.43M
                xmlXPathSubValues(ctxt);
13039
2.61M
            else if (op->value == 1)
13040
669k
                xmlXPathAddValues(ctxt);
13041
1.94M
            else if (op->value == 2)
13042
1.14M
                xmlXPathValueFlipSign(ctxt);
13043
799k
            else if (op->value == 3) {
13044
799k
                CAST_TO_NUMBER;
13045
799k
                CHECK_TYPE0(XPATH_NUMBER);
13046
799k
            }
13047
4.05M
            break;
13048
14.2M
        case XPATH_OP_MULT:
13049
14.2M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13050
14.2M
      CHECK_ERROR0;
13051
14.0M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13052
14.0M
      CHECK_ERROR0;
13053
13.9M
            if (op->value == 0)
13054
13.8M
                xmlXPathMultValues(ctxt);
13055
184k
            else if (op->value == 1)
13056
90.7k
                xmlXPathDivValues(ctxt);
13057
93.4k
            else if (op->value == 2)
13058
93.4k
                xmlXPathModValues(ctxt);
13059
13.9M
            break;
13060
5.62M
        case XPATH_OP_UNION:
13061
5.62M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13062
5.62M
      CHECK_ERROR0;
13063
5.59M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13064
5.59M
      CHECK_ERROR0;
13065
13066
5.58M
            arg2 = valuePop(ctxt);
13067
5.58M
            arg1 = valuePop(ctxt);
13068
5.58M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13069
5.58M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13070
2.52k
          xmlXPathReleaseObject(ctxt->context, arg1);
13071
2.52k
          xmlXPathReleaseObject(ctxt->context, arg2);
13072
2.52k
                XP_ERROR0(XPATH_INVALID_TYPE);
13073
0
            }
13074
5.58M
            if ((ctxt->context->opLimit != 0) &&
13075
5.58M
                (((arg1->nodesetval != NULL) &&
13076
5.58M
                  (xmlXPathCheckOpLimit(ctxt,
13077
4.46M
                                        arg1->nodesetval->nodeNr) < 0)) ||
13078
5.58M
                 ((arg2->nodesetval != NULL) &&
13079
5.58M
                  (xmlXPathCheckOpLimit(ctxt,
13080
4.81M
                                        arg2->nodesetval->nodeNr) < 0)))) {
13081
53
          xmlXPathReleaseObject(ctxt->context, arg1);
13082
53
          xmlXPathReleaseObject(ctxt->context, arg2);
13083
53
                break;
13084
53
            }
13085
13086
5.58M
      if ((arg1->nodesetval == NULL) ||
13087
5.58M
    ((arg2->nodesetval != NULL) &&
13088
4.46M
     (arg2->nodesetval->nodeNr != 0)))
13089
2.34M
      {
13090
                /* TODO: Check memory error. */
13091
2.34M
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13092
2.34M
              arg2->nodesetval);
13093
2.34M
      }
13094
13095
5.58M
            valuePush(ctxt, arg1);
13096
5.58M
      xmlXPathReleaseObject(ctxt->context, arg2);
13097
5.58M
            break;
13098
17.9M
        case XPATH_OP_ROOT:
13099
17.9M
            xmlXPathRoot(ctxt);
13100
17.9M
            break;
13101
35.2M
        case XPATH_OP_NODE:
13102
35.2M
            if (op->ch1 != -1)
13103
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104
35.2M
      CHECK_ERROR0;
13105
35.2M
            if (op->ch2 != -1)
13106
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13107
35.2M
      CHECK_ERROR0;
13108
35.2M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13109
35.2M
    ctxt->context->node));
13110
35.2M
            break;
13111
63.3M
        case XPATH_OP_COLLECT:{
13112
63.3M
                if (op->ch1 == -1)
13113
0
                    break;
13114
13115
63.3M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13116
63.3M
    CHECK_ERROR0;
13117
13118
63.2M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13119
63.2M
                break;
13120
63.3M
            }
13121
22.1M
        case XPATH_OP_VALUE:
13122
22.1M
            valuePush(ctxt,
13123
22.1M
                      xmlXPathCacheObjectCopy(ctxt->context,
13124
22.1M
      (xmlXPathObjectPtr) op->value4));
13125
22.1M
            break;
13126
5.09k
        case XPATH_OP_VARIABLE:{
13127
5.09k
    xmlXPathObjectPtr val;
13128
13129
5.09k
                if (op->ch1 != -1)
13130
0
                    total +=
13131
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13132
5.09k
                if (op->value5 == NULL) {
13133
3.95k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13134
3.95k
        if (val == NULL)
13135
3.95k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13136
0
                    valuePush(ctxt, val);
13137
1.13k
    } else {
13138
1.13k
                    const xmlChar *URI;
13139
13140
1.13k
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13141
1.13k
                    if (URI == NULL) {
13142
847
                        xmlGenericError(xmlGenericErrorContext,
13143
847
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13144
847
                                    (char *) op->value4, (char *)op->value5);
13145
847
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13146
847
                        break;
13147
847
                    }
13148
292
        val = xmlXPathVariableLookupNS(ctxt->context,
13149
292
                                                       op->value4, URI);
13150
292
        if (val == NULL)
13151
292
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13152
0
                    valuePush(ctxt, val);
13153
0
                }
13154
0
                break;
13155
5.09k
            }
13156
2.68M
        case XPATH_OP_FUNCTION:{
13157
2.68M
                xmlXPathFunction func;
13158
2.68M
                const xmlChar *oldFunc, *oldFuncURI;
13159
2.68M
    int i;
13160
2.68M
                int frame;
13161
13162
2.68M
                frame = xmlXPathSetFrame(ctxt);
13163
2.68M
                if (op->ch1 != -1) {
13164
531k
                    total +=
13165
531k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13166
531k
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13167
3.38k
                        xmlXPathPopFrame(ctxt, frame);
13168
3.38k
                        break;
13169
3.38k
                    }
13170
531k
                }
13171
2.68M
    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
3.61M
    for (i = 0; i < op->value; i++) {
13179
928k
        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
928k
                }
13187
2.68M
                if (op->cache != NULL)
13188
2.46M
                    func = op->cache;
13189
215k
                else {
13190
215k
                    const xmlChar *URI = NULL;
13191
13192
215k
                    if (op->value5 == NULL)
13193
110k
                        func =
13194
110k
                            xmlXPathFunctionLookup(ctxt->context,
13195
110k
                                                   op->value4);
13196
104k
                    else {
13197
104k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13198
104k
                        if (URI == NULL) {
13199
1.97k
                            xmlGenericError(xmlGenericErrorContext,
13200
1.97k
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13201
1.97k
                                    (char *)op->value4, (char *)op->value5);
13202
1.97k
                            xmlXPathPopFrame(ctxt, frame);
13203
1.97k
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13204
1.97k
                            break;
13205
1.97k
                        }
13206
102k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13207
102k
                                                        op->value4, URI);
13208
102k
                    }
13209
213k
                    if (func == NULL) {
13210
8.63k
                        xmlGenericError(xmlGenericErrorContext,
13211
8.63k
                                "xmlXPathCompOpEval: function %s not found\n",
13212
8.63k
                                        (char *)op->value4);
13213
8.63k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13214
0
                    }
13215
205k
                    op->cache = func;
13216
205k
                    op->cacheURI = (void *) URI;
13217
205k
                }
13218
2.67M
                oldFunc = ctxt->context->function;
13219
2.67M
                oldFuncURI = ctxt->context->functionURI;
13220
2.67M
                ctxt->context->function = op->value4;
13221
2.67M
                ctxt->context->functionURI = op->cacheURI;
13222
2.67M
                func(ctxt, op->value);
13223
2.67M
                ctxt->context->function = oldFunc;
13224
2.67M
                ctxt->context->functionURI = oldFuncURI;
13225
2.67M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13226
2.67M
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13227
2.67M
                    XP_ERROR0(XPATH_STACK_ERROR);
13228
2.67M
                xmlXPathPopFrame(ctxt, frame);
13229
2.67M
                break;
13230
2.67M
            }
13231
958k
        case XPATH_OP_ARG:
13232
958k
            if (op->ch1 != -1) {
13233
427k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13234
427k
          CHECK_ERROR0;
13235
427k
            }
13236
943k
            if (op->ch2 != -1) {
13237
943k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238
943k
          CHECK_ERROR0;
13239
943k
      }
13240
940k
            break;
13241
940k
        case XPATH_OP_PREDICATE:
13242
1.13M
        case XPATH_OP_FILTER:{
13243
1.13M
                xmlNodeSetPtr set;
13244
13245
                /*
13246
                 * Optimization for ()[1] selection i.e. the first elem
13247
                 */
13248
1.13M
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13249
1.13M
#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
1.13M
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13260
1.13M
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13261
#else
13262
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13263
#endif
13264
1.13M
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13265
460k
                    xmlXPathObjectPtr val;
13266
13267
460k
                    val = comp->steps[op->ch2].value4;
13268
460k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13269
460k
                        (val->floatval == 1.0)) {
13270
251k
                        xmlNodePtr first = NULL;
13271
13272
251k
                        total +=
13273
251k
                            xmlXPathCompOpEvalFirst(ctxt,
13274
251k
                                                    &comp->steps[op->ch1],
13275
251k
                                                    &first);
13276
251k
      CHECK_ERROR0;
13277
                        /*
13278
                         * The nodeset should be in document order,
13279
                         * Keep only the first value
13280
                         */
13281
250k
                        if ((ctxt->value != NULL) &&
13282
250k
                            (ctxt->value->type == XPATH_NODESET) &&
13283
250k
                            (ctxt->value->nodesetval != NULL) &&
13284
250k
                            (ctxt->value->nodesetval->nodeNr > 1))
13285
26.1k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13286
26.1k
                                                        1, 1);
13287
250k
                        break;
13288
251k
                    }
13289
460k
                }
13290
                /*
13291
                 * Optimization for ()[last()] selection i.e. the last elem
13292
                 */
13293
885k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13294
885k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13295
885k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13296
443k
                    int f = comp->steps[op->ch2].ch1;
13297
13298
443k
                    if ((f != -1) &&
13299
443k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13300
443k
                        (comp->steps[f].value5 == NULL) &&
13301
443k
                        (comp->steps[f].value == 0) &&
13302
443k
                        (comp->steps[f].value4 != NULL) &&
13303
443k
                        (xmlStrEqual
13304
132k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13305
121k
                        xmlNodePtr last = NULL;
13306
13307
121k
                        total +=
13308
121k
                            xmlXPathCompOpEvalLast(ctxt,
13309
121k
                                                   &comp->steps[op->ch1],
13310
121k
                                                   &last);
13311
121k
      CHECK_ERROR0;
13312
                        /*
13313
                         * The nodeset should be in document order,
13314
                         * Keep only the last value
13315
                         */
13316
120k
                        if ((ctxt->value != NULL) &&
13317
120k
                            (ctxt->value->type == XPATH_NODESET) &&
13318
120k
                            (ctxt->value->nodesetval != NULL) &&
13319
120k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13320
120k
                            (ctxt->value->nodesetval->nodeNr > 1))
13321
8.40k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13322
120k
                        break;
13323
121k
                    }
13324
443k
                }
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
764k
                if (op->ch1 != -1)
13337
764k
                    total +=
13338
764k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339
764k
    CHECK_ERROR0;
13340
761k
                if (op->ch2 == -1)
13341
0
                    break;
13342
761k
                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
761k
                CHECK_TYPE0(XPATH_NODESET);
13358
760k
                set = ctxt->value->nodesetval;
13359
760k
                if (set != NULL)
13360
709k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13361
709k
                                          1, set->nodeNr, 1);
13362
760k
                break;
13363
761k
            }
13364
1.69M
        case XPATH_OP_SORT:
13365
1.69M
            if (op->ch1 != -1)
13366
1.69M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367
1.69M
      CHECK_ERROR0;
13368
1.65M
            if ((ctxt->value != NULL) &&
13369
1.65M
                (ctxt->value->type == XPATH_NODESET) &&
13370
1.65M
                (ctxt->value->nodesetval != NULL) &&
13371
1.65M
    (ctxt->value->nodesetval->nodeNr > 1))
13372
230k
      {
13373
230k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13374
230k
      }
13375
1.65M
            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
193M
    }
13541
13542
192M
    ctxt->context->depth -= 1;
13543
192M
    return (total);
13544
193M
}
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
42.5M
{
13559
42.5M
    xmlXPathObjectPtr resObj = NULL;
13560
13561
50.4M
start:
13562
50.4M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13563
96
        return(0);
13564
    /* comp = ctxt->comp; */
13565
50.4M
    switch (op->op) {
13566
0
        case XPATH_OP_END:
13567
0
            return (0);
13568
11.4M
  case XPATH_OP_VALUE:
13569
11.4M
      resObj = (xmlXPathObjectPtr) op->value4;
13570
11.4M
      if (isPredicate)
13571
11.4M
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13572
0
      return(xmlXPathCastToBoolean(resObj));
13573
7.91M
  case XPATH_OP_SORT:
13574
      /*
13575
      * We don't need sorting for boolean results. Skip this one.
13576
      */
13577
7.91M
            if (op->ch1 != -1) {
13578
7.91M
    op = &ctxt->comp->steps[op->ch1];
13579
7.91M
    goto start;
13580
7.91M
      }
13581
0
      return(0);
13582
7.09M
  case XPATH_OP_COLLECT:
13583
7.09M
      if (op->ch1 == -1)
13584
0
    return(0);
13585
13586
7.09M
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13587
7.09M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13588
260
    return(-1);
13589
13590
7.09M
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13591
7.09M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13592
284
    return(-1);
13593
13594
7.09M
      resObj = valuePop(ctxt);
13595
7.09M
      if (resObj == NULL)
13596
0
    return(-1);
13597
7.09M
      break;
13598
24.0M
  default:
13599
      /*
13600
      * Fallback to call xmlXPathCompOpEval().
13601
      */
13602
24.0M
      xmlXPathCompOpEval(ctxt, op);
13603
24.0M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13604
7.10k
    return(-1);
13605
13606
24.0M
      resObj = valuePop(ctxt);
13607
24.0M
      if (resObj == NULL)
13608
0
    return(-1);
13609
24.0M
      break;
13610
50.4M
    }
13611
13612
31.1M
    if (resObj) {
13613
31.1M
  int res;
13614
13615
31.1M
  if (resObj->type == XPATH_BOOLEAN) {
13616
17.6M
      res = resObj->boolval;
13617
17.6M
  } 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
13.5M
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13627
13.5M
  } else {
13628
0
      res = xmlXPathCastToBoolean(resObj);
13629
0
  }
13630
31.1M
  xmlXPathReleaseObject(ctxt->context, resObj);
13631
31.1M
  return(res);
13632
31.1M
    }
13633
13634
0
    return(0);
13635
31.1M
}
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
26.1k
{
13648
26.1k
    int max_depth, min_depth;
13649
26.1k
    int from_root;
13650
26.1k
    int ret, depth;
13651
26.1k
    int eval_all_nodes;
13652
26.1k
    xmlNodePtr cur = NULL, limit = NULL;
13653
26.1k
    xmlStreamCtxtPtr patstream = NULL;
13654
13655
26.1k
    if ((ctxt == NULL) || (comp == NULL))
13656
0
        return(-1);
13657
26.1k
    max_depth = xmlPatternMaxDepth(comp);
13658
26.1k
    if (max_depth == -1)
13659
0
        return(-1);
13660
26.1k
    if (max_depth == -2)
13661
15.2k
        max_depth = 10000;
13662
26.1k
    min_depth = xmlPatternMinDepth(comp);
13663
26.1k
    if (min_depth == -1)
13664
0
        return(-1);
13665
26.1k
    from_root = xmlPatternFromRoot(comp);
13666
26.1k
    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
26.1k
    if (! toBool) {
13673
26.1k
  if (resultSeq == NULL)
13674
0
      return(-1);
13675
26.1k
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13676
26.1k
  if (*resultSeq == NULL)
13677
0
      return(-1);
13678
26.1k
    }
13679
13680
    /*
13681
     * handle the special cases of "/" amd "." being matched
13682
     */
13683
26.1k
    if (min_depth == 0) {
13684
1.77k
  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
1.77k
  } else {
13692
      /* Select "self::node()" */
13693
1.77k
      if (toBool)
13694
0
    return(1);
13695
            /* TODO: Check memory error. */
13696
1.77k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13697
1.77k
  }
13698
1.77k
    }
13699
26.1k
    if (max_depth == 0) {
13700
1.00k
  return(0);
13701
1.00k
    }
13702
13703
25.1k
    if (from_root) {
13704
6.95k
        cur = (xmlNodePtr)ctxt->doc;
13705
18.2k
    } else if (ctxt->node != NULL) {
13706
18.2k
        switch (ctxt->node->type) {
13707
11.6k
            case XML_ELEMENT_NODE:
13708
14.9k
            case XML_DOCUMENT_NODE:
13709
14.9k
            case XML_DOCUMENT_FRAG_NODE:
13710
14.9k
            case XML_HTML_DOCUMENT_NODE:
13711
14.9k
          cur = ctxt->node;
13712
14.9k
    break;
13713
66
            case XML_ATTRIBUTE_NODE:
13714
2.44k
            case XML_TEXT_NODE:
13715
2.56k
            case XML_CDATA_SECTION_NODE:
13716
2.56k
            case XML_ENTITY_REF_NODE:
13717
2.56k
            case XML_ENTITY_NODE:
13718
2.73k
            case XML_PI_NODE:
13719
2.93k
            case XML_COMMENT_NODE:
13720
2.93k
            case XML_NOTATION_NODE:
13721
2.93k
            case XML_DTD_NODE:
13722
2.93k
            case XML_DOCUMENT_TYPE_NODE:
13723
2.93k
            case XML_ELEMENT_DECL:
13724
2.93k
            case XML_ATTRIBUTE_DECL:
13725
2.93k
            case XML_ENTITY_DECL:
13726
3.27k
            case XML_NAMESPACE_DECL:
13727
3.27k
            case XML_XINCLUDE_START:
13728
3.27k
            case XML_XINCLUDE_END:
13729
3.27k
    break;
13730
18.2k
  }
13731
18.2k
  limit = cur;
13732
18.2k
    }
13733
25.1k
    if (cur == NULL) {
13734
3.27k
        return(0);
13735
3.27k
    }
13736
13737
21.9k
    patstream = xmlPatternGetStreamCtxt(comp);
13738
21.9k
    if (patstream == NULL) {
13739
  /*
13740
  * QUESTION TODO: Is this an error?
13741
  */
13742
0
  return(0);
13743
0
    }
13744
13745
21.9k
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746
13747
21.9k
    if (from_root) {
13748
6.95k
  ret = xmlStreamPush(patstream, NULL, NULL);
13749
6.95k
  if (ret < 0) {
13750
6.95k
  } else if (ret == 1) {
13751
394
      if (toBool)
13752
0
    goto return_1;
13753
            /* TODO: Check memory error. */
13754
394
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755
394
  }
13756
6.95k
    }
13757
21.9k
    depth = 0;
13758
21.9k
    goto scan_children;
13759
190k
next_node:
13760
344k
    do {
13761
344k
        if (ctxt->opLimit != 0) {
13762
344k
            if (ctxt->opCount >= ctxt->opLimit) {
13763
0
                xmlGenericError(xmlGenericErrorContext,
13764
0
                        "XPath operation limit exceeded\n");
13765
0
                xmlFreeStreamCtxt(patstream);
13766
0
                return(-1);
13767
0
            }
13768
344k
            ctxt->opCount++;
13769
344k
        }
13770
13771
344k
  switch (cur->type) {
13772
106k
      case XML_ELEMENT_NODE:
13773
299k
      case XML_TEXT_NODE:
13774
307k
      case XML_CDATA_SECTION_NODE:
13775
325k
      case XML_COMMENT_NODE:
13776
344k
      case XML_PI_NODE:
13777
344k
    if (cur->type == XML_ELEMENT_NODE) {
13778
106k
        ret = xmlStreamPush(patstream, cur->name,
13779
106k
        (cur->ns ? cur->ns->href : NULL));
13780
238k
    } else if (eval_all_nodes)
13781
41.4k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13782
196k
    else
13783
196k
        break;
13784
13785
147k
    if (ret < 0) {
13786
        /* NOP. */
13787
147k
    } else if (ret == 1) {
13788
42.5k
        if (toBool)
13789
0
      goto return_1;
13790
42.5k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13791
42.5k
            < 0) {
13792
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13793
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13794
0
        }
13795
42.5k
    }
13796
147k
    if ((cur->children == NULL) || (depth >= max_depth)) {
13797
76.1k
        ret = xmlStreamPop(patstream);
13798
76.1k
        while (cur->next != NULL) {
13799
60.1k
      cur = cur->next;
13800
60.1k
      if ((cur->type != XML_ENTITY_DECL) &&
13801
60.1k
          (cur->type != XML_DTD_NODE))
13802
60.1k
          goto next_node;
13803
60.1k
        }
13804
76.1k
    }
13805
87.4k
      default:
13806
87.4k
    break;
13807
344k
  }
13808
13809
306k
scan_children:
13810
306k
  if (cur->type == XML_NAMESPACE_DECL) break;
13811
306k
  if ((cur->children != NULL) && (depth < max_depth)) {
13812
      /*
13813
       * Do not descend on entities declarations
13814
       */
13815
90.5k
      if (cur->children->type != XML_ENTITY_DECL) {
13816
90.5k
    cur = cur->children;
13817
90.5k
    depth++;
13818
    /*
13819
     * Skip DTDs
13820
     */
13821
90.5k
    if (cur->type != XML_DTD_NODE)
13822
90.5k
        continue;
13823
90.5k
      }
13824
90.5k
  }
13825
13826
215k
  if (cur == limit)
13827
2.83k
      break;
13828
13829
212k
  while (cur->next != NULL) {
13830
130k
      cur = cur->next;
13831
130k
      if ((cur->type != XML_ENTITY_DECL) &&
13832
130k
    (cur->type != XML_DTD_NODE))
13833
130k
    goto next_node;
13834
130k
  }
13835
13836
90.5k
  do {
13837
90.5k
      cur = cur->parent;
13838
90.5k
      depth--;
13839
90.5k
      if ((cur == NULL) || (cur == limit) ||
13840
90.5k
                (cur->type == XML_DOCUMENT_NODE))
13841
19.0k
          goto done;
13842
71.4k
      if (cur->type == XML_ELEMENT_NODE) {
13843
71.4k
    ret = xmlStreamPop(patstream);
13844
71.4k
      } 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
71.4k
      if (cur->next != NULL) {
13853
63.6k
    cur = cur->next;
13854
63.6k
    break;
13855
63.6k
      }
13856
71.4k
  } while (cur != NULL);
13857
13858
154k
    } while ((cur != NULL) && (depth >= 0));
13859
13860
21.9k
done:
13861
13862
21.9k
    if (patstream)
13863
21.9k
  xmlFreeStreamCtxt(patstream);
13864
21.9k
    return(0);
13865
13866
0
return_1:
13867
0
    if (patstream)
13868
0
  xmlFreeStreamCtxt(patstream);
13869
0
    return(1);
13870
190k
}
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
229k
{
13883
229k
    xmlXPathCompExprPtr comp;
13884
229k
    int oldDepth;
13885
13886
229k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13887
0
  return(-1);
13888
13889
229k
    if (ctxt->valueTab == NULL) {
13890
  /* Allocate the value stack */
13891
3.81k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13892
3.81k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13893
3.81k
  if (ctxt->valueTab == NULL) {
13894
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13895
0
      return(-1);
13896
0
  }
13897
3.81k
  ctxt->valueNr = 0;
13898
3.81k
  ctxt->valueMax = 10;
13899
3.81k
  ctxt->value = NULL;
13900
3.81k
        ctxt->valueFrame = 0;
13901
3.81k
    }
13902
229k
#ifdef XPATH_STREAMING
13903
229k
    if (ctxt->comp->stream) {
13904
26.1k
  int res;
13905
13906
26.1k
  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
26.1k
  } else {
13915
26.1k
      xmlXPathObjectPtr resObj = NULL;
13916
13917
      /*
13918
      * Evaluation to a sequence.
13919
      */
13920
26.1k
      res = xmlXPathRunStreamEval(ctxt->context,
13921
26.1k
    ctxt->comp->stream, &resObj, 0);
13922
13923
26.1k
      if ((res != -1) && (resObj != NULL)) {
13924
26.1k
    valuePush(ctxt, resObj);
13925
26.1k
    return(0);
13926
26.1k
      }
13927
0
      if (resObj != NULL)
13928
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13929
0
  }
13930
  /*
13931
  * QUESTION TODO: This falls back to normal XPath evaluation
13932
  * if res == -1. Is this intended?
13933
  */
13934
26.1k
    }
13935
203k
#endif
13936
203k
    comp = ctxt->comp;
13937
203k
    if (comp->last < 0) {
13938
0
  xmlGenericError(xmlGenericErrorContext,
13939
0
      "xmlXPathRunEval: last is less than zero\n");
13940
0
  return(-1);
13941
0
    }
13942
203k
    oldDepth = ctxt->context->depth;
13943
203k
    if (toBool)
13944
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13945
0
      &comp->steps[comp->last], 0));
13946
203k
    else
13947
203k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13948
203k
    ctxt->context->depth = oldDepth;
13949
13950
203k
    return(0);
13951
203k
}
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.9M
                                xmlXPathObjectPtr res) {
14016
24.9M
    if ((ctxt == NULL) || (res == NULL)) return(0);
14017
24.9M
    switch (res->type) {
14018
0
        case XPATH_BOOLEAN:
14019
0
      return(res->boolval);
14020
7.56M
        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
7.56M
      return(res->floatval == ctxt->context->proximityPosition);
14026
0
#endif
14027
7.52M
        case XPATH_NODESET:
14028
7.52M
        case XPATH_XSLT_TREE:
14029
7.52M
      if (res->nodesetval == NULL)
14030
1.27M
    return(0);
14031
6.25M
      return(res->nodesetval->nodeNr != 0);
14032
9.80M
        case XPATH_STRING:
14033
9.80M
      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
0
        default:
14043
0
      STRANGE
14044
24.9M
    }
14045
0
    return(0);
14046
24.9M
}
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
234k
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
234k
    xmlPatternPtr stream;
14065
234k
    xmlXPathCompExprPtr comp;
14066
234k
    xmlDictPtr dict = NULL;
14067
234k
    const xmlChar **namespaces = NULL;
14068
234k
    xmlNsPtr ns;
14069
234k
    int i, j;
14070
14071
234k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14072
234k
        (!xmlStrchr(str, '@'))) {
14073
57.8k
  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
57.8k
  tmp = xmlStrchr(str, ':');
14085
57.8k
  if ((tmp != NULL) &&
14086
57.8k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14087
13.4k
      return(NULL);
14088
14089
44.4k
  if (ctxt != NULL) {
14090
44.4k
      dict = ctxt->dict;
14091
44.4k
      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
44.4k
  }
14106
14107
44.4k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14108
44.4k
  if (namespaces != NULL) {
14109
0
      xmlFree((xmlChar **)namespaces);
14110
0
  }
14111
44.4k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14112
8.04k
      comp = xmlXPathNewCompExpr();
14113
8.04k
      if (comp == NULL) {
14114
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14115
0
    return(NULL);
14116
0
      }
14117
8.04k
      comp->stream = stream;
14118
8.04k
      comp->dict = dict;
14119
8.04k
      if (comp->dict)
14120
0
    xmlDictReference(comp->dict);
14121
8.04k
      return(comp);
14122
8.04k
  }
14123
36.3k
  xmlFreePattern(stream);
14124
36.3k
    }
14125
212k
    return(NULL);
14126
234k
}
14127
#endif /* XPATH_STREAMING */
14128
14129
static void
14130
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14131
                           xmlXPathStepOpPtr op)
14132
6.69M
{
14133
6.69M
    xmlXPathCompExprPtr comp = pctxt->comp;
14134
6.69M
    xmlXPathContextPtr ctxt;
14135
14136
    /*
14137
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14138
    * internal representation.
14139
    */
14140
14141
6.69M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14142
6.69M
        (op->ch1 != -1) &&
14143
6.69M
        (op->ch2 == -1 /* no predicate */))
14144
1.95M
    {
14145
1.95M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14146
14147
1.95M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14148
1.95M
            ((xmlXPathAxisVal) prevop->value ==
14149
821k
                AXIS_DESCENDANT_OR_SELF) &&
14150
1.95M
            (prevop->ch2 == -1) &&
14151
1.95M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14152
1.95M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14153
376k
        {
14154
            /*
14155
            * This is a "descendant-or-self::node()" without predicates.
14156
            * Try to eliminate it.
14157
            */
14158
14159
376k
            switch ((xmlXPathAxisVal) op->value) {
14160
314k
                case AXIS_CHILD:
14161
314k
                case AXIS_DESCENDANT:
14162
                    /*
14163
                    * Convert "descendant-or-self::node()/child::" or
14164
                    * "descendant-or-self::node()/descendant::" to
14165
                    * "descendant::"
14166
                    */
14167
314k
                    op->ch1   = prevop->ch1;
14168
314k
                    op->value = AXIS_DESCENDANT;
14169
314k
                    break;
14170
174
                case AXIS_SELF:
14171
5.56k
                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
5.56k
                    op->ch1   = prevop->ch1;
14178
5.56k
                    op->value = AXIS_DESCENDANT_OR_SELF;
14179
5.56k
                    break;
14180
56.2k
                default:
14181
56.2k
                    break;
14182
376k
            }
14183
376k
  }
14184
1.95M
    }
14185
14186
    /* OP_VALUE has invalid ch1. */
14187
6.69M
    if (op->op == XPATH_OP_VALUE)
14188
536k
        return;
14189
14190
    /* Recurse */
14191
6.15M
    ctxt = pctxt->context;
14192
6.15M
    if (ctxt != NULL) {
14193
6.15M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14194
972
            return;
14195
6.15M
        ctxt->depth += 1;
14196
6.15M
    }
14197
6.15M
    if (op->ch1 != -1)
14198
4.45M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14199
6.15M
    if (op->ch2 != -1)
14200
2.08M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14201
6.15M
    if (ctxt != NULL)
14202
6.15M
        ctxt->depth -= 1;
14203
6.15M
}
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
230k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14217
230k
    xmlXPathParserContextPtr pctxt;
14218
230k
    xmlXPathCompExprPtr comp;
14219
230k
    int oldDepth = 0;
14220
14221
230k
#ifdef XPATH_STREAMING
14222
230k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14223
230k
    if (comp != NULL)
14224
8.02k
        return(comp);
14225
222k
#endif
14226
14227
222k
    xmlInitParser();
14228
14229
222k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14230
222k
    if (pctxt == NULL)
14231
0
        return NULL;
14232
222k
    if (ctxt != NULL)
14233
222k
        oldDepth = ctxt->depth;
14234
222k
    xmlXPathCompileExpr(pctxt, 1);
14235
222k
    if (ctxt != NULL)
14236
222k
        ctxt->depth = oldDepth;
14237
14238
222k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14239
54.7k
    {
14240
54.7k
        xmlXPathFreeParserContext(pctxt);
14241
54.7k
        return(NULL);
14242
54.7k
    }
14243
14244
167k
    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
19.4k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14252
19.4k
  comp = NULL;
14253
148k
    } else {
14254
148k
  comp = pctxt->comp;
14255
148k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14256
147k
            if (ctxt != NULL)
14257
147k
                oldDepth = ctxt->depth;
14258
147k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14259
147k
            if (ctxt != NULL)
14260
147k
                ctxt->depth = oldDepth;
14261
147k
  }
14262
148k
  pctxt->comp = NULL;
14263
148k
    }
14264
167k
    xmlXPathFreeParserContext(pctxt);
14265
14266
167k
    if (comp != NULL) {
14267
148k
  comp->expr = xmlStrdup(str);
14268
#ifdef DEBUG_EVAL_COUNTS
14269
  comp->string = xmlStrdup(str);
14270
  comp->nb = 0;
14271
#endif
14272
148k
    }
14273
167k
    return(comp);
14274
222k
}
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
225k
{
14309
225k
    xmlXPathParserContextPtr pctxt;
14310
225k
    xmlXPathObjectPtr resObj;
14311
#ifndef LIBXML_THREAD_ENABLED
14312
    static int reentance = 0;
14313
#endif
14314
225k
    int res;
14315
14316
225k
    CHECK_CTXT_NEG(ctxt)
14317
14318
225k
    if (comp == NULL)
14319
0
  return(-1);
14320
225k
    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
225k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14336
225k
    res = xmlXPathRunEval(pctxt, toBool);
14337
14338
225k
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14339
34.7k
        resObj = NULL;
14340
191k
    } else {
14341
191k
        resObj = valuePop(pctxt);
14342
191k
        if (resObj == NULL) {
14343
0
            if (!toBool)
14344
0
                xmlGenericError(xmlGenericErrorContext,
14345
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14346
191k
        } 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
191k
    }
14352
14353
225k
    if (resObjPtr)
14354
225k
        *resObjPtr = resObj;
14355
55
    else
14356
55
        xmlXPathReleaseObject(ctxt, resObj);
14357
14358
225k
    pctxt->comp = NULL;
14359
225k
    xmlXPathFreeParserContext(pctxt);
14360
#ifndef LIBXML_THREAD_ENABLED
14361
    reentance--;
14362
#endif
14363
14364
225k
    return(res);
14365
225k
}
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
225k
{
14380
225k
    xmlXPathObjectPtr res = NULL;
14381
14382
225k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14383
225k
    return(res);
14384
225k
}
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
3.85k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14413
3.85k
#ifdef XPATH_STREAMING
14414
3.85k
    xmlXPathCompExprPtr comp;
14415
3.85k
#endif
14416
3.85k
    int oldDepth = 0;
14417
14418
3.85k
    if (ctxt == NULL) return;
14419
14420
3.85k
#ifdef XPATH_STREAMING
14421
3.85k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422
3.85k
    if (comp != NULL) {
14423
17
        if (ctxt->comp != NULL)
14424
17
      xmlXPathFreeCompExpr(ctxt->comp);
14425
17
        ctxt->comp = comp;
14426
17
    } else
14427
3.83k
#endif
14428
3.83k
    {
14429
3.83k
        if (ctxt->context != NULL)
14430
3.83k
            oldDepth = ctxt->context->depth;
14431
3.83k
  xmlXPathCompileExpr(ctxt, 1);
14432
3.83k
        if (ctxt->context != NULL)
14433
3.83k
            ctxt->context->depth = oldDepth;
14434
3.83k
        CHECK_ERROR;
14435
14436
        /* Check for trailing characters. */
14437
3.82k
        if (*ctxt->cur != 0)
14438
3.80k
            XP_ERROR(XPATH_EXPR_ERROR);
14439
14440
3.80k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441
3.78k
            if (ctxt->context != NULL)
14442
3.78k
                oldDepth = ctxt->context->depth;
14443
3.78k
      xmlXPathOptimizeExpression(ctxt,
14444
3.78k
    &ctxt->comp->steps[ctxt->comp->last]);
14445
3.78k
            if (ctxt->context != NULL)
14446
3.78k
                ctxt->context->depth = oldDepth;
14447
3.78k
        }
14448
3.80k
    }
14449
14450
3.81k
    xmlXPathRunEval(ctxt, 0);
14451
3.81k
}
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
3.85k
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14465
3.85k
    xmlXPathParserContextPtr ctxt;
14466
3.85k
    xmlXPathObjectPtr res;
14467
14468
3.85k
    CHECK_CTXT(ctx)
14469
14470
3.85k
    xmlInitParser();
14471
14472
3.85k
    ctxt = xmlXPathNewParserContext(str, ctx);
14473
3.85k
    if (ctxt == NULL)
14474
0
        return NULL;
14475
3.85k
    xmlXPathEvalExpr(ctxt);
14476
14477
3.85k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14478
40
  res = NULL;
14479
3.81k
    } else {
14480
3.81k
  res = valuePop(ctxt);
14481
3.81k
        if (res == NULL) {
14482
0
            xmlGenericError(xmlGenericErrorContext,
14483
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14484
3.81k
        } 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
3.81k
    }
14490
14491
3.85k
    xmlXPathFreeParserContext(ctxt);
14492
3.85k
    return(res);
14493
3.85k
}
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
467k
{
14676
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14677
467k
                         xmlXPathBooleanFunction);
14678
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14679
467k
                         xmlXPathCeilingFunction);
14680
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14681
467k
                         xmlXPathCountFunction);
14682
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14683
467k
                         xmlXPathConcatFunction);
14684
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14685
467k
                         xmlXPathContainsFunction);
14686
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14687
467k
                         xmlXPathIdFunction);
14688
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14689
467k
                         xmlXPathFalseFunction);
14690
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14691
467k
                         xmlXPathFloorFunction);
14692
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14693
467k
                         xmlXPathLastFunction);
14694
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14695
467k
                         xmlXPathLangFunction);
14696
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14697
467k
                         xmlXPathLocalNameFunction);
14698
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14699
467k
                         xmlXPathNotFunction);
14700
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14701
467k
                         xmlXPathNameFunction);
14702
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14703
467k
                         xmlXPathNamespaceURIFunction);
14704
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14705
467k
                         xmlXPathNormalizeFunction);
14706
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14707
467k
                         xmlXPathNumberFunction);
14708
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14709
467k
                         xmlXPathPositionFunction);
14710
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14711
467k
                         xmlXPathRoundFunction);
14712
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14713
467k
                         xmlXPathStringFunction);
14714
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14715
467k
                         xmlXPathStringLengthFunction);
14716
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14717
467k
                         xmlXPathStartsWithFunction);
14718
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14719
467k
                         xmlXPathSubstringFunction);
14720
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14721
467k
                         xmlXPathSubstringBeforeFunction);
14722
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14723
467k
                         xmlXPathSubstringAfterFunction);
14724
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14725
467k
                         xmlXPathSumFunction);
14726
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14727
467k
                         xmlXPathTrueFunction);
14728
467k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14729
467k
                         xmlXPathTranslateFunction);
14730
14731
467k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14732
467k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14733
467k
                         xmlXPathEscapeUriFunction);
14734
467k
}
14735
14736
#endif /* LIBXML_XPATH_ENABLED */