Coverage Report

Created: 2024-06-09 05:16

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