Coverage Report

Created: 2023-06-07 06:14

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/valid.h>
35
#include <libxml/xpath.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/parserInternals.h>
38
#include <libxml/hash.h>
39
#ifdef LIBXML_XPTR_LOCS_ENABLED
40
#include <libxml/xpointer.h>
41
#endif
42
#ifdef LIBXML_DEBUG_ENABLED
43
#include <libxml/debugXML.h>
44
#endif
45
#include <libxml/xmlerror.h>
46
#include <libxml/threads.h>
47
#include <libxml/globals.h>
48
#ifdef LIBXML_PATTERN_ENABLED
49
#include <libxml/pattern.h>
50
#endif
51
52
#include "private/buf.h"
53
#include "private/error.h"
54
#include "private/xpath.h"
55
56
#ifdef LIBXML_PATTERN_ENABLED
57
#define XPATH_STREAMING
58
#endif
59
60
#define TODO                \
61
128
    xmlGenericError(xmlGenericErrorContext,       \
62
128
      "Unimplemented block at %s:%d\n",       \
63
128
            __FILE__, __LINE__);
64
65
/**
66
 * WITH_TIM_SORT:
67
 *
68
 * Use the Timsort algorithm provided in timsort.h to sort
69
 * nodeset as this is a great improvement over the old Shell sort
70
 * used in xmlXPathNodeSetSort()
71
 */
72
#define WITH_TIM_SORT
73
74
/*
75
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
76
* If defined, this will use xmlXPathCmpNodesExt() instead of
77
* xmlXPathCmpNodes(). The new function is optimized comparison of
78
* non-element nodes; actually it will speed up comparison only if
79
* xmlXPathOrderDocElems() was called in order to index the elements of
80
* a tree in document order; Libxslt does such an indexing, thus it will
81
* benefit from this optimization.
82
*/
83
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
84
85
/*
86
* XP_OPTIMIZED_FILTER_FIRST:
87
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
88
* in a way, that it stop evaluation at the first node.
89
*/
90
#define XP_OPTIMIZED_FILTER_FIRST
91
92
/*
93
* XP_DEBUG_OBJ_USAGE:
94
* Internal flag to enable tracking of how much XPath objects have been
95
* created.
96
*/
97
/* #define XP_DEBUG_OBJ_USAGE */
98
99
/*
100
 * XPATH_MAX_STEPS:
101
 * when compiling an XPath expression we arbitrary limit the maximum
102
 * number of step operation in the compiled expression. 1000000 is
103
 * an insanely large value which should never be reached under normal
104
 * circumstances
105
 */
106
828k
#define XPATH_MAX_STEPS 1000000
107
108
/*
109
 * XPATH_MAX_STACK_DEPTH:
110
 * when evaluating an XPath expression we arbitrary limit the maximum
111
 * number of object allowed to be pushed on the stack. 1000000 is
112
 * an insanely large value which should never be reached under normal
113
 * circumstances
114
 */
115
32
#define XPATH_MAX_STACK_DEPTH 1000000
116
117
/*
118
 * XPATH_MAX_NODESET_LENGTH:
119
 * when evaluating an XPath expression nodesets are created and we
120
 * arbitrary limit the maximum length of those node set. 10000000 is
121
 * an insanely large value which should never be reached under normal
122
 * circumstances, one would first need to construct an in memory tree
123
 * with more than 10 millions nodes.
124
 */
125
1.32M
#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
46.9M
#define XPATH_MAX_RECURSION_DEPTH 500
134
#elif defined(_WIN32)
135
/* Windows typically limits stack size to 1MB. */
136
#define XPATH_MAX_RECURSION_DEPTH 1000
137
#else
138
#define XPATH_MAX_RECURSION_DEPTH 5000
139
#endif
140
141
/*
142
 * TODO:
143
 * There are a few spots where some tests are done which depend upon ascii
144
 * data.  These should be enhanced for full UTF8 support (see particularly
145
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146
 */
147
148
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
149
150
/************************************************************************
151
 *                  *
152
 *      Floating point stuff        *
153
 *                  *
154
 ************************************************************************/
155
156
double xmlXPathNAN = 0.0;
157
double xmlXPathPINF = 0.0;
158
double xmlXPathNINF = 0.0;
159
160
/**
161
 * xmlXPathInit:
162
 *
163
 * DEPRECATED: Alias for xmlInitParser.
164
 */
165
void
166
0
xmlXPathInit(void) {
167
0
    xmlInitParser();
168
0
}
169
170
/**
171
 * xmlInitXPathInternal:
172
 *
173
 * Initialize the XPath environment
174
 */
175
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
176
void
177
2
xmlInitXPathInternal(void) {
178
2
#if defined(NAN) && defined(INFINITY)
179
2
    xmlXPathNAN = NAN;
180
2
    xmlXPathPINF = INFINITY;
181
2
    xmlXPathNINF = -INFINITY;
182
#else
183
    /* MSVC doesn't allow division by zero in constant expressions. */
184
    double zero = 0.0;
185
    xmlXPathNAN = 0.0 / zero;
186
    xmlXPathPINF = 1.0 / zero;
187
    xmlXPathNINF = -xmlXPathPINF;
188
#endif
189
2
}
190
191
/**
192
 * xmlXPathIsNaN:
193
 * @val:  a double value
194
 *
195
 * Returns 1 if the value is a NaN, 0 otherwise
196
 */
197
int
198
1.64M
xmlXPathIsNaN(double val) {
199
1.64M
#ifdef isnan
200
1.64M
    return isnan(val);
201
#else
202
    return !(val == val);
203
#endif
204
1.64M
}
205
206
/**
207
 * xmlXPathIsInf:
208
 * @val:  a double value
209
 *
210
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
211
 */
212
int
213
1.10M
xmlXPathIsInf(double val) {
214
1.10M
#ifdef isinf
215
1.10M
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
216
#else
217
    if (val >= xmlXPathPINF)
218
        return 1;
219
    if (val <= -xmlXPathPINF)
220
        return -1;
221
    return 0;
222
#endif
223
1.10M
}
224
225
#endif /* SCHEMAS or XPATH */
226
227
#ifdef LIBXML_XPATH_ENABLED
228
229
/*
230
 * TODO: when compatibility allows remove all "fake node libxslt" strings
231
 *       the test should just be name[0] = ' '
232
 */
233
#ifdef DEBUG_XPATH_EXPRESSION
234
#define DEBUG_STEP
235
#define DEBUG_EXPR
236
#define DEBUG_EVAL_COUNTS
237
#endif
238
239
static xmlNs xmlXPathXMLNamespaceStruct = {
240
    NULL,
241
    XML_NAMESPACE_DECL,
242
    XML_XML_NAMESPACE,
243
    BAD_CAST "xml",
244
    NULL,
245
    NULL
246
};
247
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
248
#ifndef LIBXML_THREAD_ENABLED
249
/*
250
 * Optimizer is disabled only when threaded apps are detected while
251
 * the library ain't compiled for thread safety.
252
 */
253
static int xmlXPathDisableOptimizer = 0;
254
#endif
255
256
static void
257
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
258
259
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
260
/**
261
 * xmlXPathCmpNodesExt:
262
 * @node1:  the first node
263
 * @node2:  the second node
264
 *
265
 * Compare two nodes w.r.t document order.
266
 * This one is optimized for handling of non-element nodes.
267
 *
268
 * Returns -2 in case of error 1 if first point < second point, 0 if
269
 *         it's the same node, -1 otherwise
270
 */
271
static int
272
59.0M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
273
59.0M
    int depth1, depth2;
274
59.0M
    int misc = 0, precedence1 = 0, precedence2 = 0;
275
59.0M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
276
59.0M
    xmlNodePtr cur, root;
277
59.0M
    ptrdiff_t l1, l2;
278
279
59.0M
    if ((node1 == NULL) || (node2 == NULL))
280
0
  return(-2);
281
282
59.0M
    if (node1 == node2)
283
0
  return(0);
284
285
    /*
286
     * a couple of optimizations which will avoid computations in most cases
287
     */
288
59.0M
    switch (node1->type) {
289
41.2M
  case XML_ELEMENT_NODE:
290
41.2M
      if (node2->type == XML_ELEMENT_NODE) {
291
32.0M
    if ((0 > (ptrdiff_t) node1->content) &&
292
32.0M
        (0 > (ptrdiff_t) node2->content) &&
293
32.0M
        (node1->doc == node2->doc))
294
6.33M
    {
295
6.33M
        l1 = -((ptrdiff_t) node1->content);
296
6.33M
        l2 = -((ptrdiff_t) node2->content);
297
6.33M
        if (l1 < l2)
298
3.08M
      return(1);
299
3.25M
        if (l1 > l2)
300
3.25M
      return(-1);
301
3.25M
    } else
302
25.7M
        goto turtle_comparison;
303
32.0M
      }
304
9.17M
      break;
305
9.17M
  case XML_ATTRIBUTE_NODE:
306
79.4k
      precedence1 = 1; /* element is owner */
307
79.4k
      miscNode1 = node1;
308
79.4k
      node1 = node1->parent;
309
79.4k
      misc = 1;
310
79.4k
      break;
311
16.8M
  case XML_TEXT_NODE:
312
16.8M
  case XML_CDATA_SECTION_NODE:
313
17.2M
  case XML_COMMENT_NODE:
314
17.4M
  case XML_PI_NODE: {
315
17.4M
      miscNode1 = node1;
316
      /*
317
      * Find nearest element node.
318
      */
319
17.4M
      if (node1->prev != NULL) {
320
10.7M
    do {
321
10.7M
        node1 = node1->prev;
322
10.7M
        if (node1->type == XML_ELEMENT_NODE) {
323
8.74M
      precedence1 = 3; /* element in prev-sibl axis */
324
8.74M
      break;
325
8.74M
        }
326
2.01M
        if (node1->prev == NULL) {
327
629k
      precedence1 = 2; /* element is parent */
328
      /*
329
      * URGENT TODO: Are there any cases, where the
330
      * parent of such a node is not an element node?
331
      */
332
629k
      node1 = node1->parent;
333
629k
      break;
334
629k
        }
335
2.01M
    } while (1);
336
9.37M
      } else {
337
8.10M
    precedence1 = 2; /* element is parent */
338
8.10M
    node1 = node1->parent;
339
8.10M
      }
340
17.4M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
341
17.4M
    (0 <= (ptrdiff_t) node1->content)) {
342
    /*
343
    * Fallback for whatever case.
344
    */
345
1.34M
    node1 = miscNode1;
346
1.34M
    precedence1 = 0;
347
1.34M
      } else
348
16.1M
    misc = 1;
349
17.4M
  }
350
0
      break;
351
143k
  case XML_NAMESPACE_DECL:
352
      /*
353
      * TODO: why do we return 1 for namespace nodes?
354
      */
355
143k
      return(1);
356
100k
  default:
357
100k
      break;
358
59.0M
    }
359
26.8M
    switch (node2->type) {
360
10.6M
  case XML_ELEMENT_NODE:
361
10.6M
      break;
362
78.3k
  case XML_ATTRIBUTE_NODE:
363
78.3k
      precedence2 = 1; /* element is owner */
364
78.3k
      miscNode2 = node2;
365
78.3k
      node2 = node2->parent;
366
78.3k
      misc = 1;
367
78.3k
      break;
368
15.3M
  case XML_TEXT_NODE:
369
15.3M
  case XML_CDATA_SECTION_NODE:
370
15.7M
  case XML_COMMENT_NODE:
371
15.9M
  case XML_PI_NODE: {
372
15.9M
      miscNode2 = node2;
373
15.9M
      if (node2->prev != NULL) {
374
10.0M
    do {
375
10.0M
        node2 = node2->prev;
376
10.0M
        if (node2->type == XML_ELEMENT_NODE) {
377
7.94M
      precedence2 = 3; /* element in prev-sibl axis */
378
7.94M
      break;
379
7.94M
        }
380
2.07M
        if (node2->prev == NULL) {
381
599k
      precedence2 = 2; /* element is parent */
382
599k
      node2 = node2->parent;
383
599k
      break;
384
599k
        }
385
2.07M
    } while (1);
386
8.54M
      } else {
387
7.42M
    precedence2 = 2; /* element is parent */
388
7.42M
    node2 = node2->parent;
389
7.42M
      }
390
15.9M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
391
15.9M
    (0 <= (ptrdiff_t) node2->content))
392
1.41M
      {
393
1.41M
    node2 = miscNode2;
394
1.41M
    precedence2 = 0;
395
1.41M
      } else
396
14.5M
    misc = 1;
397
15.9M
  }
398
0
      break;
399
4.09k
  case XML_NAMESPACE_DECL:
400
4.09k
      return(1);
401
118k
  default:
402
118k
      break;
403
26.8M
    }
404
26.8M
    if (misc) {
405
24.8M
  if (node1 == node2) {
406
8.98M
      if (precedence1 == precedence2) {
407
    /*
408
    * The ugly case; but normally there aren't many
409
    * adjacent non-element nodes around.
410
    */
411
568k
    cur = miscNode2->prev;
412
626k
    while (cur != NULL) {
413
519k
        if (cur == miscNode1)
414
426k
      return(1);
415
92.2k
        if (cur->type == XML_ELEMENT_NODE)
416
34.2k
      return(-1);
417
58.0k
        cur = cur->prev;
418
58.0k
    }
419
107k
    return (-1);
420
8.41M
      } else {
421
    /*
422
    * Evaluate based on higher precedence wrt to the element.
423
    * TODO: This assumes attributes are sorted before content.
424
    *   Is this 100% correct?
425
    */
426
8.41M
    if (precedence1 < precedence2)
427
5.63M
        return(1);
428
2.77M
    else
429
2.77M
        return(-1);
430
8.41M
      }
431
8.98M
  }
432
  /*
433
  * Special case: One of the helper-elements is contained by the other.
434
  * <foo>
435
  *   <node2>
436
  *     <node1>Text-1(precedence1 == 2)</node1>
437
  *   </node2>
438
  *   Text-6(precedence2 == 3)
439
  * </foo>
440
  */
441
15.8M
  if ((precedence2 == 3) && (precedence1 > 1)) {
442
2.22M
      cur = node1->parent;
443
6.15M
      while (cur) {
444
4.65M
    if (cur == node2)
445
732k
        return(1);
446
3.92M
    cur = cur->parent;
447
3.92M
      }
448
2.22M
  }
449
15.1M
  if ((precedence1 == 3) && (precedence2 > 1)) {
450
1.54M
      cur = node2->parent;
451
5.11M
      while (cur) {
452
3.63M
    if (cur == node1)
453
69.9k
        return(-1);
454
3.56M
    cur = cur->parent;
455
3.56M
      }
456
1.54M
  }
457
15.1M
    }
458
459
    /*
460
     * Speedup using document order if available.
461
     */
462
17.0M
    if ((node1->type == XML_ELEMENT_NODE) &&
463
17.0M
  (node2->type == XML_ELEMENT_NODE) &&
464
17.0M
  (0 > (ptrdiff_t) node1->content) &&
465
17.0M
  (0 > (ptrdiff_t) node2->content) &&
466
17.0M
  (node1->doc == node2->doc)) {
467
468
14.9M
  l1 = -((ptrdiff_t) node1->content);
469
14.9M
  l2 = -((ptrdiff_t) node2->content);
470
14.9M
  if (l1 < l2)
471
7.07M
      return(1);
472
7.84M
  if (l1 > l2)
473
7.84M
      return(-1);
474
7.84M
    }
475
476
27.8M
turtle_comparison:
477
478
27.8M
    if (node1 == node2->prev)
479
23.9M
  return(1);
480
3.86M
    if (node1 == node2->next)
481
98.0k
  return(-1);
482
    /*
483
     * compute depth to root
484
     */
485
14.3M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
486
10.8M
  if (cur->parent == node1)
487
291k
      return(1);
488
10.5M
  depth2++;
489
10.5M
    }
490
3.47M
    root = cur;
491
11.9M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
492
8.67M
  if (cur->parent == node2)
493
193k
      return(-1);
494
8.47M
  depth1++;
495
8.47M
    }
496
    /*
497
     * Distinct document (or distinct entities :-( ) case.
498
     */
499
3.28M
    if (root != cur) {
500
1.67M
  return(-2);
501
1.67M
    }
502
    /*
503
     * get the nearest common ancestor.
504
     */
505
2.50M
    while (depth1 > depth2) {
506
893k
  depth1--;
507
893k
  node1 = node1->parent;
508
893k
    }
509
4.00M
    while (depth2 > depth1) {
510
2.39M
  depth2--;
511
2.39M
  node2 = node2->parent;
512
2.39M
    }
513
2.51M
    while (node1->parent != node2->parent) {
514
898k
  node1 = node1->parent;
515
898k
  node2 = node2->parent;
516
  /* should not happen but just in case ... */
517
898k
  if ((node1 == NULL) || (node2 == NULL))
518
0
      return(-2);
519
898k
    }
520
    /*
521
     * Find who's first.
522
     */
523
1.61M
    if (node1 == node2->prev)
524
230k
  return(1);
525
1.38M
    if (node1 == node2->next)
526
117k
  return(-1);
527
    /*
528
     * Speedup using document order if available.
529
     */
530
1.26M
    if ((node1->type == XML_ELEMENT_NODE) &&
531
1.26M
  (node2->type == XML_ELEMENT_NODE) &&
532
1.26M
  (0 > (ptrdiff_t) node1->content) &&
533
1.26M
  (0 > (ptrdiff_t) node2->content) &&
534
1.26M
  (node1->doc == node2->doc)) {
535
536
0
  l1 = -((ptrdiff_t) node1->content);
537
0
  l2 = -((ptrdiff_t) node2->content);
538
0
  if (l1 < l2)
539
0
      return(1);
540
0
  if (l1 > l2)
541
0
      return(-1);
542
0
    }
543
544
11.9M
    for (cur = node1->next;cur != NULL;cur = cur->next)
545
11.4M
  if (cur == node2)
546
702k
      return(1);
547
563k
    return(-1); /* assume there is no sibling list corruption */
548
1.26M
}
549
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
550
551
/*
552
 * Wrapper for the Timsort algorithm from timsort.h
553
 */
554
#ifdef WITH_TIM_SORT
555
#define SORT_NAME libxml_domnode
556
19.4M
#define SORT_TYPE xmlNodePtr
557
/**
558
 * wrap_cmp:
559
 * @x: a node
560
 * @y: another node
561
 *
562
 * Comparison function for the Timsort implementation
563
 *
564
 * Returns -2 in case of error -1 if first point < second point, 0 if
565
 *         it's the same node, +1 otherwise
566
 */
567
static
568
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
569
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
570
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
571
59.0M
    {
572
59.0M
        int res = xmlXPathCmpNodesExt(x, y);
573
59.0M
        return res == -2 ? res : -res;
574
59.0M
    }
575
#else
576
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
577
    {
578
        int res = xmlXPathCmpNodes(x, y);
579
        return res == -2 ? res : -res;
580
    }
581
#endif
582
59.0M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
583
#include "timsort.h"
584
#endif /* WITH_TIM_SORT */
585
586
/************************************************************************
587
 *                  *
588
 *      Error handling routines       *
589
 *                  *
590
 ************************************************************************/
591
592
/**
593
 * XP_ERRORNULL:
594
 * @X:  the error code
595
 *
596
 * Macro to raise an XPath error and return NULL.
597
 */
598
#define XP_ERRORNULL(X)             \
599
72.3k
    { xmlXPathErr(ctxt, X); return(NULL); }
600
601
/*
602
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603
 */
604
static const char* const xmlXPathErrorMessages[] = {
605
    "Ok\n",
606
    "Number encoding\n",
607
    "Unfinished literal\n",
608
    "Start of literal\n",
609
    "Expected $ for variable reference\n",
610
    "Undefined variable\n",
611
    "Invalid predicate\n",
612
    "Invalid expression\n",
613
    "Missing closing curly brace\n",
614
    "Unregistered function\n",
615
    "Invalid operand\n",
616
    "Invalid type\n",
617
    "Invalid number of arguments\n",
618
    "Invalid context size\n",
619
    "Invalid context position\n",
620
    "Memory allocation error\n",
621
    "Syntax error\n",
622
    "Resource error\n",
623
    "Sub resource error\n",
624
    "Undefined namespace prefix\n",
625
    "Encoding error\n",
626
    "Char out of XML range\n",
627
    "Invalid or incomplete context\n",
628
    "Stack usage error\n",
629
    "Forbidden variable\n",
630
    "Operation limit exceeded\n",
631
    "Recursion limit exceeded\n",
632
    "?? Unknown error ??\n" /* Must be last in the list! */
633
};
634
1.39M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
635
1.39M
       sizeof(xmlXPathErrorMessages[0])) - 1)
636
/**
637
 * xmlXPathErrMemory:
638
 * @ctxt:  an XPath context
639
 * @extra:  extra information
640
 *
641
 * Handle a redefinition of attribute error
642
 */
643
static void
644
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
645
120k
{
646
120k
    if (ctxt != NULL) {
647
49.7k
        xmlResetError(&ctxt->lastError);
648
49.7k
        if (extra) {
649
48.4k
            xmlChar buf[200];
650
651
48.4k
            xmlStrPrintf(buf, 200,
652
48.4k
                         "Memory allocation failed : %s\n",
653
48.4k
                         extra);
654
48.4k
            ctxt->lastError.message = (char *) xmlStrdup(buf);
655
48.4k
        } else {
656
1.34k
            ctxt->lastError.message = (char *)
657
1.34k
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
658
1.34k
        }
659
49.7k
        ctxt->lastError.domain = XML_FROM_XPATH;
660
49.7k
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
661
49.7k
  if (ctxt->error != NULL)
662
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
663
70.3k
    } else {
664
70.3k
        if (extra)
665
70.3k
            __xmlRaiseError(NULL, NULL, NULL,
666
70.3k
                            NULL, NULL, XML_FROM_XPATH,
667
70.3k
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668
70.3k
                            extra, NULL, NULL, 0, 0,
669
70.3k
                            "Memory allocation failed : %s\n", extra);
670
0
        else
671
0
            __xmlRaiseError(NULL, NULL, NULL,
672
0
                            NULL, NULL, XML_FROM_XPATH,
673
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
674
0
                            NULL, NULL, NULL, 0, 0,
675
0
                            "Memory allocation failed\n");
676
70.3k
    }
677
120k
}
678
679
/**
680
 * xmlXPathPErrMemory:
681
 * @ctxt:  an XPath parser context
682
 * @extra:  extra information
683
 *
684
 * Handle a redefinition of attribute error
685
 */
686
static void
687
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
688
656
{
689
656
    if (ctxt == NULL)
690
0
  xmlXPathErrMemory(NULL, extra);
691
656
    else {
692
656
  ctxt->error = XPATH_MEMORY_ERROR;
693
656
  xmlXPathErrMemory(ctxt->context, extra);
694
656
    }
695
656
}
696
697
/**
698
 * xmlXPathErr:
699
 * @ctxt:  a XPath parser context
700
 * @error:  the error code
701
 *
702
 * Handle an XPath error
703
 */
704
void
705
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
706
1.39M
{
707
1.39M
    if ((error < 0) || (error > MAXERRNO))
708
0
  error = MAXERRNO;
709
1.39M
    if (ctxt == NULL) {
710
0
  __xmlRaiseError(NULL, NULL, NULL,
711
0
      NULL, NULL, XML_FROM_XPATH,
712
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713
0
      XML_ERR_ERROR, NULL, 0,
714
0
      NULL, NULL, NULL, 0, 0,
715
0
      "%s", xmlXPathErrorMessages[error]);
716
0
  return;
717
0
    }
718
    /* Only report the first error */
719
1.39M
    if (ctxt->error != 0)
720
91.5k
        return;
721
1.30M
    ctxt->error = error;
722
1.30M
    if (ctxt->context == NULL) {
723
0
  __xmlRaiseError(NULL, NULL, NULL,
724
0
      NULL, NULL, XML_FROM_XPATH,
725
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726
0
      XML_ERR_ERROR, NULL, 0,
727
0
      (const char *) ctxt->base, NULL, NULL,
728
0
      ctxt->cur - ctxt->base, 0,
729
0
      "%s", xmlXPathErrorMessages[error]);
730
0
  return;
731
0
    }
732
733
    /* cleanup current last error */
734
1.30M
    xmlResetError(&ctxt->context->lastError);
735
736
1.30M
    ctxt->context->lastError.domain = XML_FROM_XPATH;
737
1.30M
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738
1.30M
                           XPATH_EXPRESSION_OK;
739
1.30M
    ctxt->context->lastError.level = XML_ERR_ERROR;
740
1.30M
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741
1.30M
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742
1.30M
    ctxt->context->lastError.node = ctxt->context->debugNode;
743
1.30M
    if (ctxt->context->error != NULL) {
744
0
  ctxt->context->error(ctxt->context->userData,
745
0
                       &ctxt->context->lastError);
746
1.30M
    } else {
747
1.30M
  __xmlRaiseError(NULL, NULL, NULL,
748
1.30M
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749
1.30M
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750
1.30M
      XML_ERR_ERROR, NULL, 0,
751
1.30M
      (const char *) ctxt->base, NULL, NULL,
752
1.30M
      ctxt->cur - ctxt->base, 0,
753
1.30M
      "%s", xmlXPathErrorMessages[error]);
754
1.30M
    }
755
756
1.30M
}
757
758
/**
759
 * xmlXPatherror:
760
 * @ctxt:  the XPath Parser context
761
 * @file:  the file name
762
 * @line:  the line number
763
 * @no:  the error number
764
 *
765
 * Formats an error message.
766
 */
767
void
768
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
769
159k
              int line ATTRIBUTE_UNUSED, int no) {
770
159k
    xmlXPathErr(ctxt, no);
771
159k
}
772
773
/**
774
 * xmlXPathCheckOpLimit:
775
 * @ctxt:  the XPath Parser context
776
 * @opCount:  the number of operations to be added
777
 *
778
 * Adds opCount to the running total of operations and returns -1 if the
779
 * operation limit is exceeded. Returns 0 otherwise.
780
 */
781
static int
782
57.5M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783
57.5M
    xmlXPathContextPtr xpctxt = ctxt->context;
784
785
57.5M
    if ((opCount > xpctxt->opLimit) ||
786
57.5M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787
430k
        xpctxt->opCount = xpctxt->opLimit;
788
430k
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789
430k
        return(-1);
790
430k
    }
791
792
57.1M
    xpctxt->opCount += opCount;
793
57.1M
    return(0);
794
57.5M
}
795
796
#define OP_LIMIT_EXCEEDED(ctxt, n) \
797
55.4M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
798
799
/************************************************************************
800
 *                  *
801
 *      Utilities         *
802
 *                  *
803
 ************************************************************************/
804
805
/**
806
 * xsltPointerList:
807
 *
808
 * Pointer-list for various purposes.
809
 */
810
typedef struct _xmlPointerList xmlPointerList;
811
typedef xmlPointerList *xmlPointerListPtr;
812
struct _xmlPointerList {
813
    void **items;
814
    int number;
815
    int size;
816
};
817
/*
818
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
819
* and here, we should make the functions public.
820
*/
821
static int
822
xmlPointerListAddSize(xmlPointerListPtr list,
823
           void *item,
824
           int initialSize)
825
14.7M
{
826
14.7M
    if (list->size <= list->number) {
827
53.8k
        void **tmp;
828
53.8k
        size_t newSize;
829
830
53.8k
        if (list->size == 0) {
831
25.4k
            if (initialSize <= 0)
832
425
                initialSize = 1;
833
25.4k
            newSize = initialSize;
834
28.4k
        } else {
835
28.4k
            if (list->size > 50000000) {
836
0
                xmlXPathErrMemory(NULL,
837
0
                    "xmlPointerListAddSize: re-allocating item\n");
838
0
                return(-1);
839
0
            }
840
28.4k
      newSize = list->size * 2;
841
28.4k
        }
842
53.8k
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843
53.8k
  if (tmp == NULL) {
844
13.5k
      xmlXPathErrMemory(NULL,
845
13.5k
    "xmlPointerListAddSize: re-allocating item\n");
846
13.5k
      return(-1);
847
13.5k
  }
848
40.3k
        list->items = tmp;
849
40.3k
        list->size = newSize;
850
40.3k
    }
851
14.7M
    list->items[list->number++] = item;
852
14.7M
    return(0);
853
14.7M
}
854
855
/**
856
 * xsltPointerListCreate:
857
 *
858
 * Creates an xsltPointerList structure.
859
 *
860
 * Returns a xsltPointerList structure or NULL in case of an error.
861
 */
862
static xmlPointerListPtr
863
xmlPointerListCreate(int initialSize)
864
28.9k
{
865
28.9k
    xmlPointerListPtr ret;
866
867
28.9k
    ret = xmlMalloc(sizeof(xmlPointerList));
868
28.9k
    if (ret == NULL) {
869
3.95k
  xmlXPathErrMemory(NULL,
870
3.95k
      "xmlPointerListCreate: allocating item\n");
871
3.95k
  return (NULL);
872
3.95k
    }
873
25.0k
    memset(ret, 0, sizeof(xmlPointerList));
874
25.0k
    if (initialSize > 0) {
875
25.0k
  xmlPointerListAddSize(ret, NULL, initialSize);
876
25.0k
  ret->number = 0;
877
25.0k
    }
878
25.0k
    return (ret);
879
28.9k
}
880
881
/**
882
 * xsltPointerListFree:
883
 *
884
 * Frees the xsltPointerList structure. This does not free
885
 * the content of the list.
886
 */
887
static void
888
xmlPointerListFree(xmlPointerListPtr list)
889
25.0k
{
890
25.0k
    if (list == NULL)
891
0
  return;
892
25.0k
    if (list->items != NULL)
893
24.9k
  xmlFree(list->items);
894
25.0k
    xmlFree(list);
895
25.0k
}
896
897
/************************************************************************
898
 *                  *
899
 *      Parser Types          *
900
 *                  *
901
 ************************************************************************/
902
903
/*
904
 * Types are private:
905
 */
906
907
typedef enum {
908
    XPATH_OP_END=0,
909
    XPATH_OP_AND,
910
    XPATH_OP_OR,
911
    XPATH_OP_EQUAL,
912
    XPATH_OP_CMP,
913
    XPATH_OP_PLUS,
914
    XPATH_OP_MULT,
915
    XPATH_OP_UNION,
916
    XPATH_OP_ROOT,
917
    XPATH_OP_NODE,
918
    XPATH_OP_COLLECT,
919
    XPATH_OP_VALUE, /* 11 */
920
    XPATH_OP_VARIABLE,
921
    XPATH_OP_FUNCTION,
922
    XPATH_OP_ARG,
923
    XPATH_OP_PREDICATE,
924
    XPATH_OP_FILTER, /* 16 */
925
    XPATH_OP_SORT /* 17 */
926
#ifdef LIBXML_XPTR_LOCS_ENABLED
927
    ,XPATH_OP_RANGETO
928
#endif
929
} xmlXPathOp;
930
931
typedef enum {
932
    AXIS_ANCESTOR = 1,
933
    AXIS_ANCESTOR_OR_SELF,
934
    AXIS_ATTRIBUTE,
935
    AXIS_CHILD,
936
    AXIS_DESCENDANT,
937
    AXIS_DESCENDANT_OR_SELF,
938
    AXIS_FOLLOWING,
939
    AXIS_FOLLOWING_SIBLING,
940
    AXIS_NAMESPACE,
941
    AXIS_PARENT,
942
    AXIS_PRECEDING,
943
    AXIS_PRECEDING_SIBLING,
944
    AXIS_SELF
945
} xmlXPathAxisVal;
946
947
typedef enum {
948
    NODE_TEST_NONE = 0,
949
    NODE_TEST_TYPE = 1,
950
    NODE_TEST_PI = 2,
951
    NODE_TEST_ALL = 3,
952
    NODE_TEST_NS = 4,
953
    NODE_TEST_NAME = 5
954
} xmlXPathTestVal;
955
956
typedef enum {
957
    NODE_TYPE_NODE = 0,
958
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
959
    NODE_TYPE_TEXT = XML_TEXT_NODE,
960
    NODE_TYPE_PI = XML_PI_NODE
961
} xmlXPathTypeVal;
962
963
typedef struct _xmlXPathStepOp xmlXPathStepOp;
964
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
965
struct _xmlXPathStepOp {
966
    xmlXPathOp op;    /* The identifier of the operation */
967
    int ch1;      /* First child */
968
    int ch2;      /* Second child */
969
    int value;
970
    int value2;
971
    int value3;
972
    void *value4;
973
    void *value5;
974
    xmlXPathFunction cache;
975
    void *cacheURI;
976
};
977
978
struct _xmlXPathCompExpr {
979
    int nbStep;     /* Number of steps in this expression */
980
    int maxStep;    /* Maximum number of steps allocated */
981
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
982
    int last;     /* index of last step in expression */
983
    xmlChar *expr;    /* the expression being computed */
984
    xmlDictPtr dict;    /* the dictionary to use if any */
985
#ifdef DEBUG_EVAL_COUNTS
986
    int nb;
987
    xmlChar *string;
988
#endif
989
#ifdef XPATH_STREAMING
990
    xmlPatternPtr stream;
991
#endif
992
};
993
994
/************************************************************************
995
 *                  *
996
 *      Forward declarations        *
997
 *                  *
998
 ************************************************************************/
999
static void
1000
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
1001
static void
1002
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
1003
static int
1004
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1005
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1006
static int
1007
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1008
          xmlXPathStepOpPtr op,
1009
          int isPredicate);
1010
static void
1011
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1012
1013
/************************************************************************
1014
 *                  *
1015
 *      Parser Type functions       *
1016
 *                  *
1017
 ************************************************************************/
1018
1019
/**
1020
 * xmlXPathNewCompExpr:
1021
 *
1022
 * Create a new Xpath component
1023
 *
1024
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1025
 */
1026
static xmlXPathCompExprPtr
1027
1.31M
xmlXPathNewCompExpr(void) {
1028
1.31M
    xmlXPathCompExprPtr cur;
1029
1030
1.31M
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031
1.31M
    if (cur == NULL) {
1032
89
        xmlXPathErrMemory(NULL, "allocating component\n");
1033
89
  return(NULL);
1034
89
    }
1035
1.31M
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1036
1.31M
    cur->maxStep = 10;
1037
1.31M
    cur->nbStep = 0;
1038
1.31M
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039
1.31M
                                     sizeof(xmlXPathStepOp));
1040
1.31M
    if (cur->steps == NULL) {
1041
96
        xmlXPathErrMemory(NULL, "allocating steps\n");
1042
96
  xmlFree(cur);
1043
96
  return(NULL);
1044
96
    }
1045
1.31M
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046
1.31M
    cur->last = -1;
1047
#ifdef DEBUG_EVAL_COUNTS
1048
    cur->nb = 0;
1049
#endif
1050
1.31M
    return(cur);
1051
1.31M
}
1052
1053
/**
1054
 * xmlXPathFreeCompExpr:
1055
 * @comp:  an XPATH comp
1056
 *
1057
 * Free up the memory allocated by @comp
1058
 */
1059
void
1060
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1061
1.31M
{
1062
1.31M
    xmlXPathStepOpPtr op;
1063
1.31M
    int i;
1064
1065
1.31M
    if (comp == NULL)
1066
5.30k
        return;
1067
1.31M
    if (comp->dict == NULL) {
1068
113M
  for (i = 0; i < comp->nbStep; i++) {
1069
112M
      op = &comp->steps[i];
1070
112M
      if (op->value4 != NULL) {
1071
2.23M
    if (op->op == XPATH_OP_VALUE)
1072
1.16M
        xmlXPathFreeObject(op->value4);
1073
1.07M
    else
1074
1.07M
        xmlFree(op->value4);
1075
2.23M
      }
1076
112M
      if (op->value5 != NULL)
1077
2.67M
    xmlFree(op->value5);
1078
112M
  }
1079
1.19M
    } else {
1080
12.7M
  for (i = 0; i < comp->nbStep; i++) {
1081
12.6M
      op = &comp->steps[i];
1082
12.6M
      if (op->value4 != NULL) {
1083
114k
    if (op->op == XPATH_OP_VALUE)
1084
39.1k
        xmlXPathFreeObject(op->value4);
1085
114k
      }
1086
12.6M
  }
1087
119k
        xmlDictFree(comp->dict);
1088
119k
    }
1089
1.31M
    if (comp->steps != NULL) {
1090
1.31M
        xmlFree(comp->steps);
1091
1.31M
    }
1092
#ifdef DEBUG_EVAL_COUNTS
1093
    if (comp->string != NULL) {
1094
        xmlFree(comp->string);
1095
    }
1096
#endif
1097
1.31M
#ifdef XPATH_STREAMING
1098
1.31M
    if (comp->stream != NULL) {
1099
196k
        xmlFreePatternList(comp->stream);
1100
196k
    }
1101
1.31M
#endif
1102
1.31M
    if (comp->expr != NULL) {
1103
369k
        xmlFree(comp->expr);
1104
369k
    }
1105
1106
1.31M
    xmlFree(comp);
1107
1.31M
}
1108
1109
/**
1110
 * xmlXPathCompExprAdd:
1111
 * @comp:  the compiled expression
1112
 * @ch1: first child index
1113
 * @ch2: second child index
1114
 * @op:  an op
1115
 * @value:  the first int value
1116
 * @value2:  the second int value
1117
 * @value3:  the third int value
1118
 * @value4:  the first string value
1119
 * @value5:  the second string value
1120
 *
1121
 * Add a step to an XPath Compiled Expression
1122
 *
1123
 * Returns -1 in case of failure, the index otherwise
1124
 */
1125
static int
1126
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1127
   xmlXPathOp op, int value,
1128
125M
   int value2, int value3, void *value4, void *value5) {
1129
125M
    xmlXPathCompExprPtr comp = ctxt->comp;
1130
125M
    if (comp->nbStep >= comp->maxStep) {
1131
828k
  xmlXPathStepOp *real;
1132
1133
828k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1134
10
      xmlXPathPErrMemory(ctxt, "adding step\n");
1135
10
      return(-1);
1136
10
        }
1137
828k
  comp->maxStep *= 2;
1138
828k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139
828k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1140
828k
  if (real == NULL) {
1141
479
      comp->maxStep /= 2;
1142
479
      xmlXPathPErrMemory(ctxt, "adding step\n");
1143
479
      return(-1);
1144
479
  }
1145
828k
  comp->steps = real;
1146
828k
    }
1147
125M
    comp->last = comp->nbStep;
1148
125M
    comp->steps[comp->nbStep].ch1 = ch1;
1149
125M
    comp->steps[comp->nbStep].ch2 = ch2;
1150
125M
    comp->steps[comp->nbStep].op = op;
1151
125M
    comp->steps[comp->nbStep].value = value;
1152
125M
    comp->steps[comp->nbStep].value2 = value2;
1153
125M
    comp->steps[comp->nbStep].value3 = value3;
1154
125M
    if ((comp->dict != NULL) &&
1155
125M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1156
12.6M
   (op == XPATH_OP_COLLECT))) {
1157
4.24M
        if (value4 != NULL) {
1158
75.4k
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1159
75.4k
          (void *)xmlDictLookup(comp->dict, value4, -1);
1160
75.4k
      xmlFree(value4);
1161
75.4k
  } else
1162
4.16M
      comp->steps[comp->nbStep].value4 = NULL;
1163
4.24M
        if (value5 != NULL) {
1164
142k
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1165
142k
          (void *)xmlDictLookup(comp->dict, value5, -1);
1166
142k
      xmlFree(value5);
1167
142k
  } else
1168
4.09M
      comp->steps[comp->nbStep].value5 = NULL;
1169
121M
    } else {
1170
121M
  comp->steps[comp->nbStep].value4 = value4;
1171
121M
  comp->steps[comp->nbStep].value5 = value5;
1172
121M
    }
1173
125M
    comp->steps[comp->nbStep].cache = NULL;
1174
125M
    return(comp->nbStep++);
1175
125M
}
1176
1177
/**
1178
 * xmlXPathCompSwap:
1179
 * @comp:  the compiled expression
1180
 * @op: operation index
1181
 *
1182
 * Swaps 2 operations in the compiled expression
1183
 */
1184
static void
1185
45.6k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186
45.6k
    int tmp;
1187
1188
#ifndef LIBXML_THREAD_ENABLED
1189
    /*
1190
     * Since this manipulates possibly shared variables, this is
1191
     * disabled if one detects that the library is used in a multithreaded
1192
     * application
1193
     */
1194
    if (xmlXPathDisableOptimizer)
1195
  return;
1196
#endif
1197
1198
45.6k
    tmp = op->ch1;
1199
45.6k
    op->ch1 = op->ch2;
1200
45.6k
    op->ch2 = tmp;
1201
45.6k
}
1202
1203
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204
38.3M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1205
38.3M
                  (op), (val), (val2), (val3), (val4), (val5))
1206
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1207
2.65M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1208
2.65M
                  (op), (val), (val2), (val3), (val4), (val5))
1209
1210
40.2M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1211
40.2M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212
1213
3.27M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1214
3.27M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215
1216
40.9M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1217
40.9M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1218
40.9M
      (val), (val2), 0 ,NULL ,NULL)
1219
1220
/************************************************************************
1221
 *                  *
1222
 *    XPath object cache structures       *
1223
 *                  *
1224
 ************************************************************************/
1225
1226
/* #define XP_DEFAULT_CACHE_ON */
1227
1228
908k
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1229
1230
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1231
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1232
struct _xmlXPathContextCache {
1233
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1234
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1235
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1236
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1237
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1238
    int maxNodeset;
1239
    int maxString;
1240
    int maxBoolean;
1241
    int maxNumber;
1242
    int maxMisc;
1243
#ifdef XP_DEBUG_OBJ_USAGE
1244
    int dbgCachedAll;
1245
    int dbgCachedNodeset;
1246
    int dbgCachedString;
1247
    int dbgCachedBool;
1248
    int dbgCachedNumber;
1249
    int dbgCachedPoint;
1250
    int dbgCachedRange;
1251
    int dbgCachedLocset;
1252
    int dbgCachedUsers;
1253
    int dbgCachedXSLTTree;
1254
    int dbgCachedUndefined;
1255
1256
1257
    int dbgReusedAll;
1258
    int dbgReusedNodeset;
1259
    int dbgReusedString;
1260
    int dbgReusedBool;
1261
    int dbgReusedNumber;
1262
    int dbgReusedPoint;
1263
    int dbgReusedRange;
1264
    int dbgReusedLocset;
1265
    int dbgReusedUsers;
1266
    int dbgReusedXSLTTree;
1267
    int dbgReusedUndefined;
1268
1269
#endif
1270
};
1271
1272
/************************************************************************
1273
 *                  *
1274
 *    Debugging related functions       *
1275
 *                  *
1276
 ************************************************************************/
1277
1278
#define STRANGE             \
1279
0
    xmlGenericError(xmlGenericErrorContext,       \
1280
0
      "Internal error at %s:%d\n",        \
1281
0
            __FILE__, __LINE__);
1282
1283
#ifdef LIBXML_DEBUG_ENABLED
1284
static void
1285
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1286
0
    int i;
1287
0
    char shift[100];
1288
1289
0
    for (i = 0;((i < depth) && (i < 25));i++)
1290
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1291
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1292
0
    if (cur == NULL) {
1293
0
  fprintf(output, "%s", shift);
1294
0
  fprintf(output, "Node is NULL !\n");
1295
0
  return;
1296
1297
0
    }
1298
1299
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1300
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1301
0
  fprintf(output, "%s", shift);
1302
0
  fprintf(output, " /\n");
1303
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1304
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1305
0
    else
1306
0
  xmlDebugDumpOneNode(output, cur, depth);
1307
0
}
1308
static void
1309
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1310
0
    xmlNodePtr tmp;
1311
0
    int i;
1312
0
    char shift[100];
1313
1314
0
    for (i = 0;((i < depth) && (i < 25));i++)
1315
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1316
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1317
0
    if (cur == NULL) {
1318
0
  fprintf(output, "%s", shift);
1319
0
  fprintf(output, "Node is NULL !\n");
1320
0
  return;
1321
1322
0
    }
1323
1324
0
    while (cur != NULL) {
1325
0
  tmp = cur;
1326
0
  cur = cur->next;
1327
0
  xmlDebugDumpOneNode(output, tmp, depth);
1328
0
    }
1329
0
}
1330
1331
static void
1332
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1333
0
    int i;
1334
0
    char shift[100];
1335
1336
0
    for (i = 0;((i < depth) && (i < 25));i++)
1337
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1338
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1339
1340
0
    if (cur == NULL) {
1341
0
  fprintf(output, "%s", shift);
1342
0
  fprintf(output, "NodeSet is NULL !\n");
1343
0
  return;
1344
1345
0
    }
1346
1347
0
    if (cur != NULL) {
1348
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1349
0
  for (i = 0;i < cur->nodeNr;i++) {
1350
0
      fprintf(output, "%s", shift);
1351
0
      fprintf(output, "%d", i + 1);
1352
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1353
0
  }
1354
0
    }
1355
0
}
1356
1357
static void
1358
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1359
0
    int i;
1360
0
    char shift[100];
1361
1362
0
    for (i = 0;((i < depth) && (i < 25));i++)
1363
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1364
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1365
1366
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1367
0
  fprintf(output, "%s", shift);
1368
0
  fprintf(output, "Value Tree is NULL !\n");
1369
0
  return;
1370
1371
0
    }
1372
1373
0
    fprintf(output, "%s", shift);
1374
0
    fprintf(output, "%d", i + 1);
1375
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1376
0
}
1377
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1378
static void
1379
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1380
    int i;
1381
    char shift[100];
1382
1383
    for (i = 0;((i < depth) && (i < 25));i++)
1384
        shift[2 * i] = shift[2 * i + 1] = ' ';
1385
    shift[2 * i] = shift[2 * i + 1] = 0;
1386
1387
    if (cur == NULL) {
1388
  fprintf(output, "%s", shift);
1389
  fprintf(output, "LocationSet is NULL !\n");
1390
  return;
1391
1392
    }
1393
1394
    for (i = 0;i < cur->locNr;i++) {
1395
  fprintf(output, "%s", shift);
1396
        fprintf(output, "%d : ", i + 1);
1397
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1398
    }
1399
}
1400
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1401
1402
/**
1403
 * xmlXPathDebugDumpObject:
1404
 * @output:  the FILE * to dump the output
1405
 * @cur:  the object to inspect
1406
 * @depth:  indentation level
1407
 *
1408
 * Dump the content of the object for debugging purposes
1409
 */
1410
void
1411
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1412
0
    int i;
1413
0
    char shift[100];
1414
1415
0
    if (output == NULL) return;
1416
1417
0
    for (i = 0;((i < depth) && (i < 25));i++)
1418
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1419
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1420
1421
1422
0
    fprintf(output, "%s", shift);
1423
1424
0
    if (cur == NULL) {
1425
0
        fprintf(output, "Object is empty (NULL)\n");
1426
0
  return;
1427
0
    }
1428
0
    switch(cur->type) {
1429
0
        case XPATH_UNDEFINED:
1430
0
      fprintf(output, "Object is uninitialized\n");
1431
0
      break;
1432
0
        case XPATH_NODESET:
1433
0
      fprintf(output, "Object is a Node Set :\n");
1434
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
  case XPATH_XSLT_TREE:
1437
0
      fprintf(output, "Object is an XSLT value tree :\n");
1438
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1439
0
      break;
1440
0
        case XPATH_BOOLEAN:
1441
0
      fprintf(output, "Object is a Boolean : ");
1442
0
      if (cur->boolval) fprintf(output, "true\n");
1443
0
      else fprintf(output, "false\n");
1444
0
      break;
1445
0
        case XPATH_NUMBER:
1446
0
      switch (xmlXPathIsInf(cur->floatval)) {
1447
0
      case 1:
1448
0
    fprintf(output, "Object is a number : Infinity\n");
1449
0
    break;
1450
0
      case -1:
1451
0
    fprintf(output, "Object is a number : -Infinity\n");
1452
0
    break;
1453
0
      default:
1454
0
    if (xmlXPathIsNaN(cur->floatval)) {
1455
0
        fprintf(output, "Object is a number : NaN\n");
1456
0
    } else if (cur->floatval == 0) {
1457
                    /* Omit sign for negative zero. */
1458
0
        fprintf(output, "Object is a number : 0\n");
1459
0
    } else {
1460
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1461
0
    }
1462
0
      }
1463
0
      break;
1464
0
        case XPATH_STRING:
1465
0
      fprintf(output, "Object is a string : ");
1466
0
      xmlDebugDumpString(output, cur->stringval);
1467
0
      fprintf(output, "\n");
1468
0
      break;
1469
#ifdef LIBXML_XPTR_LOCS_ENABLED
1470
  case XPATH_POINT:
1471
      fprintf(output, "Object is a point : index %d in node", cur->index);
1472
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1473
      fprintf(output, "\n");
1474
      break;
1475
  case XPATH_RANGE:
1476
      if ((cur->user2 == NULL) ||
1477
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1478
    fprintf(output, "Object is a collapsed range :\n");
1479
    fprintf(output, "%s", shift);
1480
    if (cur->index >= 0)
1481
        fprintf(output, "index %d in ", cur->index);
1482
    fprintf(output, "node\n");
1483
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1484
                    depth + 1);
1485
      } else  {
1486
    fprintf(output, "Object is a range :\n");
1487
    fprintf(output, "%s", shift);
1488
    fprintf(output, "From ");
1489
    if (cur->index >= 0)
1490
        fprintf(output, "index %d in ", cur->index);
1491
    fprintf(output, "node\n");
1492
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1493
                    depth + 1);
1494
    fprintf(output, "%s", shift);
1495
    fprintf(output, "To ");
1496
    if (cur->index2 >= 0)
1497
        fprintf(output, "index %d in ", cur->index2);
1498
    fprintf(output, "node\n");
1499
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1500
                    depth + 1);
1501
    fprintf(output, "\n");
1502
      }
1503
      break;
1504
  case XPATH_LOCATIONSET:
1505
      fprintf(output, "Object is a Location Set:\n");
1506
      xmlXPathDebugDumpLocationSet(output,
1507
        (xmlLocationSetPtr) cur->user, depth);
1508
      break;
1509
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1510
0
  case XPATH_USERS:
1511
0
      fprintf(output, "Object is user defined\n");
1512
0
      break;
1513
0
    }
1514
0
}
1515
1516
static void
1517
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1518
0
                       xmlXPathStepOpPtr op, int depth) {
1519
0
    int i;
1520
0
    char shift[100];
1521
1522
0
    for (i = 0;((i < depth) && (i < 25));i++)
1523
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1524
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1525
1526
0
    fprintf(output, "%s", shift);
1527
0
    if (op == NULL) {
1528
0
  fprintf(output, "Step is NULL\n");
1529
0
  return;
1530
0
    }
1531
0
    switch (op->op) {
1532
0
        case XPATH_OP_END:
1533
0
      fprintf(output, "END"); break;
1534
0
        case XPATH_OP_AND:
1535
0
      fprintf(output, "AND"); break;
1536
0
        case XPATH_OP_OR:
1537
0
      fprintf(output, "OR"); break;
1538
0
        case XPATH_OP_EQUAL:
1539
0
       if (op->value)
1540
0
     fprintf(output, "EQUAL =");
1541
0
       else
1542
0
     fprintf(output, "EQUAL !=");
1543
0
       break;
1544
0
        case XPATH_OP_CMP:
1545
0
       if (op->value)
1546
0
     fprintf(output, "CMP <");
1547
0
       else
1548
0
     fprintf(output, "CMP >");
1549
0
       if (!op->value2)
1550
0
     fprintf(output, "=");
1551
0
       break;
1552
0
        case XPATH_OP_PLUS:
1553
0
       if (op->value == 0)
1554
0
     fprintf(output, "PLUS -");
1555
0
       else if (op->value == 1)
1556
0
     fprintf(output, "PLUS +");
1557
0
       else if (op->value == 2)
1558
0
     fprintf(output, "PLUS unary -");
1559
0
       else if (op->value == 3)
1560
0
     fprintf(output, "PLUS unary - -");
1561
0
       break;
1562
0
        case XPATH_OP_MULT:
1563
0
       if (op->value == 0)
1564
0
     fprintf(output, "MULT *");
1565
0
       else if (op->value == 1)
1566
0
     fprintf(output, "MULT div");
1567
0
       else
1568
0
     fprintf(output, "MULT mod");
1569
0
       break;
1570
0
        case XPATH_OP_UNION:
1571
0
       fprintf(output, "UNION"); break;
1572
0
        case XPATH_OP_ROOT:
1573
0
       fprintf(output, "ROOT"); break;
1574
0
        case XPATH_OP_NODE:
1575
0
       fprintf(output, "NODE"); break;
1576
0
        case XPATH_OP_SORT:
1577
0
       fprintf(output, "SORT"); break;
1578
0
        case XPATH_OP_COLLECT: {
1579
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1580
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1581
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1582
0
      const xmlChar *prefix = op->value4;
1583
0
      const xmlChar *name = op->value5;
1584
1585
0
      fprintf(output, "COLLECT ");
1586
0
      switch (axis) {
1587
0
    case AXIS_ANCESTOR:
1588
0
        fprintf(output, " 'ancestors' "); break;
1589
0
    case AXIS_ANCESTOR_OR_SELF:
1590
0
        fprintf(output, " 'ancestors-or-self' "); break;
1591
0
    case AXIS_ATTRIBUTE:
1592
0
        fprintf(output, " 'attributes' "); break;
1593
0
    case AXIS_CHILD:
1594
0
        fprintf(output, " 'child' "); break;
1595
0
    case AXIS_DESCENDANT:
1596
0
        fprintf(output, " 'descendant' "); break;
1597
0
    case AXIS_DESCENDANT_OR_SELF:
1598
0
        fprintf(output, " 'descendant-or-self' "); break;
1599
0
    case AXIS_FOLLOWING:
1600
0
        fprintf(output, " 'following' "); break;
1601
0
    case AXIS_FOLLOWING_SIBLING:
1602
0
        fprintf(output, " 'following-siblings' "); break;
1603
0
    case AXIS_NAMESPACE:
1604
0
        fprintf(output, " 'namespace' "); break;
1605
0
    case AXIS_PARENT:
1606
0
        fprintf(output, " 'parent' "); break;
1607
0
    case AXIS_PRECEDING:
1608
0
        fprintf(output, " 'preceding' "); break;
1609
0
    case AXIS_PRECEDING_SIBLING:
1610
0
        fprintf(output, " 'preceding-sibling' "); break;
1611
0
    case AXIS_SELF:
1612
0
        fprintf(output, " 'self' "); break;
1613
0
      }
1614
0
      switch (test) {
1615
0
                case NODE_TEST_NONE:
1616
0
        fprintf(output, "'none' "); break;
1617
0
                case NODE_TEST_TYPE:
1618
0
        fprintf(output, "'type' "); break;
1619
0
                case NODE_TEST_PI:
1620
0
        fprintf(output, "'PI' "); break;
1621
0
                case NODE_TEST_ALL:
1622
0
        fprintf(output, "'all' "); break;
1623
0
                case NODE_TEST_NS:
1624
0
        fprintf(output, "'namespace' "); break;
1625
0
                case NODE_TEST_NAME:
1626
0
        fprintf(output, "'name' "); break;
1627
0
      }
1628
0
      switch (type) {
1629
0
                case NODE_TYPE_NODE:
1630
0
        fprintf(output, "'node' "); break;
1631
0
                case NODE_TYPE_COMMENT:
1632
0
        fprintf(output, "'comment' "); break;
1633
0
                case NODE_TYPE_TEXT:
1634
0
        fprintf(output, "'text' "); break;
1635
0
                case NODE_TYPE_PI:
1636
0
        fprintf(output, "'PI' "); break;
1637
0
      }
1638
0
      if (prefix != NULL)
1639
0
    fprintf(output, "%s:", prefix);
1640
0
      if (name != NULL)
1641
0
    fprintf(output, "%s", (const char *) name);
1642
0
      break;
1643
1644
0
        }
1645
0
  case XPATH_OP_VALUE: {
1646
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1647
1648
0
      fprintf(output, "ELEM ");
1649
0
      xmlXPathDebugDumpObject(output, object, 0);
1650
0
      goto finish;
1651
0
  }
1652
0
  case XPATH_OP_VARIABLE: {
1653
0
      const xmlChar *prefix = op->value5;
1654
0
      const xmlChar *name = op->value4;
1655
1656
0
      if (prefix != NULL)
1657
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1658
0
      else
1659
0
    fprintf(output, "VARIABLE %s", name);
1660
0
      break;
1661
0
  }
1662
0
  case XPATH_OP_FUNCTION: {
1663
0
      int nbargs = op->value;
1664
0
      const xmlChar *prefix = op->value5;
1665
0
      const xmlChar *name = op->value4;
1666
1667
0
      if (prefix != NULL)
1668
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1669
0
      prefix, name, nbargs);
1670
0
      else
1671
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1672
0
      break;
1673
0
  }
1674
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1675
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1676
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1677
#ifdef LIBXML_XPTR_LOCS_ENABLED
1678
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1679
#endif
1680
0
  default:
1681
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1682
0
    }
1683
0
    fprintf(output, "\n");
1684
0
finish:
1685
0
    if (op->ch1 >= 0)
1686
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1687
0
    if (op->ch2 >= 0)
1688
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1689
0
}
1690
1691
/**
1692
 * xmlXPathDebugDumpCompExpr:
1693
 * @output:  the FILE * for the output
1694
 * @comp:  the precompiled XPath expression
1695
 * @depth:  the indentation level.
1696
 *
1697
 * Dumps the tree of the compiled XPath expression.
1698
 */
1699
void
1700
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1701
0
                    int depth) {
1702
0
    int i;
1703
0
    char shift[100];
1704
1705
0
    if ((output == NULL) || (comp == NULL)) return;
1706
1707
0
    for (i = 0;((i < depth) && (i < 25));i++)
1708
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1709
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1710
1711
0
    fprintf(output, "%s", shift);
1712
1713
0
#ifdef XPATH_STREAMING
1714
0
    if (comp->stream) {
1715
0
        fprintf(output, "Streaming Expression\n");
1716
0
    } else
1717
0
#endif
1718
0
    {
1719
0
        fprintf(output, "Compiled Expression : %d elements\n",
1720
0
                comp->nbStep);
1721
0
        i = comp->last;
1722
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1723
0
    }
1724
0
}
1725
1726
#ifdef XP_DEBUG_OBJ_USAGE
1727
1728
/*
1729
* XPath object usage related debugging variables.
1730
*/
1731
static int xmlXPathDebugObjCounterUndefined = 0;
1732
static int xmlXPathDebugObjCounterNodeset = 0;
1733
static int xmlXPathDebugObjCounterBool = 0;
1734
static int xmlXPathDebugObjCounterNumber = 0;
1735
static int xmlXPathDebugObjCounterString = 0;
1736
static int xmlXPathDebugObjCounterPoint = 0;
1737
static int xmlXPathDebugObjCounterRange = 0;
1738
static int xmlXPathDebugObjCounterLocset = 0;
1739
static int xmlXPathDebugObjCounterUsers = 0;
1740
static int xmlXPathDebugObjCounterXSLTTree = 0;
1741
static int xmlXPathDebugObjCounterAll = 0;
1742
1743
static int xmlXPathDebugObjTotalUndefined = 0;
1744
static int xmlXPathDebugObjTotalNodeset = 0;
1745
static int xmlXPathDebugObjTotalBool = 0;
1746
static int xmlXPathDebugObjTotalNumber = 0;
1747
static int xmlXPathDebugObjTotalString = 0;
1748
static int xmlXPathDebugObjTotalPoint = 0;
1749
static int xmlXPathDebugObjTotalRange = 0;
1750
static int xmlXPathDebugObjTotalLocset = 0;
1751
static int xmlXPathDebugObjTotalUsers = 0;
1752
static int xmlXPathDebugObjTotalXSLTTree = 0;
1753
static int xmlXPathDebugObjTotalAll = 0;
1754
1755
static int xmlXPathDebugObjMaxUndefined = 0;
1756
static int xmlXPathDebugObjMaxNodeset = 0;
1757
static int xmlXPathDebugObjMaxBool = 0;
1758
static int xmlXPathDebugObjMaxNumber = 0;
1759
static int xmlXPathDebugObjMaxString = 0;
1760
static int xmlXPathDebugObjMaxPoint = 0;
1761
static int xmlXPathDebugObjMaxRange = 0;
1762
static int xmlXPathDebugObjMaxLocset = 0;
1763
static int xmlXPathDebugObjMaxUsers = 0;
1764
static int xmlXPathDebugObjMaxXSLTTree = 0;
1765
static int xmlXPathDebugObjMaxAll = 0;
1766
1767
static void
1768
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1769
{
1770
    if (ctxt != NULL) {
1771
  if (ctxt->cache != NULL) {
1772
      xmlXPathContextCachePtr cache =
1773
    (xmlXPathContextCachePtr) ctxt->cache;
1774
1775
      cache->dbgCachedAll = 0;
1776
      cache->dbgCachedNodeset = 0;
1777
      cache->dbgCachedString = 0;
1778
      cache->dbgCachedBool = 0;
1779
      cache->dbgCachedNumber = 0;
1780
      cache->dbgCachedPoint = 0;
1781
      cache->dbgCachedRange = 0;
1782
      cache->dbgCachedLocset = 0;
1783
      cache->dbgCachedUsers = 0;
1784
      cache->dbgCachedXSLTTree = 0;
1785
      cache->dbgCachedUndefined = 0;
1786
1787
      cache->dbgReusedAll = 0;
1788
      cache->dbgReusedNodeset = 0;
1789
      cache->dbgReusedString = 0;
1790
      cache->dbgReusedBool = 0;
1791
      cache->dbgReusedNumber = 0;
1792
      cache->dbgReusedPoint = 0;
1793
      cache->dbgReusedRange = 0;
1794
      cache->dbgReusedLocset = 0;
1795
      cache->dbgReusedUsers = 0;
1796
      cache->dbgReusedXSLTTree = 0;
1797
      cache->dbgReusedUndefined = 0;
1798
  }
1799
    }
1800
1801
    xmlXPathDebugObjCounterUndefined = 0;
1802
    xmlXPathDebugObjCounterNodeset = 0;
1803
    xmlXPathDebugObjCounterBool = 0;
1804
    xmlXPathDebugObjCounterNumber = 0;
1805
    xmlXPathDebugObjCounterString = 0;
1806
    xmlXPathDebugObjCounterPoint = 0;
1807
    xmlXPathDebugObjCounterRange = 0;
1808
    xmlXPathDebugObjCounterLocset = 0;
1809
    xmlXPathDebugObjCounterUsers = 0;
1810
    xmlXPathDebugObjCounterXSLTTree = 0;
1811
    xmlXPathDebugObjCounterAll = 0;
1812
1813
    xmlXPathDebugObjTotalUndefined = 0;
1814
    xmlXPathDebugObjTotalNodeset = 0;
1815
    xmlXPathDebugObjTotalBool = 0;
1816
    xmlXPathDebugObjTotalNumber = 0;
1817
    xmlXPathDebugObjTotalString = 0;
1818
    xmlXPathDebugObjTotalPoint = 0;
1819
    xmlXPathDebugObjTotalRange = 0;
1820
    xmlXPathDebugObjTotalLocset = 0;
1821
    xmlXPathDebugObjTotalUsers = 0;
1822
    xmlXPathDebugObjTotalXSLTTree = 0;
1823
    xmlXPathDebugObjTotalAll = 0;
1824
1825
    xmlXPathDebugObjMaxUndefined = 0;
1826
    xmlXPathDebugObjMaxNodeset = 0;
1827
    xmlXPathDebugObjMaxBool = 0;
1828
    xmlXPathDebugObjMaxNumber = 0;
1829
    xmlXPathDebugObjMaxString = 0;
1830
    xmlXPathDebugObjMaxPoint = 0;
1831
    xmlXPathDebugObjMaxRange = 0;
1832
    xmlXPathDebugObjMaxLocset = 0;
1833
    xmlXPathDebugObjMaxUsers = 0;
1834
    xmlXPathDebugObjMaxXSLTTree = 0;
1835
    xmlXPathDebugObjMaxAll = 0;
1836
1837
}
1838
1839
static void
1840
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1841
            xmlXPathObjectType objType)
1842
{
1843
    int isCached = 0;
1844
1845
    if (ctxt != NULL) {
1846
  if (ctxt->cache != NULL) {
1847
      xmlXPathContextCachePtr cache =
1848
    (xmlXPathContextCachePtr) ctxt->cache;
1849
1850
      isCached = 1;
1851
1852
      cache->dbgReusedAll++;
1853
      switch (objType) {
1854
    case XPATH_UNDEFINED:
1855
        cache->dbgReusedUndefined++;
1856
        break;
1857
    case XPATH_NODESET:
1858
        cache->dbgReusedNodeset++;
1859
        break;
1860
    case XPATH_BOOLEAN:
1861
        cache->dbgReusedBool++;
1862
        break;
1863
    case XPATH_NUMBER:
1864
        cache->dbgReusedNumber++;
1865
        break;
1866
    case XPATH_STRING:
1867
        cache->dbgReusedString++;
1868
        break;
1869
#ifdef LIBXML_XPTR_LOCS_ENABLED
1870
    case XPATH_POINT:
1871
        cache->dbgReusedPoint++;
1872
        break;
1873
    case XPATH_RANGE:
1874
        cache->dbgReusedRange++;
1875
        break;
1876
    case XPATH_LOCATIONSET:
1877
        cache->dbgReusedLocset++;
1878
        break;
1879
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1880
    case XPATH_USERS:
1881
        cache->dbgReusedUsers++;
1882
        break;
1883
    case XPATH_XSLT_TREE:
1884
        cache->dbgReusedXSLTTree++;
1885
        break;
1886
    default:
1887
        break;
1888
      }
1889
  }
1890
    }
1891
1892
    switch (objType) {
1893
  case XPATH_UNDEFINED:
1894
      if (! isCached)
1895
    xmlXPathDebugObjTotalUndefined++;
1896
      xmlXPathDebugObjCounterUndefined++;
1897
      if (xmlXPathDebugObjCounterUndefined >
1898
    xmlXPathDebugObjMaxUndefined)
1899
    xmlXPathDebugObjMaxUndefined =
1900
        xmlXPathDebugObjCounterUndefined;
1901
      break;
1902
  case XPATH_NODESET:
1903
      if (! isCached)
1904
    xmlXPathDebugObjTotalNodeset++;
1905
      xmlXPathDebugObjCounterNodeset++;
1906
      if (xmlXPathDebugObjCounterNodeset >
1907
    xmlXPathDebugObjMaxNodeset)
1908
    xmlXPathDebugObjMaxNodeset =
1909
        xmlXPathDebugObjCounterNodeset;
1910
      break;
1911
  case XPATH_BOOLEAN:
1912
      if (! isCached)
1913
    xmlXPathDebugObjTotalBool++;
1914
      xmlXPathDebugObjCounterBool++;
1915
      if (xmlXPathDebugObjCounterBool >
1916
    xmlXPathDebugObjMaxBool)
1917
    xmlXPathDebugObjMaxBool =
1918
        xmlXPathDebugObjCounterBool;
1919
      break;
1920
  case XPATH_NUMBER:
1921
      if (! isCached)
1922
    xmlXPathDebugObjTotalNumber++;
1923
      xmlXPathDebugObjCounterNumber++;
1924
      if (xmlXPathDebugObjCounterNumber >
1925
    xmlXPathDebugObjMaxNumber)
1926
    xmlXPathDebugObjMaxNumber =
1927
        xmlXPathDebugObjCounterNumber;
1928
      break;
1929
  case XPATH_STRING:
1930
      if (! isCached)
1931
    xmlXPathDebugObjTotalString++;
1932
      xmlXPathDebugObjCounterString++;
1933
      if (xmlXPathDebugObjCounterString >
1934
    xmlXPathDebugObjMaxString)
1935
    xmlXPathDebugObjMaxString =
1936
        xmlXPathDebugObjCounterString;
1937
      break;
1938
#ifdef LIBXML_XPTR_LOCS_ENABLED
1939
  case XPATH_POINT:
1940
      if (! isCached)
1941
    xmlXPathDebugObjTotalPoint++;
1942
      xmlXPathDebugObjCounterPoint++;
1943
      if (xmlXPathDebugObjCounterPoint >
1944
    xmlXPathDebugObjMaxPoint)
1945
    xmlXPathDebugObjMaxPoint =
1946
        xmlXPathDebugObjCounterPoint;
1947
      break;
1948
  case XPATH_RANGE:
1949
      if (! isCached)
1950
    xmlXPathDebugObjTotalRange++;
1951
      xmlXPathDebugObjCounterRange++;
1952
      if (xmlXPathDebugObjCounterRange >
1953
    xmlXPathDebugObjMaxRange)
1954
    xmlXPathDebugObjMaxRange =
1955
        xmlXPathDebugObjCounterRange;
1956
      break;
1957
  case XPATH_LOCATIONSET:
1958
      if (! isCached)
1959
    xmlXPathDebugObjTotalLocset++;
1960
      xmlXPathDebugObjCounterLocset++;
1961
      if (xmlXPathDebugObjCounterLocset >
1962
    xmlXPathDebugObjMaxLocset)
1963
    xmlXPathDebugObjMaxLocset =
1964
        xmlXPathDebugObjCounterLocset;
1965
      break;
1966
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1967
  case XPATH_USERS:
1968
      if (! isCached)
1969
    xmlXPathDebugObjTotalUsers++;
1970
      xmlXPathDebugObjCounterUsers++;
1971
      if (xmlXPathDebugObjCounterUsers >
1972
    xmlXPathDebugObjMaxUsers)
1973
    xmlXPathDebugObjMaxUsers =
1974
        xmlXPathDebugObjCounterUsers;
1975
      break;
1976
  case XPATH_XSLT_TREE:
1977
      if (! isCached)
1978
    xmlXPathDebugObjTotalXSLTTree++;
1979
      xmlXPathDebugObjCounterXSLTTree++;
1980
      if (xmlXPathDebugObjCounterXSLTTree >
1981
    xmlXPathDebugObjMaxXSLTTree)
1982
    xmlXPathDebugObjMaxXSLTTree =
1983
        xmlXPathDebugObjCounterXSLTTree;
1984
      break;
1985
  default:
1986
      break;
1987
    }
1988
    if (! isCached)
1989
  xmlXPathDebugObjTotalAll++;
1990
    xmlXPathDebugObjCounterAll++;
1991
    if (xmlXPathDebugObjCounterAll >
1992
  xmlXPathDebugObjMaxAll)
1993
  xmlXPathDebugObjMaxAll =
1994
      xmlXPathDebugObjCounterAll;
1995
}
1996
1997
static void
1998
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1999
            xmlXPathObjectType objType)
2000
{
2001
    int isCached = 0;
2002
2003
    if (ctxt != NULL) {
2004
  if (ctxt->cache != NULL) {
2005
      xmlXPathContextCachePtr cache =
2006
    (xmlXPathContextCachePtr) ctxt->cache;
2007
2008
      isCached = 1;
2009
2010
      cache->dbgCachedAll++;
2011
      switch (objType) {
2012
    case XPATH_UNDEFINED:
2013
        cache->dbgCachedUndefined++;
2014
        break;
2015
    case XPATH_NODESET:
2016
        cache->dbgCachedNodeset++;
2017
        break;
2018
    case XPATH_BOOLEAN:
2019
        cache->dbgCachedBool++;
2020
        break;
2021
    case XPATH_NUMBER:
2022
        cache->dbgCachedNumber++;
2023
        break;
2024
    case XPATH_STRING:
2025
        cache->dbgCachedString++;
2026
        break;
2027
#ifdef LIBXML_XPTR_LOCS_ENABLED
2028
    case XPATH_POINT:
2029
        cache->dbgCachedPoint++;
2030
        break;
2031
    case XPATH_RANGE:
2032
        cache->dbgCachedRange++;
2033
        break;
2034
    case XPATH_LOCATIONSET:
2035
        cache->dbgCachedLocset++;
2036
        break;
2037
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2038
    case XPATH_USERS:
2039
        cache->dbgCachedUsers++;
2040
        break;
2041
    case XPATH_XSLT_TREE:
2042
        cache->dbgCachedXSLTTree++;
2043
        break;
2044
    default:
2045
        break;
2046
      }
2047
2048
  }
2049
    }
2050
    switch (objType) {
2051
  case XPATH_UNDEFINED:
2052
      xmlXPathDebugObjCounterUndefined--;
2053
      break;
2054
  case XPATH_NODESET:
2055
      xmlXPathDebugObjCounterNodeset--;
2056
      break;
2057
  case XPATH_BOOLEAN:
2058
      xmlXPathDebugObjCounterBool--;
2059
      break;
2060
  case XPATH_NUMBER:
2061
      xmlXPathDebugObjCounterNumber--;
2062
      break;
2063
  case XPATH_STRING:
2064
      xmlXPathDebugObjCounterString--;
2065
      break;
2066
#ifdef LIBXML_XPTR_LOCS_ENABLED
2067
  case XPATH_POINT:
2068
      xmlXPathDebugObjCounterPoint--;
2069
      break;
2070
  case XPATH_RANGE:
2071
      xmlXPathDebugObjCounterRange--;
2072
      break;
2073
  case XPATH_LOCATIONSET:
2074
      xmlXPathDebugObjCounterLocset--;
2075
      break;
2076
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2077
  case XPATH_USERS:
2078
      xmlXPathDebugObjCounterUsers--;
2079
      break;
2080
  case XPATH_XSLT_TREE:
2081
      xmlXPathDebugObjCounterXSLTTree--;
2082
      break;
2083
  default:
2084
      break;
2085
    }
2086
    xmlXPathDebugObjCounterAll--;
2087
}
2088
2089
static void
2090
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2091
{
2092
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2093
  reqXSLTTree, reqUndefined;
2094
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2095
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2096
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2097
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2098
    int leftObjs = xmlXPathDebugObjCounterAll;
2099
2100
    reqAll = xmlXPathDebugObjTotalAll;
2101
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2102
    reqString = xmlXPathDebugObjTotalString;
2103
    reqBool = xmlXPathDebugObjTotalBool;
2104
    reqNumber = xmlXPathDebugObjTotalNumber;
2105
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2106
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2107
2108
    printf("# XPath object usage:\n");
2109
2110
    if (ctxt != NULL) {
2111
  if (ctxt->cache != NULL) {
2112
      xmlXPathContextCachePtr cache =
2113
    (xmlXPathContextCachePtr) ctxt->cache;
2114
2115
      reAll = cache->dbgReusedAll;
2116
      reqAll += reAll;
2117
      reNodeset = cache->dbgReusedNodeset;
2118
      reqNodeset += reNodeset;
2119
      reString = cache->dbgReusedString;
2120
      reqString += reString;
2121
      reBool = cache->dbgReusedBool;
2122
      reqBool += reBool;
2123
      reNumber = cache->dbgReusedNumber;
2124
      reqNumber += reNumber;
2125
      reXSLTTree = cache->dbgReusedXSLTTree;
2126
      reqXSLTTree += reXSLTTree;
2127
      reUndefined = cache->dbgReusedUndefined;
2128
      reqUndefined += reUndefined;
2129
2130
      caAll = cache->dbgCachedAll;
2131
      caBool = cache->dbgCachedBool;
2132
      caNodeset = cache->dbgCachedNodeset;
2133
      caString = cache->dbgCachedString;
2134
      caNumber = cache->dbgCachedNumber;
2135
      caXSLTTree = cache->dbgCachedXSLTTree;
2136
      caUndefined = cache->dbgCachedUndefined;
2137
2138
      if (cache->nodesetObjs)
2139
    leftObjs -= cache->nodesetObjs->number;
2140
      if (cache->stringObjs)
2141
    leftObjs -= cache->stringObjs->number;
2142
      if (cache->booleanObjs)
2143
    leftObjs -= cache->booleanObjs->number;
2144
      if (cache->numberObjs)
2145
    leftObjs -= cache->numberObjs->number;
2146
      if (cache->miscObjs)
2147
    leftObjs -= cache->miscObjs->number;
2148
  }
2149
    }
2150
2151
    printf("# all\n");
2152
    printf("#   total  : %d\n", reqAll);
2153
    printf("#   left  : %d\n", leftObjs);
2154
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2155
    printf("#   reused : %d\n", reAll);
2156
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2157
2158
    printf("# node-sets\n");
2159
    printf("#   total  : %d\n", reqNodeset);
2160
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2161
    printf("#   reused : %d\n", reNodeset);
2162
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2163
2164
    printf("# strings\n");
2165
    printf("#   total  : %d\n", reqString);
2166
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2167
    printf("#   reused : %d\n", reString);
2168
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2169
2170
    printf("# booleans\n");
2171
    printf("#   total  : %d\n", reqBool);
2172
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2173
    printf("#   reused : %d\n", reBool);
2174
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2175
2176
    printf("# numbers\n");
2177
    printf("#   total  : %d\n", reqNumber);
2178
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2179
    printf("#   reused : %d\n", reNumber);
2180
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2181
2182
    printf("# XSLT result tree fragments\n");
2183
    printf("#   total  : %d\n", reqXSLTTree);
2184
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2185
    printf("#   reused : %d\n", reXSLTTree);
2186
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2187
2188
    printf("# undefined\n");
2189
    printf("#   total  : %d\n", reqUndefined);
2190
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2191
    printf("#   reused : %d\n", reUndefined);
2192
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2193
2194
}
2195
2196
#endif /* XP_DEBUG_OBJ_USAGE */
2197
2198
#endif /* LIBXML_DEBUG_ENABLED */
2199
2200
/************************************************************************
2201
 *                  *
2202
 *      XPath object caching        *
2203
 *                  *
2204
 ************************************************************************/
2205
2206
/**
2207
 * xmlXPathNewCache:
2208
 *
2209
 * Create a new object cache
2210
 *
2211
 * Returns the xmlXPathCache just allocated.
2212
 */
2213
static xmlXPathContextCachePtr
2214
xmlXPathNewCache(void)
2215
37.3k
{
2216
37.3k
    xmlXPathContextCachePtr ret;
2217
2218
37.3k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219
37.3k
    if (ret == NULL) {
2220
25
        xmlXPathErrMemory(NULL, "creating object cache\n");
2221
25
  return(NULL);
2222
25
    }
2223
37.2k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2224
37.2k
    ret->maxNodeset = 100;
2225
37.2k
    ret->maxString = 100;
2226
37.2k
    ret->maxBoolean = 100;
2227
37.2k
    ret->maxNumber = 100;
2228
37.2k
    ret->maxMisc = 100;
2229
37.2k
    return(ret);
2230
37.3k
}
2231
2232
static void
2233
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234
25.0k
{
2235
25.0k
    int i;
2236
25.0k
    xmlXPathObjectPtr obj;
2237
2238
25.0k
    if (list == NULL)
2239
0
  return;
2240
2241
387k
    for (i = 0; i < list->number; i++) {
2242
362k
  obj = list->items[i];
2243
  /*
2244
  * Note that it is already assured that we don't need to
2245
  * look out for namespace nodes in the node-set.
2246
  */
2247
362k
  if (obj->nodesetval != NULL) {
2248
290k
      if (obj->nodesetval->nodeTab != NULL)
2249
256k
    xmlFree(obj->nodesetval->nodeTab);
2250
290k
      xmlFree(obj->nodesetval);
2251
290k
  }
2252
362k
  xmlFree(obj);
2253
#ifdef XP_DEBUG_OBJ_USAGE
2254
  xmlXPathDebugObjCounterAll--;
2255
#endif
2256
362k
    }
2257
25.0k
    xmlPointerListFree(list);
2258
25.0k
}
2259
2260
static void
2261
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262
37.2k
{
2263
37.2k
    if (cache == NULL)
2264
0
  return;
2265
37.2k
    if (cache->nodesetObjs)
2266
10.5k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267
37.2k
    if (cache->stringObjs)
2268
2.44k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2269
37.2k
    if (cache->booleanObjs)
2270
2.98k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271
37.2k
    if (cache->numberObjs)
2272
3.52k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2273
37.2k
    if (cache->miscObjs)
2274
5.52k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2275
37.2k
    xmlFree(cache);
2276
37.2k
}
2277
2278
/**
2279
 * xmlXPathContextSetCache:
2280
 *
2281
 * @ctxt:  the XPath context
2282
 * @active: enables/disables (creates/frees) the cache
2283
 * @value: a value with semantics dependent on @options
2284
 * @options: options (currently only the value 0 is used)
2285
 *
2286
 * Creates/frees an object cache on the XPath context.
2287
 * If activates XPath objects (xmlXPathObject) will be cached internally
2288
 * to be reused.
2289
 * @options:
2290
 *   0: This will set the XPath object caching:
2291
 *      @value:
2292
 *        This will set the maximum number of XPath objects
2293
 *        to be cached per slot
2294
 *        There are 5 slots for: node-set, string, number, boolean, and
2295
 *        misc objects. Use <0 for the default number (100).
2296
 *   Other values for @options have currently no effect.
2297
 *
2298
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2299
 */
2300
int
2301
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2302
      int active,
2303
      int value,
2304
      int options)
2305
37.3k
{
2306
37.3k
    if (ctxt == NULL)
2307
0
  return(-1);
2308
37.3k
    if (active) {
2309
37.3k
  xmlXPathContextCachePtr cache;
2310
2311
37.3k
  if (ctxt->cache == NULL) {
2312
37.3k
      ctxt->cache = xmlXPathNewCache();
2313
37.3k
      if (ctxt->cache == NULL)
2314
25
    return(-1);
2315
37.3k
  }
2316
37.2k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2317
37.2k
  if (options == 0) {
2318
37.2k
      if (value < 0)
2319
37.2k
    value = 100;
2320
37.2k
      cache->maxNodeset = value;
2321
37.2k
      cache->maxString = value;
2322
37.2k
      cache->maxNumber = value;
2323
37.2k
      cache->maxBoolean = value;
2324
37.2k
      cache->maxMisc = value;
2325
37.2k
  }
2326
37.2k
    } else if (ctxt->cache != NULL) {
2327
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328
0
  ctxt->cache = NULL;
2329
0
    }
2330
37.2k
    return(0);
2331
37.3k
}
2332
2333
/**
2334
 * xmlXPathCacheWrapNodeSet:
2335
 * @ctxt: the XPath context
2336
 * @val:  the NodePtr value
2337
 *
2338
 * This is the cached version of xmlXPathWrapNodeSet().
2339
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2340
 *
2341
 * Returns the created or reused object.
2342
 *
2343
 * In case of error the node set is destroyed and NULL is returned.
2344
 */
2345
static xmlXPathObjectPtr
2346
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2347
4.50M
{
2348
4.50M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349
4.49M
  xmlXPathContextCachePtr cache =
2350
4.49M
      (xmlXPathContextCachePtr) ctxt->cache;
2351
2352
4.49M
  if ((cache->miscObjs != NULL) &&
2353
4.49M
      (cache->miscObjs->number != 0))
2354
2.52M
  {
2355
2.52M
      xmlXPathObjectPtr ret;
2356
2357
2.52M
      ret = (xmlXPathObjectPtr)
2358
2.52M
    cache->miscObjs->items[--cache->miscObjs->number];
2359
2.52M
      ret->type = XPATH_NODESET;
2360
2.52M
      ret->nodesetval = val;
2361
#ifdef XP_DEBUG_OBJ_USAGE
2362
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363
#endif
2364
2.52M
      return(ret);
2365
2.52M
  }
2366
4.49M
    }
2367
2368
1.97M
    return(xmlXPathWrapNodeSet(val));
2369
2370
4.50M
}
2371
2372
/**
2373
 * xmlXPathCacheWrapString:
2374
 * @ctxt: the XPath context
2375
 * @val:  the xmlChar * value
2376
 *
2377
 * This is the cached version of xmlXPathWrapString().
2378
 * Wraps the @val string into an XPath object.
2379
 *
2380
 * Returns the created or reused object.
2381
 */
2382
static xmlXPathObjectPtr
2383
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2384
440k
{
2385
440k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386
440k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387
2388
440k
  if ((cache->stringObjs != NULL) &&
2389
440k
      (cache->stringObjs->number != 0))
2390
21.7k
  {
2391
2392
21.7k
      xmlXPathObjectPtr ret;
2393
2394
21.7k
      ret = (xmlXPathObjectPtr)
2395
21.7k
    cache->stringObjs->items[--cache->stringObjs->number];
2396
21.7k
      ret->type = XPATH_STRING;
2397
21.7k
      ret->stringval = val;
2398
#ifdef XP_DEBUG_OBJ_USAGE
2399
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400
#endif
2401
21.7k
      return(ret);
2402
418k
  } else if ((cache->miscObjs != NULL) &&
2403
418k
      (cache->miscObjs->number != 0))
2404
395k
  {
2405
395k
      xmlXPathObjectPtr ret;
2406
      /*
2407
      * Fallback to misc-cache.
2408
      */
2409
395k
      ret = (xmlXPathObjectPtr)
2410
395k
    cache->miscObjs->items[--cache->miscObjs->number];
2411
2412
395k
      ret->type = XPATH_STRING;
2413
395k
      ret->stringval = val;
2414
#ifdef XP_DEBUG_OBJ_USAGE
2415
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416
#endif
2417
395k
      return(ret);
2418
395k
  }
2419
440k
    }
2420
23.0k
    return(xmlXPathWrapString(val));
2421
440k
}
2422
2423
/**
2424
 * xmlXPathCacheNewNodeSet:
2425
 * @ctxt: the XPath context
2426
 * @val:  the NodePtr value
2427
 *
2428
 * This is the cached version of xmlXPathNewNodeSet().
2429
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2430
 * it with the single Node @val
2431
 *
2432
 * Returns the created or reused object.
2433
 */
2434
static xmlXPathObjectPtr
2435
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2436
8.83M
{
2437
8.83M
    if ((ctxt != NULL) && (ctxt->cache)) {
2438
8.83M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439
2440
8.83M
  if ((cache->nodesetObjs != NULL) &&
2441
8.83M
      (cache->nodesetObjs->number != 0))
2442
7.04M
  {
2443
7.04M
      xmlXPathObjectPtr ret;
2444
      /*
2445
      * Use the nodeset-cache.
2446
      */
2447
7.04M
      ret = (xmlXPathObjectPtr)
2448
7.04M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449
7.04M
      ret->type = XPATH_NODESET;
2450
7.04M
      ret->boolval = 0;
2451
7.04M
      if (val) {
2452
6.32M
    if ((ret->nodesetval->nodeMax == 0) ||
2453
6.32M
        (val->type == XML_NAMESPACE_DECL))
2454
993k
    {
2455
                    /* TODO: Check memory error. */
2456
993k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457
5.32M
    } else {
2458
5.32M
        ret->nodesetval->nodeTab[0] = val;
2459
5.32M
        ret->nodesetval->nodeNr = 1;
2460
5.32M
    }
2461
6.32M
      }
2462
#ifdef XP_DEBUG_OBJ_USAGE
2463
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464
#endif
2465
7.04M
      return(ret);
2466
7.04M
  } else if ((cache->miscObjs != NULL) &&
2467
1.78M
      (cache->miscObjs->number != 0))
2468
141k
  {
2469
141k
      xmlXPathObjectPtr ret;
2470
141k
            xmlNodeSetPtr set;
2471
      /*
2472
      * Fallback to misc-cache.
2473
      */
2474
2475
141k
      set = xmlXPathNodeSetCreate(val);
2476
141k
      if (set == NULL) {
2477
126
    ctxt->lastError.domain = XML_FROM_XPATH;
2478
126
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2479
126
    return(NULL);
2480
126
      }
2481
2482
141k
      ret = (xmlXPathObjectPtr)
2483
141k
    cache->miscObjs->items[--cache->miscObjs->number];
2484
2485
141k
      ret->type = XPATH_NODESET;
2486
141k
      ret->boolval = 0;
2487
141k
      ret->nodesetval = set;
2488
#ifdef XP_DEBUG_OBJ_USAGE
2489
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490
#endif
2491
141k
      return(ret);
2492
141k
  }
2493
8.83M
    }
2494
1.64M
    return(xmlXPathNewNodeSet(val));
2495
8.83M
}
2496
2497
/**
2498
 * xmlXPathCacheNewString:
2499
 * @ctxt: the XPath context
2500
 * @val:  the xmlChar * value
2501
 *
2502
 * This is the cached version of xmlXPathNewString().
2503
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2504
 *
2505
 * Returns the created or reused object.
2506
 */
2507
static xmlXPathObjectPtr
2508
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2509
557k
{
2510
557k
    if ((ctxt != NULL) && (ctxt->cache)) {
2511
557k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512
2513
557k
  if ((cache->stringObjs != NULL) &&
2514
557k
      (cache->stringObjs->number != 0))
2515
274k
  {
2516
274k
      xmlXPathObjectPtr ret;
2517
274k
            xmlChar *copy;
2518
2519
274k
            if (val == NULL)
2520
1.44k
                val = BAD_CAST "";
2521
274k
            copy = xmlStrdup(val);
2522
274k
            if (copy == NULL) {
2523
432
                xmlXPathErrMemory(ctxt, NULL);
2524
432
                return(NULL);
2525
432
            }
2526
2527
273k
      ret = (xmlXPathObjectPtr)
2528
273k
    cache->stringObjs->items[--cache->stringObjs->number];
2529
273k
      ret->type = XPATH_STRING;
2530
273k
            ret->stringval = copy;
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
273k
      return(ret);
2535
282k
  } else if ((cache->miscObjs != NULL) &&
2536
282k
      (cache->miscObjs->number != 0))
2537
119k
  {
2538
119k
      xmlXPathObjectPtr ret;
2539
119k
            xmlChar *copy;
2540
2541
119k
            if (val == NULL)
2542
101
                val = BAD_CAST "";
2543
119k
            copy = xmlStrdup(val);
2544
119k
            if (copy == NULL) {
2545
899
                xmlXPathErrMemory(ctxt, NULL);
2546
899
                return(NULL);
2547
899
            }
2548
2549
118k
      ret = (xmlXPathObjectPtr)
2550
118k
    cache->miscObjs->items[--cache->miscObjs->number];
2551
2552
118k
      ret->type = XPATH_STRING;
2553
118k
            ret->stringval = copy;
2554
#ifdef XP_DEBUG_OBJ_USAGE
2555
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556
#endif
2557
118k
      return(ret);
2558
119k
  }
2559
557k
    }
2560
163k
    return(xmlXPathNewString(val));
2561
557k
}
2562
2563
/**
2564
 * xmlXPathCacheNewCString:
2565
 * @ctxt: the XPath context
2566
 * @val:  the char * value
2567
 *
2568
 * This is the cached version of xmlXPathNewCString().
2569
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2570
 *
2571
 * Returns the created or reused object.
2572
 */
2573
static xmlXPathObjectPtr
2574
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2575
10.2k
{
2576
10.2k
    return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2577
10.2k
}
2578
2579
/**
2580
 * xmlXPathCacheNewBoolean:
2581
 * @ctxt: the XPath context
2582
 * @val:  the boolean value
2583
 *
2584
 * This is the cached version of xmlXPathNewBoolean().
2585
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586
 *
2587
 * Returns the created or reused object.
2588
 */
2589
static xmlXPathObjectPtr
2590
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591
1.59M
{
2592
1.59M
    if ((ctxt != NULL) && (ctxt->cache)) {
2593
1.59M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595
1.59M
  if ((cache->booleanObjs != NULL) &&
2596
1.59M
      (cache->booleanObjs->number != 0))
2597
1.08M
  {
2598
1.08M
      xmlXPathObjectPtr ret;
2599
2600
1.08M
      ret = (xmlXPathObjectPtr)
2601
1.08M
    cache->booleanObjs->items[--cache->booleanObjs->number];
2602
1.08M
      ret->type = XPATH_BOOLEAN;
2603
1.08M
      ret->boolval = (val != 0);
2604
#ifdef XP_DEBUG_OBJ_USAGE
2605
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606
#endif
2607
1.08M
      return(ret);
2608
1.08M
  } else if ((cache->miscObjs != NULL) &&
2609
512k
      (cache->miscObjs->number != 0))
2610
143k
  {
2611
143k
      xmlXPathObjectPtr ret;
2612
2613
143k
      ret = (xmlXPathObjectPtr)
2614
143k
    cache->miscObjs->items[--cache->miscObjs->number];
2615
2616
143k
      ret->type = XPATH_BOOLEAN;
2617
143k
      ret->boolval = (val != 0);
2618
#ifdef XP_DEBUG_OBJ_USAGE
2619
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620
#endif
2621
143k
      return(ret);
2622
143k
  }
2623
1.59M
    }
2624
369k
    return(xmlXPathNewBoolean(val));
2625
1.59M
}
2626
2627
/**
2628
 * xmlXPathCacheNewFloat:
2629
 * @ctxt: the XPath context
2630
 * @val:  the double value
2631
 *
2632
 * This is the cached version of xmlXPathNewFloat().
2633
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2634
 *
2635
 * Returns the created or reused object.
2636
 */
2637
static xmlXPathObjectPtr
2638
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639
3.38M
{
2640
3.38M
     if ((ctxt != NULL) && (ctxt->cache)) {
2641
3.38M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643
3.38M
  if ((cache->numberObjs != NULL) &&
2644
3.38M
      (cache->numberObjs->number != 0))
2645
2.14M
  {
2646
2.14M
      xmlXPathObjectPtr ret;
2647
2648
2.14M
      ret = (xmlXPathObjectPtr)
2649
2.14M
    cache->numberObjs->items[--cache->numberObjs->number];
2650
2.14M
      ret->type = XPATH_NUMBER;
2651
2.14M
      ret->floatval = val;
2652
#ifdef XP_DEBUG_OBJ_USAGE
2653
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654
#endif
2655
2.14M
      return(ret);
2656
2.14M
  } else if ((cache->miscObjs != NULL) &&
2657
1.24M
      (cache->miscObjs->number != 0))
2658
448k
  {
2659
448k
      xmlXPathObjectPtr ret;
2660
2661
448k
      ret = (xmlXPathObjectPtr)
2662
448k
    cache->miscObjs->items[--cache->miscObjs->number];
2663
2664
448k
      ret->type = XPATH_NUMBER;
2665
448k
      ret->floatval = val;
2666
#ifdef XP_DEBUG_OBJ_USAGE
2667
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668
#endif
2669
448k
      return(ret);
2670
448k
  }
2671
3.38M
    }
2672
792k
    return(xmlXPathNewFloat(val));
2673
3.38M
}
2674
2675
/**
2676
 * xmlXPathCacheConvertString:
2677
 * @ctxt: the XPath context
2678
 * @val:  an XPath object
2679
 *
2680
 * This is the cached version of xmlXPathConvertString().
2681
 * Converts an existing object to its string() equivalent
2682
 *
2683
 * Returns a created or reused object, the old one is freed (cached)
2684
 *         (or the operation is done directly on @val)
2685
 */
2686
2687
static xmlXPathObjectPtr
2688
900k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689
900k
    xmlChar *res = NULL;
2690
2691
900k
    if (val == NULL)
2692
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694
900k
    switch (val->type) {
2695
0
    case XPATH_UNDEFINED:
2696
#ifdef DEBUG_EXPR
2697
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698
#endif
2699
0
  break;
2700
420k
    case XPATH_NODESET:
2701
420k
    case XPATH_XSLT_TREE:
2702
420k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2703
420k
  break;
2704
465k
    case XPATH_STRING:
2705
465k
  return(val);
2706
6.09k
    case XPATH_BOOLEAN:
2707
6.09k
  res = xmlXPathCastBooleanToString(val->boolval);
2708
6.09k
  break;
2709
8.65k
    case XPATH_NUMBER:
2710
8.65k
  res = xmlXPathCastNumberToString(val->floatval);
2711
8.65k
  break;
2712
0
    case XPATH_USERS:
2713
#ifdef LIBXML_XPTR_LOCS_ENABLED
2714
    case XPATH_POINT:
2715
    case XPATH_RANGE:
2716
    case XPATH_LOCATIONSET:
2717
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2718
0
  TODO;
2719
0
  break;
2720
900k
    }
2721
435k
    xmlXPathReleaseObject(ctxt, val);
2722
435k
    if (res == NULL)
2723
668
  return(xmlXPathCacheNewCString(ctxt, ""));
2724
434k
    return(xmlXPathCacheWrapString(ctxt, res));
2725
435k
}
2726
2727
/**
2728
 * xmlXPathCacheObjectCopy:
2729
 * @ctxt: the XPath context
2730
 * @val:  the original object
2731
 *
2732
 * This is the cached version of xmlXPathObjectCopy().
2733
 * Acquire a copy of a given object
2734
 *
2735
 * Returns a created or reused created object.
2736
 */
2737
static xmlXPathObjectPtr
2738
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739
908k
{
2740
908k
    if (val == NULL)
2741
0
  return(NULL);
2742
2743
908k
    if (XP_HAS_CACHE(ctxt)) {
2744
908k
  switch (val->type) {
2745
0
      case XPATH_NODESET:
2746
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2747
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748
159k
      case XPATH_STRING:
2749
159k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2750
0
      case XPATH_BOOLEAN:
2751
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752
749k
      case XPATH_NUMBER:
2753
749k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754
0
      default:
2755
0
    break;
2756
908k
  }
2757
908k
    }
2758
0
    return(xmlXPathObjectCopy(val));
2759
908k
}
2760
2761
/**
2762
 * xmlXPathCacheConvertBoolean:
2763
 * @ctxt: the XPath context
2764
 * @val:  an XPath object
2765
 *
2766
 * This is the cached version of xmlXPathConvertBoolean().
2767
 * Converts an existing object to its boolean() equivalent
2768
 *
2769
 * Returns a created or reused object, the old one is freed (or the operation
2770
 *         is done directly on @val)
2771
 */
2772
static xmlXPathObjectPtr
2773
305k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
305k
    xmlXPathObjectPtr ret;
2775
2776
305k
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2778
305k
    if (val->type == XPATH_BOOLEAN)
2779
40.8k
  return(val);
2780
264k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781
264k
    xmlXPathReleaseObject(ctxt, val);
2782
264k
    return(ret);
2783
305k
}
2784
2785
/**
2786
 * xmlXPathCacheConvertNumber:
2787
 * @ctxt: the XPath context
2788
 * @val:  an XPath object
2789
 *
2790
 * This is the cached version of xmlXPathConvertNumber().
2791
 * Converts an existing object to its number() equivalent
2792
 *
2793
 * Returns a created or reused object, the old one is freed (or the operation
2794
 *         is done directly on @val)
2795
 */
2796
static xmlXPathObjectPtr
2797
1.51M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798
1.51M
    xmlXPathObjectPtr ret;
2799
2800
1.51M
    if (val == NULL)
2801
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802
1.51M
    if (val->type == XPATH_NUMBER)
2803
1.14k
  return(val);
2804
1.51M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805
1.51M
    xmlXPathReleaseObject(ctxt, val);
2806
1.51M
    return(ret);
2807
1.51M
}
2808
2809
/************************************************************************
2810
 *                  *
2811
 *    Parser stacks related functions and macros    *
2812
 *                  *
2813
 ************************************************************************/
2814
2815
/**
2816
 * valuePop:
2817
 * @ctxt: an XPath evaluation context
2818
 *
2819
 * Pops the top XPath object from the value stack
2820
 *
2821
 * Returns the XPath object just removed
2822
 */
2823
xmlXPathObjectPtr
2824
valuePop(xmlXPathParserContextPtr ctxt)
2825
22.8M
{
2826
22.8M
    xmlXPathObjectPtr ret;
2827
2828
22.8M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829
49.7k
        return (NULL);
2830
2831
22.8M
    ctxt->valueNr--;
2832
22.8M
    if (ctxt->valueNr > 0)
2833
12.3M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834
10.4M
    else
2835
10.4M
        ctxt->value = NULL;
2836
22.8M
    ret = ctxt->valueTab[ctxt->valueNr];
2837
22.8M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2838
22.8M
    return (ret);
2839
22.8M
}
2840
/**
2841
 * valuePush:
2842
 * @ctxt:  an XPath evaluation context
2843
 * @value:  the XPath object
2844
 *
2845
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2846
 * a memory error is recorded in the parser context.
2847
 *
2848
 * Returns the number of items on the value stack, or -1 in case of error.
2849
 *
2850
 * The object is destroyed in case of error.
2851
 */
2852
int
2853
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854
23.3M
{
2855
23.3M
    if (ctxt == NULL) return(-1);
2856
23.3M
    if (value == NULL) {
2857
        /*
2858
         * A NULL value typically indicates that a memory allocation failed,
2859
         * so we set ctxt->error here to propagate the error.
2860
         */
2861
16.3k
  ctxt->error = XPATH_MEMORY_ERROR;
2862
16.3k
        return(-1);
2863
16.3k
    }
2864
23.3M
    if (ctxt->valueNr >= ctxt->valueMax) {
2865
32
        xmlXPathObjectPtr *tmp;
2866
2867
32
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2868
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2869
0
            xmlXPathFreeObject(value);
2870
0
            return (-1);
2871
0
        }
2872
32
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2873
32
                                             2 * ctxt->valueMax *
2874
32
                                             sizeof(ctxt->valueTab[0]));
2875
32
        if (tmp == NULL) {
2876
12
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2877
12
            xmlXPathFreeObject(value);
2878
12
            return (-1);
2879
12
        }
2880
20
        ctxt->valueMax *= 2;
2881
20
  ctxt->valueTab = tmp;
2882
20
    }
2883
23.3M
    ctxt->valueTab[ctxt->valueNr] = value;
2884
23.3M
    ctxt->value = value;
2885
23.3M
    return (ctxt->valueNr++);
2886
23.3M
}
2887
2888
/**
2889
 * xmlXPathPopBoolean:
2890
 * @ctxt:  an XPath parser context
2891
 *
2892
 * Pops a boolean from the stack, handling conversion if needed.
2893
 * Check error with #xmlXPathCheckError.
2894
 *
2895
 * Returns the boolean
2896
 */
2897
int
2898
495
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899
495
    xmlXPathObjectPtr obj;
2900
495
    int ret;
2901
2902
495
    obj = valuePop(ctxt);
2903
495
    if (obj == NULL) {
2904
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905
0
  return(0);
2906
0
    }
2907
495
    if (obj->type != XPATH_BOOLEAN)
2908
82
  ret = xmlXPathCastToBoolean(obj);
2909
413
    else
2910
413
        ret = obj->boolval;
2911
495
    xmlXPathReleaseObject(ctxt->context, obj);
2912
495
    return(ret);
2913
495
}
2914
2915
/**
2916
 * xmlXPathPopNumber:
2917
 * @ctxt:  an XPath parser context
2918
 *
2919
 * Pops a number from the stack, handling conversion if needed.
2920
 * Check error with #xmlXPathCheckError.
2921
 *
2922
 * Returns the number
2923
 */
2924
double
2925
1.62k
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2926
1.62k
    xmlXPathObjectPtr obj;
2927
1.62k
    double ret;
2928
2929
1.62k
    obj = valuePop(ctxt);
2930
1.62k
    if (obj == NULL) {
2931
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932
0
  return(0);
2933
0
    }
2934
1.62k
    if (obj->type != XPATH_NUMBER)
2935
1.29k
  ret = xmlXPathCastToNumber(obj);
2936
324
    else
2937
324
        ret = obj->floatval;
2938
1.62k
    xmlXPathReleaseObject(ctxt->context, obj);
2939
1.62k
    return(ret);
2940
1.62k
}
2941
2942
/**
2943
 * xmlXPathPopString:
2944
 * @ctxt:  an XPath parser context
2945
 *
2946
 * Pops a string from the stack, handling conversion if needed.
2947
 * Check error with #xmlXPathCheckError.
2948
 *
2949
 * Returns the string
2950
 */
2951
xmlChar *
2952
1.41M
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953
1.41M
    xmlXPathObjectPtr obj;
2954
1.41M
    xmlChar * ret;
2955
2956
1.41M
    obj = valuePop(ctxt);
2957
1.41M
    if (obj == NULL) {
2958
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959
0
  return(NULL);
2960
0
    }
2961
1.41M
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2962
    /* TODO: needs refactoring somewhere else */
2963
1.41M
    if (obj->stringval == ret)
2964
912
  obj->stringval = NULL;
2965
1.41M
    xmlXPathReleaseObject(ctxt->context, obj);
2966
1.41M
    return(ret);
2967
1.41M
}
2968
2969
/**
2970
 * xmlXPathPopNodeSet:
2971
 * @ctxt:  an XPath parser context
2972
 *
2973
 * Pops a node-set from the stack, handling conversion if needed.
2974
 * Check error with #xmlXPathCheckError.
2975
 *
2976
 * Returns the node-set
2977
 */
2978
xmlNodeSetPtr
2979
1.07M
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980
1.07M
    xmlXPathObjectPtr obj;
2981
1.07M
    xmlNodeSetPtr ret;
2982
2983
1.07M
    if (ctxt == NULL) return(NULL);
2984
1.07M
    if (ctxt->value == NULL) {
2985
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986
0
  return(NULL);
2987
0
    }
2988
1.07M
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2989
389
  xmlXPathSetTypeError(ctxt);
2990
389
  return(NULL);
2991
389
    }
2992
1.07M
    obj = valuePop(ctxt);
2993
1.07M
    ret = obj->nodesetval;
2994
#if 0
2995
    /* to fix memory leak of not clearing obj->user */
2996
    if (obj->boolval && obj->user != NULL)
2997
        xmlFreeNodeList((xmlNodePtr) obj->user);
2998
#endif
2999
1.07M
    obj->nodesetval = NULL;
3000
1.07M
    xmlXPathReleaseObject(ctxt->context, obj);
3001
1.07M
    return(ret);
3002
1.07M
}
3003
3004
/**
3005
 * xmlXPathPopExternal:
3006
 * @ctxt:  an XPath parser context
3007
 *
3008
 * Pops an external object from the stack, handling conversion if needed.
3009
 * Check error with #xmlXPathCheckError.
3010
 *
3011
 * Returns the object
3012
 */
3013
void *
3014
781
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3015
781
    xmlXPathObjectPtr obj;
3016
781
    void * ret;
3017
3018
781
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3019
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3020
0
  return(NULL);
3021
0
    }
3022
781
    if (ctxt->value->type != XPATH_USERS) {
3023
0
  xmlXPathSetTypeError(ctxt);
3024
0
  return(NULL);
3025
0
    }
3026
781
    obj = valuePop(ctxt);
3027
781
    ret = obj->user;
3028
781
    obj->user = NULL;
3029
781
    xmlXPathReleaseObject(ctxt->context, obj);
3030
781
    return(ret);
3031
781
}
3032
3033
/*
3034
 * Macros for accessing the content. Those should be used only by the parser,
3035
 * and not exported.
3036
 *
3037
 * Dirty macros, i.e. one need to make assumption on the context to use them
3038
 *
3039
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3040
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3041
 *           in ISO-Latin or UTF-8.
3042
 *           This should be used internally by the parser
3043
 *           only to compare to ASCII values otherwise it would break when
3044
 *           running with UTF-8 encoding.
3045
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3046
 *           to compare on ASCII based substring.
3047
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3048
 *           strings within the parser.
3049
 *   CURRENT Returns the current char value, with the full decoding of
3050
 *           UTF-8 if we are using this mode. It returns an int.
3051
 *   NEXT    Skip to the next character, this does the proper decoding
3052
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3053
 *           It returns the pointer to the current xmlChar.
3054
 */
3055
3056
922M
#define CUR (*ctxt->cur)
3057
840k
#define SKIP(val) ctxt->cur += (val)
3058
21.1M
#define NXT(val) ctxt->cur[(val)]
3059
491k
#define CUR_PTR ctxt->cur
3060
33.1M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061
3062
#define COPY_BUF(l,b,i,v)                                              \
3063
13.0M
    if (l == 1) b[i++] = v;                                            \
3064
13.0M
    else i += xmlCopyChar(l,&b[i],v)
3065
3066
28.0M
#define NEXTL(l)  ctxt->cur += l
3067
3068
#define SKIP_BLANKS             \
3069
530M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070
3071
#define CURRENT (*ctxt->cur)
3072
386M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3073
3074
3075
#ifndef DBL_DIG
3076
#define DBL_DIG 16
3077
#endif
3078
#ifndef DBL_EPSILON
3079
#define DBL_EPSILON 1E-9
3080
#endif
3081
3082
15.1k
#define UPPER_DOUBLE 1E9
3083
4.23k
#define LOWER_DOUBLE 1E-5
3084
#define LOWER_DOUBLE_EXP 5
3085
3086
#define INTEGER_DIGITS DBL_DIG
3087
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3088
11.8k
#define EXPONENT_DIGITS (3 + 2)
3089
3090
/**
3091
 * xmlXPathFormatNumber:
3092
 * @number:     number to format
3093
 * @buffer:     output buffer
3094
 * @buffersize: size of output buffer
3095
 *
3096
 * Convert the number into a string representation.
3097
 */
3098
static void
3099
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3100
117k
{
3101
117k
    switch (xmlXPathIsInf(number)) {
3102
0
    case 1:
3103
0
  if (buffersize > (int)sizeof("Infinity"))
3104
0
      snprintf(buffer, buffersize, "Infinity");
3105
0
  break;
3106
0
    case -1:
3107
0
  if (buffersize > (int)sizeof("-Infinity"))
3108
0
      snprintf(buffer, buffersize, "-Infinity");
3109
0
  break;
3110
117k
    default:
3111
117k
  if (xmlXPathIsNaN(number)) {
3112
0
      if (buffersize > (int)sizeof("NaN"))
3113
0
    snprintf(buffer, buffersize, "NaN");
3114
117k
  } else if (number == 0) {
3115
            /* Omit sign for negative zero. */
3116
0
      snprintf(buffer, buffersize, "0");
3117
117k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3118
117k
                   (number == (int) number)) {
3119
102k
      char work[30];
3120
102k
      char *ptr, *cur;
3121
102k
      int value = (int) number;
3122
3123
102k
            ptr = &buffer[0];
3124
102k
      if (value == 0) {
3125
0
    *ptr++ = '0';
3126
102k
      } else {
3127
102k
    snprintf(work, 29, "%d", value);
3128
102k
    cur = &work[0];
3129
278k
    while ((*cur) && (ptr - buffer < buffersize)) {
3130
176k
        *ptr++ = *cur++;
3131
176k
    }
3132
102k
      }
3133
102k
      if (ptr - buffer < buffersize) {
3134
102k
    *ptr = 0;
3135
102k
      } else if (buffersize > 0) {
3136
0
    ptr--;
3137
0
    *ptr = 0;
3138
0
      }
3139
102k
  } else {
3140
      /*
3141
        For the dimension of work,
3142
            DBL_DIG is number of significant digits
3143
      EXPONENT is only needed for "scientific notation"
3144
            3 is sign, decimal point, and terminating zero
3145
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3146
        Note that this dimension is slightly (a few characters)
3147
        larger than actually necessary.
3148
      */
3149
15.1k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3150
15.1k
      int integer_place, fraction_place;
3151
15.1k
      char *ptr;
3152
15.1k
      char *after_fraction;
3153
15.1k
      double absolute_value;
3154
15.1k
      int size;
3155
3156
15.1k
      absolute_value = fabs(number);
3157
3158
      /*
3159
       * First choose format - scientific or regular floating point.
3160
       * In either case, result is in work, and after_fraction points
3161
       * just past the fractional part.
3162
      */
3163
15.1k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3164
15.1k
      (absolute_value < LOWER_DOUBLE)) &&
3165
15.1k
     (absolute_value != 0.0) ) {
3166
    /* Use scientific notation */
3167
11.8k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3168
11.8k
    fraction_place = DBL_DIG - 1;
3169
11.8k
    size = snprintf(work, sizeof(work),"%*.*e",
3170
11.8k
       integer_place, fraction_place, number);
3171
59.8k
    while ((size > 0) && (work[size] != 'e')) size--;
3172
3173
11.8k
      }
3174
3.28k
      else {
3175
    /* Use regular notation */
3176
3.28k
    if (absolute_value > 0.0) {
3177
3.28k
        integer_place = (int)log10(absolute_value);
3178
3.28k
        if (integer_place > 0)
3179
641
            fraction_place = DBL_DIG - integer_place - 1;
3180
2.64k
        else
3181
2.64k
            fraction_place = DBL_DIG - integer_place;
3182
3.28k
    } else {
3183
0
        fraction_place = 1;
3184
0
    }
3185
3.28k
    size = snprintf(work, sizeof(work), "%0.*f",
3186
3.28k
        fraction_place, number);
3187
3.28k
      }
3188
3189
      /* Remove leading spaces sometimes inserted by snprintf */
3190
25.3k
      while (work[0] == ' ') {
3191
215k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192
10.2k
    size--;
3193
10.2k
      }
3194
3195
      /* Remove fractional trailing zeroes */
3196
15.1k
      after_fraction = work + size;
3197
15.1k
      ptr = after_fraction;
3198
73.6k
      while (*(--ptr) == '0')
3199
58.5k
    ;
3200
15.1k
      if (*ptr != '.')
3201
14.5k
          ptr++;
3202
63.1k
      while ((*ptr++ = *after_fraction++) != 0);
3203
3204
      /* Finally copy result back to caller */
3205
15.1k
      size = strlen(work) + 1;
3206
15.1k
      if (size > buffersize) {
3207
0
    work[buffersize - 1] = 0;
3208
0
    size = buffersize;
3209
0
      }
3210
15.1k
      memmove(buffer, work, size);
3211
15.1k
  }
3212
117k
  break;
3213
117k
    }
3214
117k
}
3215
3216
3217
/************************************************************************
3218
 *                  *
3219
 *      Routines to handle NodeSets     *
3220
 *                  *
3221
 ************************************************************************/
3222
3223
/**
3224
 * xmlXPathOrderDocElems:
3225
 * @doc:  an input document
3226
 *
3227
 * Call this routine to speed up XPath computation on static documents.
3228
 * This stamps all the element nodes with the document order
3229
 * Like for line information, the order is kept in the element->content
3230
 * field, the value stored is actually - the node number (starting at -1)
3231
 * to be able to differentiate from line numbers.
3232
 *
3233
 * Returns the number of elements found in the document or -1 in case
3234
 *    of error.
3235
 */
3236
long
3237
14.1k
xmlXPathOrderDocElems(xmlDocPtr doc) {
3238
14.1k
    ptrdiff_t count = 0;
3239
14.1k
    xmlNodePtr cur;
3240
3241
14.1k
    if (doc == NULL)
3242
0
  return(-1);
3243
14.1k
    cur = doc->children;
3244
520k
    while (cur != NULL) {
3245
506k
  if (cur->type == XML_ELEMENT_NODE) {
3246
330k
      cur->content = (void *) (-(++count));
3247
330k
      if (cur->children != NULL) {
3248
89.7k
    cur = cur->children;
3249
89.7k
    continue;
3250
89.7k
      }
3251
330k
  }
3252
417k
  if (cur->next != NULL) {
3253
347k
      cur = cur->next;
3254
347k
      continue;
3255
347k
  }
3256
103k
  do {
3257
103k
      cur = cur->parent;
3258
103k
      if (cur == NULL)
3259
0
    break;
3260
103k
      if (cur == (xmlNodePtr) doc) {
3261
14.1k
    cur = NULL;
3262
14.1k
    break;
3263
14.1k
      }
3264
89.7k
      if (cur->next != NULL) {
3265
55.3k
    cur = cur->next;
3266
55.3k
    break;
3267
55.3k
      }
3268
89.7k
  } while (cur != NULL);
3269
69.4k
    }
3270
14.1k
    return(count);
3271
14.1k
}
3272
3273
/**
3274
 * xmlXPathCmpNodes:
3275
 * @node1:  the first node
3276
 * @node2:  the second node
3277
 *
3278
 * Compare two nodes w.r.t document order
3279
 *
3280
 * Returns -2 in case of error 1 if first point < second point, 0 if
3281
 *         it's the same node, -1 otherwise
3282
 */
3283
int
3284
16.1k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285
16.1k
    int depth1, depth2;
3286
16.1k
    int attr1 = 0, attr2 = 0;
3287
16.1k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288
16.1k
    xmlNodePtr cur, root;
3289
3290
16.1k
    if ((node1 == NULL) || (node2 == NULL))
3291
0
  return(-2);
3292
    /*
3293
     * a couple of optimizations which will avoid computations in most cases
3294
     */
3295
16.1k
    if (node1 == node2)    /* trivial case */
3296
0
  return(0);
3297
16.1k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3298
0
  attr1 = 1;
3299
0
  attrNode1 = node1;
3300
0
  node1 = node1->parent;
3301
0
    }
3302
16.1k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr2 = 1;
3304
0
  attrNode2 = node2;
3305
0
  node2 = node2->parent;
3306
0
    }
3307
16.1k
    if (node1 == node2) {
3308
0
  if (attr1 == attr2) {
3309
      /* not required, but we keep attributes in order */
3310
0
      if (attr1 != 0) {
3311
0
          cur = attrNode2->prev;
3312
0
    while (cur != NULL) {
3313
0
        if (cur == attrNode1)
3314
0
            return (1);
3315
0
        cur = cur->prev;
3316
0
    }
3317
0
    return (-1);
3318
0
      }
3319
0
      return(0);
3320
0
  }
3321
0
  if (attr2 == 1)
3322
0
      return(1);
3323
0
  return(-1);
3324
0
    }
3325
16.1k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3326
16.1k
        (node2->type == XML_NAMESPACE_DECL))
3327
825
  return(1);
3328
15.2k
    if (node1 == node2->prev)
3329
18
  return(1);
3330
15.2k
    if (node1 == node2->next)
3331
0
  return(-1);
3332
3333
    /*
3334
     * Speedup using document order if available.
3335
     */
3336
15.2k
    if ((node1->type == XML_ELEMENT_NODE) &&
3337
15.2k
  (node2->type == XML_ELEMENT_NODE) &&
3338
15.2k
  (0 > (ptrdiff_t) node1->content) &&
3339
15.2k
  (0 > (ptrdiff_t) node2->content) &&
3340
15.2k
  (node1->doc == node2->doc)) {
3341
430
  ptrdiff_t l1, l2;
3342
3343
430
  l1 = -((ptrdiff_t) node1->content);
3344
430
  l2 = -((ptrdiff_t) node2->content);
3345
430
  if (l1 < l2)
3346
426
      return(1);
3347
4
  if (l1 > l2)
3348
4
      return(-1);
3349
4
    }
3350
3351
    /*
3352
     * compute depth to root
3353
     */
3354
318k
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355
304k
  if (cur->parent == node1)
3356
495
      return(1);
3357
304k
  depth2++;
3358
304k
    }
3359
14.3k
    root = cur;
3360
55.5k
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361
41.1k
  if (cur->parent == node2)
3362
0
      return(-1);
3363
41.1k
  depth1++;
3364
41.1k
    }
3365
    /*
3366
     * Distinct document (or distinct entities :-( ) case.
3367
     */
3368
14.3k
    if (root != cur) {
3369
1.04k
  return(-2);
3370
1.04k
    }
3371
    /*
3372
     * get the nearest common ancestor.
3373
     */
3374
13.4k
    while (depth1 > depth2) {
3375
158
  depth1--;
3376
158
  node1 = node1->parent;
3377
158
    }
3378
270k
    while (depth2 > depth1) {
3379
257k
  depth2--;
3380
257k
  node2 = node2->parent;
3381
257k
    }
3382
25.8k
    while (node1->parent != node2->parent) {
3383
12.5k
  node1 = node1->parent;
3384
12.5k
  node2 = node2->parent;
3385
  /* should not happen but just in case ... */
3386
12.5k
  if ((node1 == NULL) || (node2 == NULL))
3387
0
      return(-2);
3388
12.5k
    }
3389
    /*
3390
     * Find who's first.
3391
     */
3392
13.2k
    if (node1 == node2->prev)
3393
1.09k
  return(1);
3394
12.1k
    if (node1 == node2->next)
3395
0
  return(-1);
3396
    /*
3397
     * Speedup using document order if available.
3398
     */
3399
12.1k
    if ((node1->type == XML_ELEMENT_NODE) &&
3400
12.1k
  (node2->type == XML_ELEMENT_NODE) &&
3401
12.1k
  (0 > (ptrdiff_t) node1->content) &&
3402
12.1k
  (0 > (ptrdiff_t) node2->content) &&
3403
12.1k
  (node1->doc == node2->doc)) {
3404
10.9k
  ptrdiff_t l1, l2;
3405
3406
10.9k
  l1 = -((ptrdiff_t) node1->content);
3407
10.9k
  l2 = -((ptrdiff_t) node2->content);
3408
10.9k
  if (l1 < l2)
3409
10.9k
      return(1);
3410
0
  if (l1 > l2)
3411
0
      return(-1);
3412
0
    }
3413
3414
4.63k
    for (cur = node1->next;cur != NULL;cur = cur->next)
3415
4.63k
  if (cur == node2)
3416
1.22k
      return(1);
3417
0
    return(-1); /* assume there is no sibling list corruption */
3418
1.22k
}
3419
3420
/**
3421
 * xmlXPathNodeSetSort:
3422
 * @set:  the node set
3423
 *
3424
 * Sort the node set in document order
3425
 */
3426
void
3427
1.39M
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428
#ifndef WITH_TIM_SORT
3429
    int i, j, incr, len;
3430
    xmlNodePtr tmp;
3431
#endif
3432
3433
1.39M
    if (set == NULL)
3434
0
  return;
3435
3436
#ifndef WITH_TIM_SORT
3437
    /*
3438
     * Use the old Shell's sort implementation to sort the node-set
3439
     * Timsort ought to be quite faster
3440
     */
3441
    len = set->nodeNr;
3442
    for (incr = len / 2; incr > 0; incr /= 2) {
3443
  for (i = incr; i < len; i++) {
3444
      j = i - incr;
3445
      while (j >= 0) {
3446
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3447
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3448
      set->nodeTab[j + incr]) == -1)
3449
#else
3450
    if (xmlXPathCmpNodes(set->nodeTab[j],
3451
      set->nodeTab[j + incr]) == -1)
3452
#endif
3453
    {
3454
        tmp = set->nodeTab[j];
3455
        set->nodeTab[j] = set->nodeTab[j + incr];
3456
        set->nodeTab[j + incr] = tmp;
3457
        j -= incr;
3458
    } else
3459
        break;
3460
      }
3461
  }
3462
    }
3463
#else /* WITH_TIM_SORT */
3464
1.39M
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465
1.39M
#endif /* WITH_TIM_SORT */
3466
1.39M
}
3467
3468
13.6M
#define XML_NODESET_DEFAULT 10
3469
/**
3470
 * xmlXPathNodeSetDupNs:
3471
 * @node:  the parent node of the namespace XPath node
3472
 * @ns:  the libxml namespace declaration node.
3473
 *
3474
 * Namespace node in libxml don't match the XPath semantic. In a node set
3475
 * the namespace nodes are duplicated and the next pointer is set to the
3476
 * parent node in the XPath semantic.
3477
 *
3478
 * Returns the newly created object.
3479
 */
3480
static xmlNodePtr
3481
501k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482
501k
    xmlNsPtr cur;
3483
3484
501k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485
0
  return(NULL);
3486
501k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3487
0
  return((xmlNodePtr) ns);
3488
3489
    /*
3490
     * Allocate a new Namespace and fill the fields.
3491
     */
3492
501k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493
501k
    if (cur == NULL) {
3494
1.33k
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495
1.33k
  return(NULL);
3496
1.33k
    }
3497
500k
    memset(cur, 0, sizeof(xmlNs));
3498
500k
    cur->type = XML_NAMESPACE_DECL;
3499
500k
    if (ns->href != NULL)
3500
500k
  cur->href = xmlStrdup(ns->href);
3501
500k
    if (ns->prefix != NULL)
3502
484k
  cur->prefix = xmlStrdup(ns->prefix);
3503
500k
    cur->next = (xmlNsPtr) node;
3504
500k
    return((xmlNodePtr) cur);
3505
501k
}
3506
3507
/**
3508
 * xmlXPathNodeSetFreeNs:
3509
 * @ns:  the XPath namespace node found in a nodeset.
3510
 *
3511
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3512
 * the namespace nodes are duplicated and the next pointer is set to the
3513
 * parent node in the XPath semantic. Check if such a node needs to be freed
3514
 */
3515
void
3516
500k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517
500k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518
0
  return;
3519
3520
500k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521
500k
  if (ns->href != NULL)
3522
500k
      xmlFree((xmlChar *)ns->href);
3523
500k
  if (ns->prefix != NULL)
3524
483k
      xmlFree((xmlChar *)ns->prefix);
3525
500k
  xmlFree(ns);
3526
500k
    }
3527
500k
}
3528
3529
/**
3530
 * xmlXPathNodeSetCreate:
3531
 * @val:  an initial xmlNodePtr, or NULL
3532
 *
3533
 * Create a new xmlNodeSetPtr of type double and of value @val
3534
 *
3535
 * Returns the newly created object.
3536
 */
3537
xmlNodeSetPtr
3538
8.21M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3539
8.21M
    xmlNodeSetPtr ret;
3540
3541
8.21M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542
8.21M
    if (ret == NULL) {
3543
11.9k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3544
11.9k
  return(NULL);
3545
11.9k
    }
3546
8.20M
    memset(ret, 0 , sizeof(xmlNodeSet));
3547
8.20M
    if (val != NULL) {
3548
977k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549
977k
               sizeof(xmlNodePtr));
3550
977k
  if (ret->nodeTab == NULL) {
3551
91
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3552
91
      xmlFree(ret);
3553
91
      return(NULL);
3554
91
  }
3555
977k
  memset(ret->nodeTab, 0 ,
3556
977k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557
977k
        ret->nodeMax = XML_NODESET_DEFAULT;
3558
977k
  if (val->type == XML_NAMESPACE_DECL) {
3559
2.32k
      xmlNsPtr ns = (xmlNsPtr) val;
3560
2.32k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3561
3562
2.32k
            if (nsNode == NULL) {
3563
2
                xmlXPathFreeNodeSet(ret);
3564
2
                return(NULL);
3565
2
            }
3566
2.32k
      ret->nodeTab[ret->nodeNr++] = nsNode;
3567
2.32k
  } else
3568
974k
      ret->nodeTab[ret->nodeNr++] = val;
3569
977k
    }
3570
8.20M
    return(ret);
3571
8.20M
}
3572
3573
/**
3574
 * xmlXPathNodeSetContains:
3575
 * @cur:  the node-set
3576
 * @val:  the node
3577
 *
3578
 * checks whether @cur contains @val
3579
 *
3580
 * Returns true (1) if @cur contains @val, false (0) otherwise
3581
 */
3582
int
3583
19.5k
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3584
19.5k
    int i;
3585
3586
19.5k
    if ((cur == NULL) || (val == NULL)) return(0);
3587
19.5k
    if (val->type == XML_NAMESPACE_DECL) {
3588
23.4k
  for (i = 0; i < cur->nodeNr; i++) {
3589
22.4k
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3590
20.8k
    xmlNsPtr ns1, ns2;
3591
3592
20.8k
    ns1 = (xmlNsPtr) val;
3593
20.8k
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3594
20.8k
    if (ns1 == ns2)
3595
0
        return(1);
3596
20.8k
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3597
20.8k
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3598
163
        return(1);
3599
20.8k
      }
3600
22.4k
  }
3601
18.3k
    } else {
3602
1.00M
  for (i = 0; i < cur->nodeNr; i++) {
3603
998k
      if (cur->nodeTab[i] == val)
3604
9.15k
    return(1);
3605
998k
  }
3606
18.3k
    }
3607
10.1k
    return(0);
3608
19.5k
}
3609
3610
/**
3611
 * xmlXPathNodeSetAddNs:
3612
 * @cur:  the initial node set
3613
 * @node:  the hosting node
3614
 * @ns:  a the namespace node
3615
 *
3616
 * add a new namespace node to an existing NodeSet
3617
 *
3618
 * Returns 0 in case of success and -1 in case of error
3619
 */
3620
int
3621
311k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622
311k
    int i;
3623
311k
    xmlNodePtr nsNode;
3624
3625
311k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626
311k
        (ns->type != XML_NAMESPACE_DECL) ||
3627
311k
  (node->type != XML_ELEMENT_NODE))
3628
0
  return(-1);
3629
3630
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3631
    /*
3632
     * prevent duplicates
3633
     */
3634
1.01M
    for (i = 0;i < cur->nodeNr;i++) {
3635
708k
        if ((cur->nodeTab[i] != NULL) &&
3636
708k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637
708k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638
708k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639
6
      return(0);
3640
708k
    }
3641
3642
    /*
3643
     * grow the nodeTab if needed
3644
     */
3645
311k
    if (cur->nodeMax == 0) {
3646
32.5k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647
32.5k
               sizeof(xmlNodePtr));
3648
32.5k
  if (cur->nodeTab == NULL) {
3649
15
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3650
15
      return(-1);
3651
15
  }
3652
32.4k
  memset(cur->nodeTab, 0 ,
3653
32.4k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654
32.4k
        cur->nodeMax = XML_NODESET_DEFAULT;
3655
278k
    } else if (cur->nodeNr == cur->nodeMax) {
3656
1.89k
        xmlNodePtr *temp;
3657
3658
1.89k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660
0
            return(-1);
3661
0
        }
3662
1.89k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663
1.89k
              sizeof(xmlNodePtr));
3664
1.89k
  if (temp == NULL) {
3665
1
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3666
1
      return(-1);
3667
1
  }
3668
1.89k
        cur->nodeMax *= 2;
3669
1.89k
  cur->nodeTab = temp;
3670
1.89k
    }
3671
311k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3672
311k
    if(nsNode == NULL)
3673
132
        return(-1);
3674
311k
    cur->nodeTab[cur->nodeNr++] = nsNode;
3675
311k
    return(0);
3676
311k
}
3677
3678
/**
3679
 * xmlXPathNodeSetAdd:
3680
 * @cur:  the initial node set
3681
 * @val:  a new xmlNodePtr
3682
 *
3683
 * add a new xmlNodePtr to an existing NodeSet
3684
 *
3685
 * Returns 0 in case of success, and -1 in case of error
3686
 */
3687
int
3688
26.0M
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3689
26.0M
    int i;
3690
3691
26.0M
    if ((cur == NULL) || (val == NULL)) return(-1);
3692
3693
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3694
    /*
3695
     * prevent duplicates
3696
     */
3697
30.7G
    for (i = 0;i < cur->nodeNr;i++)
3698
30.6G
        if (cur->nodeTab[i] == val) return(0);
3699
3700
    /*
3701
     * grow the nodeTab if needed
3702
     */
3703
25.4M
    if (cur->nodeMax == 0) {
3704
62.6k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705
62.6k
               sizeof(xmlNodePtr));
3706
62.6k
  if (cur->nodeTab == NULL) {
3707
1.50k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3708
1.50k
      return(-1);
3709
1.50k
  }
3710
61.1k
  memset(cur->nodeTab, 0 ,
3711
61.1k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712
61.1k
        cur->nodeMax = XML_NODESET_DEFAULT;
3713
25.3M
    } else if (cur->nodeNr == cur->nodeMax) {
3714
162k
        xmlNodePtr *temp;
3715
3716
162k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3717
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3718
0
            return(-1);
3719
0
        }
3720
162k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3721
162k
              sizeof(xmlNodePtr));
3722
162k
  if (temp == NULL) {
3723
3.73k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3724
3.73k
      return(-1);
3725
3.73k
  }
3726
158k
        cur->nodeMax *= 2;
3727
158k
  cur->nodeTab = temp;
3728
158k
    }
3729
25.4M
    if (val->type == XML_NAMESPACE_DECL) {
3730
1.17k
  xmlNsPtr ns = (xmlNsPtr) val;
3731
1.17k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3732
3733
1.17k
        if (nsNode == NULL)
3734
259
            return(-1);
3735
911
  cur->nodeTab[cur->nodeNr++] = nsNode;
3736
911
    } else
3737
25.4M
  cur->nodeTab[cur->nodeNr++] = val;
3738
25.4M
    return(0);
3739
25.4M
}
3740
3741
/**
3742
 * xmlXPathNodeSetAddUnique:
3743
 * @cur:  the initial node set
3744
 * @val:  a new xmlNodePtr
3745
 *
3746
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3747
 * when we are sure the node is not already in the set.
3748
 *
3749
 * Returns 0 in case of success and -1 in case of failure
3750
 */
3751
int
3752
19.0M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753
19.0M
    if ((cur == NULL) || (val == NULL)) return(-1);
3754
3755
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3756
    /*
3757
     * grow the nodeTab if needed
3758
     */
3759
19.0M
    if (cur->nodeMax == 0) {
3760
3.21M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761
3.21M
               sizeof(xmlNodePtr));
3762
3.21M
  if (cur->nodeTab == NULL) {
3763
12.0k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3764
12.0k
      return(-1);
3765
12.0k
  }
3766
3.20M
  memset(cur->nodeTab, 0 ,
3767
3.20M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768
3.20M
        cur->nodeMax = XML_NODESET_DEFAULT;
3769
15.8M
    } else if (cur->nodeNr == cur->nodeMax) {
3770
847k
        xmlNodePtr *temp;
3771
3772
847k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774
0
            return(-1);
3775
0
        }
3776
847k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777
847k
              sizeof(xmlNodePtr));
3778
847k
  if (temp == NULL) {
3779
864
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3780
864
      return(-1);
3781
864
  }
3782
846k
  cur->nodeTab = temp;
3783
846k
        cur->nodeMax *= 2;
3784
846k
    }
3785
19.0M
    if (val->type == XML_NAMESPACE_DECL) {
3786
118k
  xmlNsPtr ns = (xmlNsPtr) val;
3787
118k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788
3789
118k
        if (nsNode == NULL)
3790
916
            return(-1);
3791
117k
  cur->nodeTab[cur->nodeNr++] = nsNode;
3792
117k
    } else
3793
18.8M
  cur->nodeTab[cur->nodeNr++] = val;
3794
19.0M
    return(0);
3795
19.0M
}
3796
3797
/**
3798
 * xmlXPathNodeSetMerge:
3799
 * @val1:  the first NodeSet or NULL
3800
 * @val2:  the second NodeSet
3801
 *
3802
 * Merges two nodesets, all nodes from @val2 are added to @val1
3803
 * if @val1 is NULL, a new set is created and copied from @val2
3804
 *
3805
 * Returns @val1 once extended or NULL in case of error.
3806
 *
3807
 * Frees @val1 in case of error.
3808
 */
3809
xmlNodeSetPtr
3810
1.76M
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811
1.76M
    int i, j, initNr, skip;
3812
1.76M
    xmlNodePtr n1, n2;
3813
3814
1.76M
    if (val2 == NULL) return(val1);
3815
1.49M
    if (val1 == NULL) {
3816
273k
  val1 = xmlXPathNodeSetCreate(NULL);
3817
273k
        if (val1 == NULL)
3818
342
            return (NULL);
3819
273k
    }
3820
3821
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822
1.49M
    initNr = val1->nodeNr;
3823
3824
13.9M
    for (i = 0;i < val2->nodeNr;i++) {
3825
12.4M
  n2 = val2->nodeTab[i];
3826
  /*
3827
   * check against duplicates
3828
   */
3829
12.4M
  skip = 0;
3830
33.2M
  for (j = 0; j < initNr; j++) {
3831
21.6M
      n1 = val1->nodeTab[j];
3832
21.6M
      if (n1 == n2) {
3833
840k
    skip = 1;
3834
840k
    break;
3835
20.8M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836
20.8M
           (n2->type == XML_NAMESPACE_DECL)) {
3837
38.7k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3838
38.7k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3839
7.32k
      ((xmlNsPtr) n2)->prefix)))
3840
1.93k
    {
3841
1.93k
        skip = 1;
3842
1.93k
        break;
3843
1.93k
    }
3844
38.7k
      }
3845
21.6M
  }
3846
12.4M
  if (skip)
3847
842k
      continue;
3848
3849
  /*
3850
   * grow the nodeTab if needed
3851
   */
3852
11.5M
  if (val1->nodeMax == 0) {
3853
202k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854
202k
                sizeof(xmlNodePtr));
3855
202k
      if (val1->nodeTab == NULL) {
3856
390
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3857
390
    goto error;
3858
390
      }
3859
202k
      memset(val1->nodeTab, 0 ,
3860
202k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861
202k
      val1->nodeMax = XML_NODESET_DEFAULT;
3862
11.3M
  } else if (val1->nodeNr == val1->nodeMax) {
3863
280k
      xmlNodePtr *temp;
3864
3865
280k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867
0
                goto error;
3868
0
            }
3869
280k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870
280k
               sizeof(xmlNodePtr));
3871
280k
      if (temp == NULL) {
3872
83
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3873
83
    goto error;
3874
83
      }
3875
280k
      val1->nodeTab = temp;
3876
280k
      val1->nodeMax *= 2;
3877
280k
  }
3878
11.5M
  if (n2->type == XML_NAMESPACE_DECL) {
3879
68.6k
      xmlNsPtr ns = (xmlNsPtr) n2;
3880
68.6k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881
3882
68.6k
            if (nsNode == NULL)
3883
27
                goto error;
3884
68.6k
      val1->nodeTab[val1->nodeNr++] = nsNode;
3885
68.6k
  } else
3886
11.5M
      val1->nodeTab[val1->nodeNr++] = n2;
3887
11.5M
    }
3888
3889
1.49M
    return(val1);
3890
3891
500
error:
3892
500
    xmlXPathFreeNodeSet(val1);
3893
500
    return(NULL);
3894
1.49M
}
3895
3896
3897
/**
3898
 * xmlXPathNodeSetMergeAndClear:
3899
 * @set1:  the first NodeSet or NULL
3900
 * @set2:  the second NodeSet
3901
 *
3902
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3903
 * Checks for duplicate nodes. Clears set2.
3904
 *
3905
 * Returns @set1 once extended or NULL in case of error.
3906
 *
3907
 * Frees @set1 in case of error.
3908
 */
3909
static xmlNodeSetPtr
3910
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3911
116k
{
3912
116k
    {
3913
116k
  int i, j, initNbSet1;
3914
116k
  xmlNodePtr n1, n2;
3915
3916
116k
  initNbSet1 = set1->nodeNr;
3917
407k
  for (i = 0;i < set2->nodeNr;i++) {
3918
290k
      n2 = set2->nodeTab[i];
3919
      /*
3920
      * Skip duplicates.
3921
      */
3922
14.1M
      for (j = 0; j < initNbSet1; j++) {
3923
14.0M
    n1 = set1->nodeTab[j];
3924
14.0M
    if (n1 == n2) {
3925
205k
        goto skip_node;
3926
13.8M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3927
13.8M
        (n2->type == XML_NAMESPACE_DECL))
3928
1.87M
    {
3929
1.87M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930
1.87M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931
237k
      ((xmlNsPtr) n2)->prefix)))
3932
3
        {
3933
      /*
3934
      * Free the namespace node.
3935
      */
3936
3
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3937
3
      goto skip_node;
3938
3
        }
3939
1.87M
    }
3940
14.0M
      }
3941
      /*
3942
      * grow the nodeTab if needed
3943
      */
3944
85.3k
      if (set1->nodeMax == 0) {
3945
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3946
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3947
0
    if (set1->nodeTab == NULL) {
3948
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3949
0
        goto error;
3950
0
    }
3951
0
    memset(set1->nodeTab, 0,
3952
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3953
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3954
85.3k
      } else if (set1->nodeNr >= set1->nodeMax) {
3955
4.06k
    xmlNodePtr *temp;
3956
3957
4.06k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959
0
                    goto error;
3960
0
                }
3961
4.06k
    temp = (xmlNodePtr *) xmlRealloc(
3962
4.06k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963
4.06k
    if (temp == NULL) {
3964
20
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3965
20
        goto error;
3966
20
    }
3967
4.04k
    set1->nodeTab = temp;
3968
4.04k
    set1->nodeMax *= 2;
3969
4.04k
      }
3970
85.3k
      set1->nodeTab[set1->nodeNr++] = n2;
3971
290k
skip_node:
3972
290k
            set2->nodeTab[i] = NULL;
3973
290k
  }
3974
116k
    }
3975
116k
    set2->nodeNr = 0;
3976
116k
    return(set1);
3977
3978
20
error:
3979
20
    xmlXPathFreeNodeSet(set1);
3980
20
    xmlXPathNodeSetClear(set2, 1);
3981
20
    return(NULL);
3982
116k
}
3983
3984
/**
3985
 * xmlXPathNodeSetMergeAndClearNoDupls:
3986
 * @set1:  the first NodeSet or NULL
3987
 * @set2:  the second NodeSet
3988
 *
3989
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3990
 * Doesn't check for duplicate nodes. Clears set2.
3991
 *
3992
 * Returns @set1 once extended or NULL in case of error.
3993
 *
3994
 * Frees @set1 in case of error.
3995
 */
3996
static xmlNodeSetPtr
3997
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3998
245k
{
3999
245k
    {
4000
245k
  int i;
4001
245k
  xmlNodePtr n2;
4002
4003
916k
  for (i = 0;i < set2->nodeNr;i++) {
4004
671k
      n2 = set2->nodeTab[i];
4005
671k
      if (set1->nodeMax == 0) {
4006
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008
0
    if (set1->nodeTab == NULL) {
4009
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4010
0
        goto error;
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
671k
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
28.3k
    xmlNodePtr *temp;
4017
4018
28.3k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    goto error;
4021
0
                }
4022
28.3k
    temp = (xmlNodePtr *) xmlRealloc(
4023
28.3k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
28.3k
    if (temp == NULL) {
4025
42
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
42
        goto error;
4027
42
    }
4028
28.2k
    set1->nodeTab = temp;
4029
28.2k
    set1->nodeMax *= 2;
4030
28.2k
      }
4031
671k
      set1->nodeTab[set1->nodeNr++] = n2;
4032
671k
            set2->nodeTab[i] = NULL;
4033
671k
  }
4034
245k
    }
4035
245k
    set2->nodeNr = 0;
4036
245k
    return(set1);
4037
4038
42
error:
4039
42
    xmlXPathFreeNodeSet(set1);
4040
42
    xmlXPathNodeSetClear(set2, 1);
4041
42
    return(NULL);
4042
245k
}
4043
4044
/**
4045
 * xmlXPathNodeSetDel:
4046
 * @cur:  the initial node set
4047
 * @val:  an xmlNodePtr
4048
 *
4049
 * Removes an xmlNodePtr from an existing NodeSet
4050
 */
4051
void
4052
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4053
0
    int i;
4054
4055
0
    if (cur == NULL) return;
4056
0
    if (val == NULL) return;
4057
4058
    /*
4059
     * find node in nodeTab
4060
     */
4061
0
    for (i = 0;i < cur->nodeNr;i++)
4062
0
        if (cur->nodeTab[i] == val) break;
4063
4064
0
    if (i >= cur->nodeNr) { /* not found */
4065
#ifdef DEBUG
4066
        xmlGenericError(xmlGenericErrorContext,
4067
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4068
    val->name);
4069
#endif
4070
0
        return;
4071
0
    }
4072
0
    if ((cur->nodeTab[i] != NULL) &&
4073
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4075
0
    cur->nodeNr--;
4076
0
    for (;i < cur->nodeNr;i++)
4077
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4078
0
    cur->nodeTab[cur->nodeNr] = NULL;
4079
0
}
4080
4081
/**
4082
 * xmlXPathNodeSetRemove:
4083
 * @cur:  the initial node set
4084
 * @val:  the index to remove
4085
 *
4086
 * Removes an entry from an existing NodeSet list.
4087
 */
4088
void
4089
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4090
0
    if (cur == NULL) return;
4091
0
    if (val >= cur->nodeNr) return;
4092
0
    if ((cur->nodeTab[val] != NULL) &&
4093
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4094
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4095
0
    cur->nodeNr--;
4096
0
    for (;val < cur->nodeNr;val++)
4097
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4098
0
    cur->nodeTab[cur->nodeNr] = NULL;
4099
0
}
4100
4101
/**
4102
 * xmlXPathFreeNodeSet:
4103
 * @obj:  the xmlNodeSetPtr to free
4104
 *
4105
 * Free the NodeSet compound (not the actual nodes !).
4106
 */
4107
void
4108
7.93M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109
7.93M
    if (obj == NULL) return;
4110
7.91M
    if (obj->nodeTab != NULL) {
4111
4.22M
  int i;
4112
4113
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114
50.5M
  for (i = 0;i < obj->nodeNr;i++)
4115
46.3M
      if ((obj->nodeTab[i] != NULL) &&
4116
46.3M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117
388k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118
4.22M
  xmlFree(obj->nodeTab);
4119
4.22M
    }
4120
7.91M
    xmlFree(obj);
4121
7.91M
}
4122
4123
/**
4124
 * xmlXPathNodeSetClearFromPos:
4125
 * @set: the node set to be cleared
4126
 * @pos: the start position to clear from
4127
 *
4128
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4129
 * are feed) starting with the entry at @pos, but does *not* free the list
4130
 * itself. Sets the length of the list to @pos.
4131
 */
4132
static void
4133
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4134
13.1k
{
4135
13.1k
    if ((set == NULL) || (pos >= set->nodeNr))
4136
0
  return;
4137
13.1k
    else if ((hasNsNodes)) {
4138
12.7k
  int i;
4139
12.7k
  xmlNodePtr node;
4140
4141
56.4k
  for (i = pos; i < set->nodeNr; i++) {
4142
43.7k
      node = set->nodeTab[i];
4143
43.7k
      if ((node != NULL) &&
4144
43.7k
    (node->type == XML_NAMESPACE_DECL))
4145
25.5k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146
43.7k
  }
4147
12.7k
    }
4148
13.1k
    set->nodeNr = pos;
4149
13.1k
}
4150
4151
/**
4152
 * xmlXPathNodeSetClear:
4153
 * @set:  the node set to clear
4154
 *
4155
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4156
 * are feed), but does *not* free the list itself. Sets the length of the
4157
 * list to 0.
4158
 */
4159
static void
4160
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4161
6.84k
{
4162
6.84k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4163
6.84k
}
4164
4165
/**
4166
 * xmlXPathNodeSetKeepLast:
4167
 * @set: the node set to be cleared
4168
 *
4169
 * Move the last node to the first position and clear temporary XPath objects
4170
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4171
 * to 1.
4172
 */
4173
static void
4174
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4175
12.4k
{
4176
12.4k
    int i;
4177
12.4k
    xmlNodePtr node;
4178
4179
12.4k
    if ((set == NULL) || (set->nodeNr <= 1))
4180
0
  return;
4181
36.9k
    for (i = 0; i < set->nodeNr - 1; i++) {
4182
24.5k
        node = set->nodeTab[i];
4183
24.5k
        if ((node != NULL) &&
4184
24.5k
            (node->type == XML_NAMESPACE_DECL))
4185
187
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
24.5k
    }
4187
12.4k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188
12.4k
    set->nodeNr = 1;
4189
12.4k
}
4190
4191
/**
4192
 * xmlXPathFreeValueTree:
4193
 * @obj:  the xmlNodeSetPtr to free
4194
 *
4195
 * Free the NodeSet compound and the actual tree, this is different
4196
 * from xmlXPathFreeNodeSet()
4197
 */
4198
static void
4199
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4200
0
    int i;
4201
4202
0
    if (obj == NULL) return;
4203
4204
0
    if (obj->nodeTab != NULL) {
4205
0
  for (i = 0;i < obj->nodeNr;i++) {
4206
0
      if (obj->nodeTab[i] != NULL) {
4207
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4208
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4209
0
    } else {
4210
0
        xmlFreeNodeList(obj->nodeTab[i]);
4211
0
    }
4212
0
      }
4213
0
  }
4214
0
  xmlFree(obj->nodeTab);
4215
0
    }
4216
0
    xmlFree(obj);
4217
0
}
4218
4219
#if defined(DEBUG) || defined(DEBUG_STEP)
4220
/**
4221
 * xmlGenericErrorContextNodeSet:
4222
 * @output:  a FILE * for the output
4223
 * @obj:  the xmlNodeSetPtr to display
4224
 *
4225
 * Quick display of a NodeSet
4226
 */
4227
void
4228
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4229
    int i;
4230
4231
    if (output == NULL) output = xmlGenericErrorContext;
4232
    if (obj == NULL)  {
4233
        fprintf(output, "NodeSet == NULL !\n");
4234
  return;
4235
    }
4236
    if (obj->nodeNr == 0) {
4237
        fprintf(output, "NodeSet is empty\n");
4238
  return;
4239
    }
4240
    if (obj->nodeTab == NULL) {
4241
  fprintf(output, " nodeTab == NULL !\n");
4242
  return;
4243
    }
4244
    for (i = 0; i < obj->nodeNr; i++) {
4245
        if (obj->nodeTab[i] == NULL) {
4246
      fprintf(output, " NULL !\n");
4247
      return;
4248
        }
4249
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4250
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4251
      fprintf(output, " /");
4252
  else if (obj->nodeTab[i]->name == NULL)
4253
      fprintf(output, " noname!");
4254
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4255
    }
4256
    fprintf(output, "\n");
4257
}
4258
#endif
4259
4260
/**
4261
 * xmlXPathNewNodeSet:
4262
 * @val:  the NodePtr value
4263
 *
4264
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4265
 * it with the single Node @val
4266
 *
4267
 * Returns the newly created object.
4268
 */
4269
xmlXPathObjectPtr
4270
3.61M
xmlXPathNewNodeSet(xmlNodePtr val) {
4271
3.61M
    xmlXPathObjectPtr ret;
4272
4273
3.61M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274
3.61M
    if (ret == NULL) {
4275
2.17k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4276
2.17k
  return(NULL);
4277
2.17k
    }
4278
3.61M
    memset(ret, 0 , sizeof(xmlXPathObject));
4279
3.61M
    ret->type = XPATH_NODESET;
4280
3.61M
    ret->boolval = 0;
4281
    /* TODO: Check memory error. */
4282
3.61M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4283
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4284
#ifdef XP_DEBUG_OBJ_USAGE
4285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4286
#endif
4287
3.61M
    return(ret);
4288
3.61M
}
4289
4290
/**
4291
 * xmlXPathNewValueTree:
4292
 * @val:  the NodePtr value
4293
 *
4294
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4295
 * it with the tree root @val
4296
 *
4297
 * Returns the newly created object.
4298
 */
4299
xmlXPathObjectPtr
4300
22.8k
xmlXPathNewValueTree(xmlNodePtr val) {
4301
22.8k
    xmlXPathObjectPtr ret;
4302
4303
22.8k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304
22.8k
    if (ret == NULL) {
4305
1.76k
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4306
1.76k
  return(NULL);
4307
1.76k
    }
4308
21.0k
    memset(ret, 0 , sizeof(xmlXPathObject));
4309
21.0k
    ret->type = XPATH_XSLT_TREE;
4310
21.0k
    ret->boolval = 1;
4311
21.0k
    ret->user = (void *) val;
4312
21.0k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4313
#ifdef XP_DEBUG_OBJ_USAGE
4314
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4315
#endif
4316
21.0k
    return(ret);
4317
22.8k
}
4318
4319
/**
4320
 * xmlXPathNewNodeSetList:
4321
 * @val:  an existing NodeSet
4322
 *
4323
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4324
 * it with the Nodeset @val
4325
 *
4326
 * Returns the newly created object.
4327
 */
4328
xmlXPathObjectPtr
4329
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4330
0
{
4331
0
    xmlXPathObjectPtr ret;
4332
0
    int i;
4333
4334
0
    if (val == NULL)
4335
0
        ret = NULL;
4336
0
    else if (val->nodeTab == NULL)
4337
0
        ret = xmlXPathNewNodeSet(NULL);
4338
0
    else {
4339
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4340
0
        if (ret) {
4341
0
            for (i = 1; i < val->nodeNr; ++i) {
4342
                /* TODO: Propagate memory error. */
4343
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4344
0
        < 0) break;
4345
0
      }
4346
0
  }
4347
0
    }
4348
4349
0
    return (ret);
4350
0
}
4351
4352
/**
4353
 * xmlXPathWrapNodeSet:
4354
 * @val:  the NodePtr value
4355
 *
4356
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4357
 *
4358
 * Returns the newly created object.
4359
 *
4360
 * In case of error the node set is destroyed and NULL is returned.
4361
 */
4362
xmlXPathObjectPtr
4363
2.01M
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364
2.01M
    xmlXPathObjectPtr ret;
4365
4366
2.01M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367
2.01M
    if (ret == NULL) {
4368
5.85k
        xmlXPathErrMemory(NULL, "creating node set object\n");
4369
5.85k
        xmlXPathFreeNodeSet(val);
4370
5.85k
  return(NULL);
4371
5.85k
    }
4372
2.01M
    memset(ret, 0 , sizeof(xmlXPathObject));
4373
2.01M
    ret->type = XPATH_NODESET;
4374
2.01M
    ret->nodesetval = val;
4375
#ifdef XP_DEBUG_OBJ_USAGE
4376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377
#endif
4378
2.01M
    return(ret);
4379
2.01M
}
4380
4381
/**
4382
 * xmlXPathFreeNodeSetList:
4383
 * @obj:  an existing NodeSetList object
4384
 *
4385
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4386
 * the list contrary to xmlXPathFreeObject().
4387
 */
4388
void
4389
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4390
0
    if (obj == NULL) return;
4391
#ifdef XP_DEBUG_OBJ_USAGE
4392
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4393
#endif
4394
0
    xmlFree(obj);
4395
0
}
4396
4397
/**
4398
 * xmlXPathDifference:
4399
 * @nodes1:  a node-set
4400
 * @nodes2:  a node-set
4401
 *
4402
 * Implements the EXSLT - Sets difference() function:
4403
 *    node-set set:difference (node-set, node-set)
4404
 *
4405
 * Returns the difference between the two node sets, or nodes1 if
4406
 *         nodes2 is empty
4407
 */
4408
xmlNodeSetPtr
4409
673
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4410
673
    xmlNodeSetPtr ret;
4411
673
    int i, l1;
4412
673
    xmlNodePtr cur;
4413
4414
673
    if (xmlXPathNodeSetIsEmpty(nodes2))
4415
249
  return(nodes1);
4416
4417
    /* TODO: Check memory error. */
4418
424
    ret = xmlXPathNodeSetCreate(NULL);
4419
424
    if (xmlXPathNodeSetIsEmpty(nodes1))
4420
125
  return(ret);
4421
4422
299
    l1 = xmlXPathNodeSetGetLength(nodes1);
4423
4424
16.7k
    for (i = 0; i < l1; i++) {
4425
16.4k
  cur = xmlXPathNodeSetItem(nodes1, i);
4426
16.4k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4427
            /* TODO: Propagate memory error. */
4428
8.07k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4429
5
          break;
4430
8.07k
  }
4431
16.4k
    }
4432
299
    return(ret);
4433
424
}
4434
4435
/**
4436
 * xmlXPathIntersection:
4437
 * @nodes1:  a node-set
4438
 * @nodes2:  a node-set
4439
 *
4440
 * Implements the EXSLT - Sets intersection() function:
4441
 *    node-set set:intersection (node-set, node-set)
4442
 *
4443
 * Returns a node set comprising the nodes that are within both the
4444
 *         node sets passed as arguments
4445
 */
4446
xmlNodeSetPtr
4447
415
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4448
415
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4449
415
    int i, l1;
4450
415
    xmlNodePtr cur;
4451
4452
415
    if (ret == NULL)
4453
1
        return(ret);
4454
414
    if (xmlXPathNodeSetIsEmpty(nodes1))
4455
132
  return(ret);
4456
282
    if (xmlXPathNodeSetIsEmpty(nodes2))
4457
150
  return(ret);
4458
4459
132
    l1 = xmlXPathNodeSetGetLength(nodes1);
4460
4461
1.45k
    for (i = 0; i < l1; i++) {
4462
1.32k
  cur = xmlXPathNodeSetItem(nodes1, i);
4463
1.32k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4464
            /* TODO: Propagate memory error. */
4465
557
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4466
1
          break;
4467
557
  }
4468
1.32k
    }
4469
132
    return(ret);
4470
282
}
4471
4472
/**
4473
 * xmlXPathDistinctSorted:
4474
 * @nodes:  a node-set, sorted by document order
4475
 *
4476
 * Implements the EXSLT - Sets distinct() function:
4477
 *    node-set set:distinct (node-set)
4478
 *
4479
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4480
 *         it is empty
4481
 */
4482
xmlNodeSetPtr
4483
133
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4484
133
    xmlNodeSetPtr ret;
4485
133
    xmlHashTablePtr hash;
4486
133
    int i, l;
4487
133
    xmlChar * strval;
4488
133
    xmlNodePtr cur;
4489
4490
133
    if (xmlXPathNodeSetIsEmpty(nodes))
4491
38
  return(nodes);
4492
4493
95
    ret = xmlXPathNodeSetCreate(NULL);
4494
95
    if (ret == NULL)
4495
1
        return(ret);
4496
94
    l = xmlXPathNodeSetGetLength(nodes);
4497
94
    hash = xmlHashCreate (l);
4498
974
    for (i = 0; i < l; i++) {
4499
889
  cur = xmlXPathNodeSetItem(nodes, i);
4500
889
  strval = xmlXPathCastNodeToString(cur);
4501
889
  if (xmlHashLookup(hash, strval) == NULL) {
4502
254
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
4503
8
                xmlFree(strval);
4504
8
                goto error;
4505
8
            }
4506
246
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4507
1
          goto error;
4508
635
  } else {
4509
635
      xmlFree(strval);
4510
635
  }
4511
889
    }
4512
85
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4513
85
    return(ret);
4514
4515
9
error:
4516
9
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4517
9
    xmlXPathFreeNodeSet(ret);
4518
9
    return(NULL);
4519
94
}
4520
4521
/**
4522
 * xmlXPathDistinct:
4523
 * @nodes:  a node-set
4524
 *
4525
 * Implements the EXSLT - Sets distinct() function:
4526
 *    node-set set:distinct (node-set)
4527
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4528
 * is called with the sorted node-set
4529
 *
4530
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4531
 *         it is empty
4532
 */
4533
xmlNodeSetPtr
4534
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4535
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
0
  return(nodes);
4537
4538
0
    xmlXPathNodeSetSort(nodes);
4539
0
    return(xmlXPathDistinctSorted(nodes));
4540
0
}
4541
4542
/**
4543
 * xmlXPathHasSameNodes:
4544
 * @nodes1:  a node-set
4545
 * @nodes2:  a node-set
4546
 *
4547
 * Implements the EXSLT - Sets has-same-nodes function:
4548
 *    boolean set:has-same-node(node-set, node-set)
4549
 *
4550
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4551
 *         otherwise
4552
 */
4553
int
4554
1.60k
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4555
1.60k
    int i, l;
4556
1.60k
    xmlNodePtr cur;
4557
4558
1.60k
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4559
1.60k
  xmlXPathNodeSetIsEmpty(nodes2))
4560
1.31k
  return(0);
4561
4562
294
    l = xmlXPathNodeSetGetLength(nodes1);
4563
1.52k
    for (i = 0; i < l; i++) {
4564
1.40k
  cur = xmlXPathNodeSetItem(nodes1, i);
4565
1.40k
  if (xmlXPathNodeSetContains(nodes2, cur))
4566
169
      return(1);
4567
1.40k
    }
4568
125
    return(0);
4569
294
}
4570
4571
/**
4572
 * xmlXPathNodeLeadingSorted:
4573
 * @nodes: a node-set, sorted by document order
4574
 * @node: a node
4575
 *
4576
 * Implements the EXSLT - Sets leading() function:
4577
 *    node-set set:leading (node-set, node-set)
4578
 *
4579
 * Returns the nodes in @nodes that precede @node in document order,
4580
 *         @nodes if @node is NULL or an empty node-set if @nodes
4581
 *         doesn't contain @node
4582
 */
4583
xmlNodeSetPtr
4584
399
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4585
399
    int i, l;
4586
399
    xmlNodePtr cur;
4587
399
    xmlNodeSetPtr ret;
4588
4589
399
    if (node == NULL)
4590
0
  return(nodes);
4591
4592
399
    ret = xmlXPathNodeSetCreate(NULL);
4593
399
    if (ret == NULL)
4594
2
        return(ret);
4595
397
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4596
397
  (!xmlXPathNodeSetContains(nodes, node)))
4597
320
  return(ret);
4598
4599
77
    l = xmlXPathNodeSetGetLength(nodes);
4600
482
    for (i = 0; i < l; i++) {
4601
439
  cur = xmlXPathNodeSetItem(nodes, i);
4602
439
  if (cur == node)
4603
33
      break;
4604
        /* TODO: Propagate memory error. */
4605
406
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4606
1
      break;
4607
406
    }
4608
77
    return(ret);
4609
397
}
4610
4611
/**
4612
 * xmlXPathNodeLeading:
4613
 * @nodes:  a node-set
4614
 * @node:  a node
4615
 *
4616
 * Implements the EXSLT - Sets leading() function:
4617
 *    node-set set:leading (node-set, node-set)
4618
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4619
 * is called.
4620
 *
4621
 * Returns the nodes in @nodes that precede @node in document order,
4622
 *         @nodes if @node is NULL or an empty node-set if @nodes
4623
 *         doesn't contain @node
4624
 */
4625
xmlNodeSetPtr
4626
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627
0
    xmlXPathNodeSetSort(nodes);
4628
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4629
0
}
4630
4631
/**
4632
 * xmlXPathLeadingSorted:
4633
 * @nodes1:  a node-set, sorted by document order
4634
 * @nodes2:  a node-set, sorted by document order
4635
 *
4636
 * Implements the EXSLT - Sets leading() function:
4637
 *    node-set set:leading (node-set, node-set)
4638
 *
4639
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4640
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4642
 */
4643
xmlNodeSetPtr
4644
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4646
0
  return(nodes1);
4647
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4648
0
             xmlXPathNodeSetItem(nodes2, 1)));
4649
0
}
4650
4651
/**
4652
 * xmlXPathLeading:
4653
 * @nodes1:  a node-set
4654
 * @nodes2:  a node-set
4655
 *
4656
 * Implements the EXSLT - Sets leading() function:
4657
 *    node-set set:leading (node-set, node-set)
4658
 * @nodes1 and @nodes2 are sorted by document order, then
4659
 * #exslSetsLeadingSorted is called.
4660
 *
4661
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4662
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4664
 */
4665
xmlNodeSetPtr
4666
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4668
0
  return(nodes1);
4669
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4670
0
  return(xmlXPathNodeSetCreate(NULL));
4671
0
    xmlXPathNodeSetSort(nodes1);
4672
0
    xmlXPathNodeSetSort(nodes2);
4673
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4674
0
             xmlXPathNodeSetItem(nodes2, 1)));
4675
0
}
4676
4677
/**
4678
 * xmlXPathNodeTrailingSorted:
4679
 * @nodes: a node-set, sorted by document order
4680
 * @node: a node
4681
 *
4682
 * Implements the EXSLT - Sets trailing() function:
4683
 *    node-set set:trailing (node-set, node-set)
4684
 *
4685
 * Returns the nodes in @nodes that follow @node in document order,
4686
 *         @nodes if @node is NULL or an empty node-set if @nodes
4687
 *         doesn't contain @node
4688
 */
4689
xmlNodeSetPtr
4690
497
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4691
497
    int i, l;
4692
497
    xmlNodePtr cur;
4693
497
    xmlNodeSetPtr ret;
4694
4695
497
    if (node == NULL)
4696
0
  return(nodes);
4697
4698
497
    ret = xmlXPathNodeSetCreate(NULL);
4699
497
    if (ret == NULL)
4700
1
        return(ret);
4701
496
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4702
496
  (!xmlXPathNodeSetContains(nodes, node)))
4703
330
  return(ret);
4704
4705
166
    l = xmlXPathNodeSetGetLength(nodes);
4706
2.19k
    for (i = l - 1; i >= 0; i--) {
4707
2.19k
  cur = xmlXPathNodeSetItem(nodes, i);
4708
2.19k
  if (cur == node)
4709
165
      break;
4710
        /* TODO: Propagate memory error. */
4711
2.02k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4712
1
      break;
4713
2.02k
    }
4714
166
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4715
166
    return(ret);
4716
496
}
4717
4718
/**
4719
 * xmlXPathNodeTrailing:
4720
 * @nodes:  a node-set
4721
 * @node:  a node
4722
 *
4723
 * Implements the EXSLT - Sets trailing() function:
4724
 *    node-set set:trailing (node-set, node-set)
4725
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4726
 * is called.
4727
 *
4728
 * Returns the nodes in @nodes that follow @node in document order,
4729
 *         @nodes if @node is NULL or an empty node-set if @nodes
4730
 *         doesn't contain @node
4731
 */
4732
xmlNodeSetPtr
4733
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4734
0
    xmlXPathNodeSetSort(nodes);
4735
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4736
0
}
4737
4738
/**
4739
 * xmlXPathTrailingSorted:
4740
 * @nodes1:  a node-set, sorted by document order
4741
 * @nodes2:  a node-set, sorted by document order
4742
 *
4743
 * Implements the EXSLT - Sets trailing() function:
4744
 *    node-set set:trailing (node-set, node-set)
4745
 *
4746
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4747
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4748
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4749
 */
4750
xmlNodeSetPtr
4751
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4752
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4753
0
  return(nodes1);
4754
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4755
0
              xmlXPathNodeSetItem(nodes2, 0)));
4756
0
}
4757
4758
/**
4759
 * xmlXPathTrailing:
4760
 * @nodes1:  a node-set
4761
 * @nodes2:  a node-set
4762
 *
4763
 * Implements the EXSLT - Sets trailing() function:
4764
 *    node-set set:trailing (node-set, node-set)
4765
 * @nodes1 and @nodes2 are sorted by document order, then
4766
 * #xmlXPathTrailingSorted is called.
4767
 *
4768
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4769
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4770
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4771
 */
4772
xmlNodeSetPtr
4773
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4774
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4775
0
  return(nodes1);
4776
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4777
0
  return(xmlXPathNodeSetCreate(NULL));
4778
0
    xmlXPathNodeSetSort(nodes1);
4779
0
    xmlXPathNodeSetSort(nodes2);
4780
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4781
0
              xmlXPathNodeSetItem(nodes2, 0)));
4782
0
}
4783
4784
/************************************************************************
4785
 *                  *
4786
 *    Routines to handle extra functions      *
4787
 *                  *
4788
 ************************************************************************/
4789
4790
/**
4791
 * xmlXPathRegisterFunc:
4792
 * @ctxt:  the XPath context
4793
 * @name:  the function name
4794
 * @f:  the function implementation or NULL
4795
 *
4796
 * Register a new function. If @f is NULL it unregisters the function
4797
 *
4798
 * Returns 0 in case of success, -1 in case of error
4799
 */
4800
int
4801
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4802
1.73M
         xmlXPathFunction f) {
4803
1.73M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4804
1.73M
}
4805
4806
/**
4807
 * xmlXPathRegisterFuncNS:
4808
 * @ctxt:  the XPath context
4809
 * @name:  the function name
4810
 * @ns_uri:  the function namespace URI
4811
 * @f:  the function implementation or NULL
4812
 *
4813
 * Register a new function. If @f is NULL it unregisters the function
4814
 *
4815
 * Returns 0 in case of success, -1 in case of error
4816
 */
4817
int
4818
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4819
1.79M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4820
1.79M
    if (ctxt == NULL)
4821
0
  return(-1);
4822
1.79M
    if (name == NULL)
4823
0
  return(-1);
4824
4825
1.79M
    if (ctxt->funcHash == NULL)
4826
196
  ctxt->funcHash = xmlHashCreate(0);
4827
1.79M
    if (ctxt->funcHash == NULL)
4828
196
  return(-1);
4829
1.79M
    if (f == NULL)
4830
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831
1.79M
XML_IGNORE_FPTR_CAST_WARNINGS
4832
1.79M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833
1.79M
XML_POP_WARNINGS
4834
1.79M
}
4835
4836
/**
4837
 * xmlXPathRegisterFuncLookup:
4838
 * @ctxt:  the XPath context
4839
 * @f:  the lookup function
4840
 * @funcCtxt:  the lookup data
4841
 *
4842
 * Registers an external mechanism to do function lookup.
4843
 */
4844
void
4845
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4846
          xmlXPathFuncLookupFunc f,
4847
14.1k
          void *funcCtxt) {
4848
14.1k
    if (ctxt == NULL)
4849
0
  return;
4850
14.1k
    ctxt->funcLookupFunc = f;
4851
14.1k
    ctxt->funcLookupData = funcCtxt;
4852
14.1k
}
4853
4854
/**
4855
 * xmlXPathFunctionLookup:
4856
 * @ctxt:  the XPath context
4857
 * @name:  the function name
4858
 *
4859
 * Search in the Function array of the context for the given
4860
 * function.
4861
 *
4862
 * Returns the xmlXPathFunction or NULL if not found
4863
 */
4864
xmlXPathFunction
4865
56.5k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4866
56.5k
    if (ctxt == NULL)
4867
0
  return (NULL);
4868
4869
56.5k
    if (ctxt->funcLookupFunc != NULL) {
4870
56.5k
  xmlXPathFunction ret;
4871
56.5k
  xmlXPathFuncLookupFunc f;
4872
4873
56.5k
  f = ctxt->funcLookupFunc;
4874
56.5k
  ret = f(ctxt->funcLookupData, name, NULL);
4875
56.5k
  if (ret != NULL)
4876
0
      return(ret);
4877
56.5k
    }
4878
56.5k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4879
56.5k
}
4880
4881
/**
4882
 * xmlXPathFunctionLookupNS:
4883
 * @ctxt:  the XPath context
4884
 * @name:  the function name
4885
 * @ns_uri:  the function namespace URI
4886
 *
4887
 * Search in the Function array of the context for the given
4888
 * function.
4889
 *
4890
 * Returns the xmlXPathFunction or NULL if not found
4891
 */
4892
xmlXPathFunction
4893
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4894
522k
       const xmlChar *ns_uri) {
4895
522k
    xmlXPathFunction ret;
4896
4897
522k
    if (ctxt == NULL)
4898
0
  return(NULL);
4899
522k
    if (name == NULL)
4900
0
  return(NULL);
4901
4902
522k
    if (ctxt->funcLookupFunc != NULL) {
4903
522k
  xmlXPathFuncLookupFunc f;
4904
4905
522k
  f = ctxt->funcLookupFunc;
4906
522k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4907
522k
  if (ret != NULL)
4908
449k
      return(ret);
4909
522k
    }
4910
4911
72.6k
    if (ctxt->funcHash == NULL)
4912
0
  return(NULL);
4913
4914
72.6k
XML_IGNORE_FPTR_CAST_WARNINGS
4915
72.6k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4916
72.6k
XML_POP_WARNINGS
4917
72.6k
    return(ret);
4918
72.6k
}
4919
4920
/**
4921
 * xmlXPathRegisteredFuncsCleanup:
4922
 * @ctxt:  the XPath context
4923
 *
4924
 * Cleanup the XPath context data associated to registered functions
4925
 */
4926
void
4927
59.6k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928
59.6k
    if (ctxt == NULL)
4929
0
  return;
4930
4931
59.6k
    xmlHashFree(ctxt->funcHash, NULL);
4932
59.6k
    ctxt->funcHash = NULL;
4933
59.6k
}
4934
4935
/************************************************************************
4936
 *                  *
4937
 *      Routines to handle Variables      *
4938
 *                  *
4939
 ************************************************************************/
4940
4941
/**
4942
 * xmlXPathRegisterVariable:
4943
 * @ctxt:  the XPath context
4944
 * @name:  the variable name
4945
 * @value:  the variable value or NULL
4946
 *
4947
 * Register a new variable value. If @value is NULL it unregisters
4948
 * the variable
4949
 *
4950
 * Returns 0 in case of success, -1 in case of error
4951
 */
4952
int
4953
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4954
0
       xmlXPathObjectPtr value) {
4955
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956
0
}
4957
4958
/**
4959
 * xmlXPathRegisterVariableNS:
4960
 * @ctxt:  the XPath context
4961
 * @name:  the variable name
4962
 * @ns_uri:  the variable namespace URI
4963
 * @value:  the variable value or NULL
4964
 *
4965
 * Register a new variable value. If @value is NULL it unregisters
4966
 * the variable
4967
 *
4968
 * Returns 0 in case of success, -1 in case of error
4969
 */
4970
int
4971
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972
         const xmlChar *ns_uri,
4973
0
         xmlXPathObjectPtr value) {
4974
0
    if (ctxt == NULL)
4975
0
  return(-1);
4976
0
    if (name == NULL)
4977
0
  return(-1);
4978
4979
0
    if (ctxt->varHash == NULL)
4980
0
  ctxt->varHash = xmlHashCreate(0);
4981
0
    if (ctxt->varHash == NULL)
4982
0
  return(-1);
4983
0
    if (value == NULL)
4984
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985
0
                             xmlXPathFreeObjectEntry));
4986
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987
0
             (void *) value, xmlXPathFreeObjectEntry));
4988
0
}
4989
4990
/**
4991
 * xmlXPathRegisterVariableLookup:
4992
 * @ctxt:  the XPath context
4993
 * @f:  the lookup function
4994
 * @data:  the lookup data
4995
 *
4996
 * register an external mechanism to do variable lookup
4997
 */
4998
void
4999
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5000
14.1k
   xmlXPathVariableLookupFunc f, void *data) {
5001
14.1k
    if (ctxt == NULL)
5002
0
  return;
5003
14.1k
    ctxt->varLookupFunc = f;
5004
14.1k
    ctxt->varLookupData = data;
5005
14.1k
}
5006
5007
/**
5008
 * xmlXPathVariableLookup:
5009
 * @ctxt:  the XPath context
5010
 * @name:  the variable name
5011
 *
5012
 * Search in the Variable array of the context for the given
5013
 * variable value.
5014
 *
5015
 * Returns a copy of the value or NULL if not found
5016
 */
5017
xmlXPathObjectPtr
5018
84.7k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5019
84.7k
    if (ctxt == NULL)
5020
0
  return(NULL);
5021
5022
84.7k
    if (ctxt->varLookupFunc != NULL) {
5023
84.7k
  xmlXPathObjectPtr ret;
5024
5025
84.7k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5026
84.7k
          (ctxt->varLookupData, name, NULL);
5027
84.7k
  return(ret);
5028
84.7k
    }
5029
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5030
84.7k
}
5031
5032
/**
5033
 * xmlXPathVariableLookupNS:
5034
 * @ctxt:  the XPath context
5035
 * @name:  the variable name
5036
 * @ns_uri:  the variable namespace URI
5037
 *
5038
 * Search in the Variable array of the context for the given
5039
 * variable value.
5040
 *
5041
 * Returns the a copy of the value or NULL if not found
5042
 */
5043
xmlXPathObjectPtr
5044
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5045
356
       const xmlChar *ns_uri) {
5046
356
    if (ctxt == NULL)
5047
0
  return(NULL);
5048
5049
356
    if (ctxt->varLookupFunc != NULL) {
5050
356
  xmlXPathObjectPtr ret;
5051
5052
356
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5053
356
          (ctxt->varLookupData, name, ns_uri);
5054
356
  if (ret != NULL) return(ret);
5055
356
    }
5056
5057
356
    if (ctxt->varHash == NULL)
5058
356
  return(NULL);
5059
0
    if (name == NULL)
5060
0
  return(NULL);
5061
5062
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5063
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5064
0
}
5065
5066
/**
5067
 * xmlXPathRegisteredVariablesCleanup:
5068
 * @ctxt:  the XPath context
5069
 *
5070
 * Cleanup the XPath context data associated to registered variables
5071
 */
5072
void
5073
59.6k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074
59.6k
    if (ctxt == NULL)
5075
0
  return;
5076
5077
59.6k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078
59.6k
    ctxt->varHash = NULL;
5079
59.6k
}
5080
5081
/**
5082
 * xmlXPathRegisterNs:
5083
 * @ctxt:  the XPath context
5084
 * @prefix:  the namespace prefix cannot be NULL or empty string
5085
 * @ns_uri:  the namespace name
5086
 *
5087
 * Register a new namespace. If @ns_uri is NULL it unregisters
5088
 * the namespace
5089
 *
5090
 * Returns 0 in case of success, -1 in case of error
5091
 */
5092
int
5093
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5094
0
         const xmlChar *ns_uri) {
5095
0
    xmlChar *copy;
5096
5097
0
    if (ctxt == NULL)
5098
0
  return(-1);
5099
0
    if (prefix == NULL)
5100
0
  return(-1);
5101
0
    if (prefix[0] == 0)
5102
0
  return(-1);
5103
5104
0
    if (ctxt->nsHash == NULL)
5105
0
  ctxt->nsHash = xmlHashCreate(10);
5106
0
    if (ctxt->nsHash == NULL)
5107
0
  return(-1);
5108
0
    if (ns_uri == NULL)
5109
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110
0
                            xmlHashDefaultDeallocator));
5111
5112
0
    copy = xmlStrdup(ns_uri);
5113
0
    if (copy == NULL)
5114
0
        return(-1);
5115
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116
0
                           xmlHashDefaultDeallocator) < 0) {
5117
0
        xmlFree(copy);
5118
0
        return(-1);
5119
0
    }
5120
5121
0
    return(0);
5122
0
}
5123
5124
/**
5125
 * xmlXPathNsLookup:
5126
 * @ctxt:  the XPath context
5127
 * @prefix:  the namespace prefix value
5128
 *
5129
 * Search in the namespace declaration array of the context for the given
5130
 * namespace name associated to the given prefix
5131
 *
5132
 * Returns the value or NULL if not found
5133
 */
5134
const xmlChar *
5135
681k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136
681k
    if (ctxt == NULL)
5137
0
  return(NULL);
5138
681k
    if (prefix == NULL)
5139
0
  return(NULL);
5140
5141
681k
#ifdef XML_XML_NAMESPACE
5142
681k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143
8.61k
  return(XML_XML_NAMESPACE);
5144
673k
#endif
5145
5146
673k
    if (ctxt->namespaces != NULL) {
5147
673k
  int i;
5148
5149
4.69M
  for (i = 0;i < ctxt->nsNr;i++) {
5150
4.57M
      if ((ctxt->namespaces[i] != NULL) &&
5151
4.57M
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5152
553k
    return(ctxt->namespaces[i]->href);
5153
4.57M
  }
5154
673k
    }
5155
5156
120k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157
673k
}
5158
5159
/**
5160
 * xmlXPathRegisteredNsCleanup:
5161
 * @ctxt:  the XPath context
5162
 *
5163
 * Cleanup the XPath context data associated to registered variables
5164
 */
5165
void
5166
59.6k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167
59.6k
    if (ctxt == NULL)
5168
0
  return;
5169
5170
59.6k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171
59.6k
    ctxt->nsHash = NULL;
5172
59.6k
}
5173
5174
/************************************************************************
5175
 *                  *
5176
 *      Routines to handle Values     *
5177
 *                  *
5178
 ************************************************************************/
5179
5180
/* Allocations are terrible, one needs to optimize all this !!! */
5181
5182
/**
5183
 * xmlXPathNewFloat:
5184
 * @val:  the double value
5185
 *
5186
 * Create a new xmlXPathObjectPtr of type double and of value @val
5187
 *
5188
 * Returns the newly created object.
5189
 */
5190
xmlXPathObjectPtr
5191
967k
xmlXPathNewFloat(double val) {
5192
967k
    xmlXPathObjectPtr ret;
5193
5194
967k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195
967k
    if (ret == NULL) {
5196
2.44k
        xmlXPathErrMemory(NULL, "creating float object\n");
5197
2.44k
  return(NULL);
5198
2.44k
    }
5199
965k
    memset(ret, 0 , sizeof(xmlXPathObject));
5200
965k
    ret->type = XPATH_NUMBER;
5201
965k
    ret->floatval = val;
5202
#ifdef XP_DEBUG_OBJ_USAGE
5203
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204
#endif
5205
965k
    return(ret);
5206
967k
}
5207
5208
/**
5209
 * xmlXPathNewBoolean:
5210
 * @val:  the boolean value
5211
 *
5212
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5213
 *
5214
 * Returns the newly created object.
5215
 */
5216
xmlXPathObjectPtr
5217
380k
xmlXPathNewBoolean(int val) {
5218
380k
    xmlXPathObjectPtr ret;
5219
5220
380k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221
380k
    if (ret == NULL) {
5222
2.53k
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5223
2.53k
  return(NULL);
5224
2.53k
    }
5225
377k
    memset(ret, 0 , sizeof(xmlXPathObject));
5226
377k
    ret->type = XPATH_BOOLEAN;
5227
377k
    ret->boolval = (val != 0);
5228
#ifdef XP_DEBUG_OBJ_USAGE
5229
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230
#endif
5231
377k
    return(ret);
5232
380k
}
5233
5234
/**
5235
 * xmlXPathNewString:
5236
 * @val:  the xmlChar * value
5237
 *
5238
 * Create a new xmlXPathObjectPtr of type string and of value @val
5239
 *
5240
 * Returns the newly created object.
5241
 */
5242
xmlXPathObjectPtr
5243
223k
xmlXPathNewString(const xmlChar *val) {
5244
223k
    xmlXPathObjectPtr ret;
5245
5246
223k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
223k
    if (ret == NULL) {
5248
4.92k
        xmlXPathErrMemory(NULL, "creating string object\n");
5249
4.92k
  return(NULL);
5250
4.92k
    }
5251
218k
    memset(ret, 0 , sizeof(xmlXPathObject));
5252
218k
    ret->type = XPATH_STRING;
5253
218k
    if (val == NULL)
5254
135
        val = BAD_CAST "";
5255
218k
    ret->stringval = xmlStrdup(val);
5256
218k
    if (ret->stringval == NULL) {
5257
40
        xmlFree(ret);
5258
40
        return(NULL);
5259
40
    }
5260
#ifdef XP_DEBUG_OBJ_USAGE
5261
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5262
#endif
5263
218k
    return(ret);
5264
218k
}
5265
5266
/**
5267
 * xmlXPathWrapString:
5268
 * @val:  the xmlChar * value
5269
 *
5270
 * Wraps the @val string into an XPath object.
5271
 *
5272
 * Returns the newly created object.
5273
 *
5274
 * Frees @val in case of error.
5275
 */
5276
xmlXPathObjectPtr
5277
480k
xmlXPathWrapString (xmlChar *val) {
5278
480k
    xmlXPathObjectPtr ret;
5279
5280
480k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281
480k
    if (ret == NULL) {
5282
111
        xmlXPathErrMemory(NULL, "creating string object\n");
5283
111
        xmlFree(val);
5284
111
  return(NULL);
5285
111
    }
5286
480k
    memset(ret, 0 , sizeof(xmlXPathObject));
5287
480k
    ret->type = XPATH_STRING;
5288
480k
    ret->stringval = val;
5289
#ifdef XP_DEBUG_OBJ_USAGE
5290
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291
#endif
5292
480k
    return(ret);
5293
480k
}
5294
5295
/**
5296
 * xmlXPathNewCString:
5297
 * @val:  the char * value
5298
 *
5299
 * Create a new xmlXPathObjectPtr of type string and of value @val
5300
 *
5301
 * Returns the newly created object.
5302
 */
5303
xmlXPathObjectPtr
5304
43.3k
xmlXPathNewCString(const char *val) {
5305
43.3k
    return(xmlXPathNewString(BAD_CAST val));
5306
43.3k
}
5307
5308
/**
5309
 * xmlXPathWrapCString:
5310
 * @val:  the char * value
5311
 *
5312
 * Wraps a string into an XPath object.
5313
 *
5314
 * Returns the newly created object.
5315
 */
5316
xmlXPathObjectPtr
5317
0
xmlXPathWrapCString (char * val) {
5318
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5319
0
}
5320
5321
/**
5322
 * xmlXPathWrapExternal:
5323
 * @val:  the user data
5324
 *
5325
 * Wraps the @val data into an XPath object.
5326
 *
5327
 * Returns the newly created object.
5328
 */
5329
xmlXPathObjectPtr
5330
917
xmlXPathWrapExternal (void *val) {
5331
917
    xmlXPathObjectPtr ret;
5332
5333
917
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334
917
    if (ret == NULL) {
5335
5
        xmlXPathErrMemory(NULL, "creating user object\n");
5336
5
  return(NULL);
5337
5
    }
5338
912
    memset(ret, 0 , sizeof(xmlXPathObject));
5339
912
    ret->type = XPATH_USERS;
5340
912
    ret->user = val;
5341
#ifdef XP_DEBUG_OBJ_USAGE
5342
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343
#endif
5344
912
    return(ret);
5345
917
}
5346
5347
/**
5348
 * xmlXPathObjectCopy:
5349
 * @val:  the original object
5350
 *
5351
 * allocate a new copy of a given object
5352
 *
5353
 * Returns the newly created object.
5354
 */
5355
xmlXPathObjectPtr
5356
429k
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5357
429k
    xmlXPathObjectPtr ret;
5358
5359
429k
    if (val == NULL)
5360
1
  return(NULL);
5361
5362
429k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5363
429k
    if (ret == NULL) {
5364
314
        xmlXPathErrMemory(NULL, "copying object\n");
5365
314
  return(NULL);
5366
314
    }
5367
429k
    memcpy(ret, val , sizeof(xmlXPathObject));
5368
#ifdef XP_DEBUG_OBJ_USAGE
5369
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5370
#endif
5371
429k
    switch (val->type) {
5372
5
  case XPATH_BOOLEAN:
5373
7.50k
  case XPATH_NUMBER:
5374
#ifdef LIBXML_XPTR_LOCS_ENABLED
5375
  case XPATH_POINT:
5376
  case XPATH_RANGE:
5377
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5378
7.50k
      break;
5379
38.9k
  case XPATH_STRING:
5380
38.9k
      ret->stringval = xmlStrdup(val->stringval);
5381
38.9k
            if (ret->stringval == NULL) {
5382
18
                xmlFree(ret);
5383
18
                return(NULL);
5384
18
            }
5385
38.8k
      break;
5386
38.8k
  case XPATH_XSLT_TREE:
5387
#if 0
5388
/*
5389
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390
  this previous handling is no longer correct, and can cause some serious
5391
  problems (ref. bug 145547)
5392
*/
5393
      if ((val->nodesetval != NULL) &&
5394
    (val->nodesetval->nodeTab != NULL)) {
5395
    xmlNodePtr cur, tmp;
5396
    xmlDocPtr top;
5397
5398
    ret->boolval = 1;
5399
    top =  xmlNewDoc(NULL);
5400
    top->name = (char *)
5401
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5402
    ret->user = top;
5403
    if (top != NULL) {
5404
        top->doc = top;
5405
        cur = val->nodesetval->nodeTab[0]->children;
5406
        while (cur != NULL) {
5407
      tmp = xmlDocCopyNode(cur, top, 1);
5408
      xmlAddChild((xmlNodePtr) top, tmp);
5409
      cur = cur->next;
5410
        }
5411
    }
5412
5413
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5414
      } else
5415
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5416
      /* Deallocate the copied tree value */
5417
      break;
5418
#endif
5419
383k
  case XPATH_NODESET:
5420
            /* TODO: Check memory error. */
5421
383k
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5422
      /* Do not deallocate the copied tree value */
5423
383k
      ret->boolval = 0;
5424
383k
      break;
5425
#ifdef LIBXML_XPTR_LOCS_ENABLED
5426
  case XPATH_LOCATIONSET:
5427
  {
5428
      xmlLocationSetPtr loc = val->user;
5429
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5430
      break;
5431
  }
5432
#endif
5433
0
        case XPATH_USERS:
5434
0
      ret->user = val->user;
5435
0
      break;
5436
0
        case XPATH_UNDEFINED:
5437
0
      xmlGenericError(xmlGenericErrorContext,
5438
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5439
0
        val->type);
5440
0
      break;
5441
429k
    }
5442
429k
    return(ret);
5443
429k
}
5444
5445
/**
5446
 * xmlXPathFreeObject:
5447
 * @obj:  the object to free
5448
 *
5449
 * Free up an xmlXPathObjectPtr object.
5450
 */
5451
void
5452
7.72M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453
7.72M
    if (obj == NULL) return;
5454
7.71M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455
4.57M
  if (obj->boolval) {
5456
#if 0
5457
      if (obj->user != NULL) {
5458
                xmlXPathFreeNodeSet(obj->nodesetval);
5459
    xmlFreeNodeList((xmlNodePtr) obj->user);
5460
      } else
5461
#endif
5462
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5463
0
      if (obj->nodesetval != NULL)
5464
0
    xmlXPathFreeValueTree(obj->nodesetval);
5465
4.57M
  } else {
5466
4.57M
      if (obj->nodesetval != NULL)
5467
4.10M
    xmlXPathFreeNodeSet(obj->nodesetval);
5468
4.57M
  }
5469
#ifdef LIBXML_XPTR_LOCS_ENABLED
5470
    } else if (obj->type == XPATH_LOCATIONSET) {
5471
  if (obj->user != NULL)
5472
      xmlXPtrFreeLocationSet(obj->user);
5473
#endif
5474
4.57M
    } else if (obj->type == XPATH_STRING) {
5475
1.24M
  if (obj->stringval != NULL)
5476
1.21M
      xmlFree(obj->stringval);
5477
1.24M
    }
5478
#ifdef XP_DEBUG_OBJ_USAGE
5479
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480
#endif
5481
7.71M
    xmlFree(obj);
5482
7.71M
}
5483
5484
static void
5485
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487
0
}
5488
5489
/**
5490
 * xmlXPathReleaseObject:
5491
 * @obj:  the xmlXPathObjectPtr to free or to cache
5492
 *
5493
 * Depending on the state of the cache this frees the given
5494
 * XPath object or stores it in the cache.
5495
 */
5496
static void
5497
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5498
14.7M
{
5499
14.7M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500
28.9k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501
14.7M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502
5503
17.1M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504
5505
14.7M
    if (obj == NULL)
5506
21.4k
  return;
5507
14.7M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508
16.2k
   xmlXPathFreeObject(obj);
5509
14.7M
    } else {
5510
14.7M
  xmlXPathContextCachePtr cache =
5511
14.7M
      (xmlXPathContextCachePtr) ctxt->cache;
5512
5513
14.7M
  switch (obj->type) {
5514
11.1M
      case XPATH_NODESET:
5515
11.1M
      case XPATH_XSLT_TREE:
5516
11.1M
    if (obj->nodesetval != NULL) {
5517
9.74M
        if (obj->boolval) {
5518
      /*
5519
      * It looks like the @boolval is used for
5520
      * evaluation if this an XSLT Result Tree Fragment.
5521
      * TODO: Check if this assumption is correct.
5522
      */
5523
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5524
0
      xmlXPathFreeValueTree(obj->nodesetval);
5525
0
      obj->nodesetval = NULL;
5526
9.74M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5527
9.74M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5528
9.70M
          cache->maxNodeset)))
5529
7.34M
        {
5530
7.34M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5531
7.33M
      goto obj_cached;
5532
7.34M
        } else {
5533
2.39M
      xmlXPathFreeNodeSet(obj->nodesetval);
5534
2.39M
      obj->nodesetval = NULL;
5535
2.39M
        }
5536
9.74M
    }
5537
3.83M
    break;
5538
3.83M
      case XPATH_STRING:
5539
305k
    if (obj->stringval != NULL)
5540
305k
        xmlFree(obj->stringval);
5541
5542
305k
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543
304k
        XP_CACHE_ADD(cache->stringObjs, obj);
5544
304k
        goto obj_cached;
5545
304k
    }
5546
543
    break;
5547
1.10M
      case XPATH_BOOLEAN:
5548
1.10M
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549
1.10M
        XP_CACHE_ADD(cache->booleanObjs, obj);
5550
1.09M
        goto obj_cached;
5551
1.10M
    }
5552
570
    break;
5553
2.16M
      case XPATH_NUMBER:
5554
2.16M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555
2.16M
        XP_CACHE_ADD(cache->numberObjs, obj);
5556
2.16M
        goto obj_cached;
5557
2.16M
    }
5558
3.21k
    break;
5559
#ifdef LIBXML_XPTR_LOCS_ENABLED
5560
      case XPATH_LOCATIONSET:
5561
    if (obj->user != NULL) {
5562
        xmlXPtrFreeLocationSet(obj->user);
5563
    }
5564
    goto free_obj;
5565
#endif
5566
3.21k
      default:
5567
909
    goto free_obj;
5568
14.7M
  }
5569
5570
  /*
5571
  * Fallback to adding to the misc-objects slot.
5572
  */
5573
3.83M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574
3.81M
      XP_CACHE_ADD(cache->miscObjs, obj);
5575
3.81M
  } else
5576
25.5k
      goto free_obj;
5577
5578
14.7M
obj_cached:
5579
5580
#ifdef XP_DEBUG_OBJ_USAGE
5581
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582
#endif
5583
5584
14.7M
  if (obj->nodesetval != NULL) {
5585
7.33M
      xmlNodeSetPtr tmpset = obj->nodesetval;
5586
5587
      /*
5588
      * TODO: Due to those nasty ns-nodes, we need to traverse
5589
      *  the list and free the ns-nodes.
5590
      * URGENT TODO: Check if it's actually slowing things down.
5591
      *  Maybe we shouldn't try to preserve the list.
5592
      */
5593
7.33M
      if (tmpset->nodeNr > 1) {
5594
689k
    int i;
5595
689k
    xmlNodePtr node;
5596
5597
10.9M
    for (i = 0; i < tmpset->nodeNr; i++) {
5598
10.2M
        node = tmpset->nodeTab[i];
5599
10.2M
        if ((node != NULL) &&
5600
10.2M
      (node->type == XML_NAMESPACE_DECL))
5601
15.1k
        {
5602
15.1k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603
15.1k
        }
5604
10.2M
    }
5605
6.64M
      } else if (tmpset->nodeNr == 1) {
5606
5.61M
    if ((tmpset->nodeTab[0] != NULL) &&
5607
5.61M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608
59.8k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609
5.61M
      }
5610
7.33M
      tmpset->nodeNr = 0;
5611
7.33M
      memset(obj, 0, sizeof(xmlXPathObject));
5612
7.33M
      obj->nodesetval = tmpset;
5613
7.33M
  } else
5614
7.37M
      memset(obj, 0, sizeof(xmlXPathObject));
5615
5616
14.7M
  return;
5617
5618
43.9k
free_obj:
5619
  /*
5620
  * Cache is full; free the object.
5621
  */
5622
43.9k
  if (obj->nodesetval != NULL)
5623
8.43k
      xmlXPathFreeNodeSet(obj->nodesetval);
5624
#ifdef XP_DEBUG_OBJ_USAGE
5625
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626
#endif
5627
43.9k
  xmlFree(obj);
5628
43.9k
    }
5629
60.2k
    return;
5630
14.7M
}
5631
5632
5633
/************************************************************************
5634
 *                  *
5635
 *      Type Casting Routines       *
5636
 *                  *
5637
 ************************************************************************/
5638
5639
/**
5640
 * xmlXPathCastBooleanToString:
5641
 * @val:  a boolean
5642
 *
5643
 * Converts a boolean to its string value.
5644
 *
5645
 * Returns a newly allocated string.
5646
 */
5647
xmlChar *
5648
92.2k
xmlXPathCastBooleanToString (int val) {
5649
92.2k
    xmlChar *ret;
5650
92.2k
    if (val)
5651
20.2k
  ret = xmlStrdup((const xmlChar *) "true");
5652
71.9k
    else
5653
71.9k
  ret = xmlStrdup((const xmlChar *) "false");
5654
92.2k
    return(ret);
5655
92.2k
}
5656
5657
/**
5658
 * xmlXPathCastNumberToString:
5659
 * @val:  a number
5660
 *
5661
 * Converts a number to its string value.
5662
 *
5663
 * Returns a newly allocated string.
5664
 */
5665
xmlChar *
5666
432k
xmlXPathCastNumberToString (double val) {
5667
432k
    xmlChar *ret;
5668
432k
    switch (xmlXPathIsInf(val)) {
5669
222
    case 1:
5670
222
  ret = xmlStrdup((const xmlChar *) "Infinity");
5671
222
  break;
5672
207
    case -1:
5673
207
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5674
207
  break;
5675
431k
    default:
5676
431k
  if (xmlXPathIsNaN(val)) {
5677
289k
      ret = xmlStrdup((const xmlChar *) "NaN");
5678
289k
  } else if (val == 0) {
5679
            /* Omit sign for negative zero. */
5680
25.0k
      ret = xmlStrdup((const xmlChar *) "0");
5681
117k
  } else {
5682
      /* could be improved */
5683
117k
      char buf[100];
5684
117k
      xmlXPathFormatNumber(val, buf, 99);
5685
117k
      buf[99] = 0;
5686
117k
      ret = xmlStrdup((const xmlChar *) buf);
5687
117k
  }
5688
432k
    }
5689
432k
    return(ret);
5690
432k
}
5691
5692
/**
5693
 * xmlXPathCastNodeToString:
5694
 * @node:  a node
5695
 *
5696
 * Converts a node to its string value.
5697
 *
5698
 * Returns a newly allocated string.
5699
 */
5700
xmlChar *
5701
2.72M
xmlXPathCastNodeToString (xmlNodePtr node) {
5702
2.72M
xmlChar *ret;
5703
2.72M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5704
17.2k
  ret = xmlStrdup((const xmlChar *) "");
5705
2.72M
    return(ret);
5706
2.72M
}
5707
5708
/**
5709
 * xmlXPathCastNodeSetToString:
5710
 * @ns:  a node-set
5711
 *
5712
 * Converts a node-set to its string value.
5713
 *
5714
 * Returns a newly allocated string.
5715
 */
5716
xmlChar *
5717
3.62M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718
3.62M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719
1.08M
  return(xmlStrdup((const xmlChar *) ""));
5720
5721
2.54M
    if (ns->nodeNr > 1)
5722
86.1k
  xmlXPathNodeSetSort(ns);
5723
2.54M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724
3.62M
}
5725
5726
/**
5727
 * xmlXPathCastToString:
5728
 * @val:  an XPath object
5729
 *
5730
 * Converts an existing object to its string() equivalent
5731
 *
5732
 * Returns the allocated string value of the object, NULL in case of error.
5733
 *         It's up to the caller to free the string memory with xmlFree().
5734
 */
5735
xmlChar *
5736
1.89M
xmlXPathCastToString(xmlXPathObjectPtr val) {
5737
1.89M
    xmlChar *ret = NULL;
5738
5739
1.89M
    if (val == NULL)
5740
0
  return(xmlStrdup((const xmlChar *) ""));
5741
1.89M
    switch (val->type) {
5742
0
  case XPATH_UNDEFINED:
5743
#ifdef DEBUG_EXPR
5744
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5745
#endif
5746
0
      ret = xmlStrdup((const xmlChar *) "");
5747
0
      break;
5748
1.45M
        case XPATH_NODESET:
5749
1.45M
        case XPATH_XSLT_TREE:
5750
1.45M
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751
1.45M
      break;
5752
123k
  case XPATH_STRING:
5753
123k
      return(xmlStrdup(val->stringval));
5754
80.1k
        case XPATH_BOOLEAN:
5755
80.1k
      ret = xmlXPathCastBooleanToString(val->boolval);
5756
80.1k
      break;
5757
237k
  case XPATH_NUMBER: {
5758
237k
      ret = xmlXPathCastNumberToString(val->floatval);
5759
237k
      break;
5760
1.45M
  }
5761
0
  case XPATH_USERS:
5762
#ifdef LIBXML_XPTR_LOCS_ENABLED
5763
  case XPATH_POINT:
5764
  case XPATH_RANGE:
5765
  case XPATH_LOCATIONSET:
5766
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5767
0
      TODO
5768
0
      ret = xmlStrdup((const xmlChar *) "");
5769
0
      break;
5770
1.89M
    }
5771
1.77M
    return(ret);
5772
1.89M
}
5773
5774
/**
5775
 * xmlXPathConvertString:
5776
 * @val:  an XPath object
5777
 *
5778
 * Converts an existing object to its string() equivalent
5779
 *
5780
 * Returns the new object, the old one is freed (or the operation
5781
 *         is done directly on @val)
5782
 */
5783
xmlXPathObjectPtr
5784
371k
xmlXPathConvertString(xmlXPathObjectPtr val) {
5785
371k
    xmlChar *res = NULL;
5786
5787
371k
    if (val == NULL)
5788
0
  return(xmlXPathNewCString(""));
5789
5790
371k
    switch (val->type) {
5791
0
    case XPATH_UNDEFINED:
5792
#ifdef DEBUG_EXPR
5793
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5794
#endif
5795
0
  break;
5796
345k
    case XPATH_NODESET:
5797
346k
    case XPATH_XSLT_TREE:
5798
346k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5799
346k
  break;
5800
0
    case XPATH_STRING:
5801
0
  return(val);
5802
6.02k
    case XPATH_BOOLEAN:
5803
6.02k
  res = xmlXPathCastBooleanToString(val->boolval);
5804
6.02k
  break;
5805
19.5k
    case XPATH_NUMBER:
5806
19.5k
  res = xmlXPathCastNumberToString(val->floatval);
5807
19.5k
  break;
5808
0
    case XPATH_USERS:
5809
#ifdef LIBXML_XPTR_LOCS_ENABLED
5810
    case XPATH_POINT:
5811
    case XPATH_RANGE:
5812
    case XPATH_LOCATIONSET:
5813
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5814
0
  TODO;
5815
0
  break;
5816
371k
    }
5817
371k
    xmlXPathFreeObject(val);
5818
371k
    if (res == NULL)
5819
205
  return(xmlXPathNewCString(""));
5820
371k
    return(xmlXPathWrapString(res));
5821
371k
}
5822
5823
/**
5824
 * xmlXPathCastBooleanToNumber:
5825
 * @val:  a boolean
5826
 *
5827
 * Converts a boolean to its number value
5828
 *
5829
 * Returns the number value
5830
 */
5831
double
5832
293k
xmlXPathCastBooleanToNumber(int val) {
5833
293k
    if (val)
5834
12.5k
  return(1.0);
5835
280k
    return(0.0);
5836
293k
}
5837
5838
/**
5839
 * xmlXPathCastStringToNumber:
5840
 * @val:  a string
5841
 *
5842
 * Converts a string to its number value
5843
 *
5844
 * Returns the number value
5845
 */
5846
double
5847
1.62M
xmlXPathCastStringToNumber(const xmlChar * val) {
5848
1.62M
    return(xmlXPathStringEvalNumber(val));
5849
1.62M
}
5850
5851
/**
5852
 * xmlXPathCastNodeToNumber:
5853
 * @node:  a node
5854
 *
5855
 * Converts a node to its number value
5856
 *
5857
 * Returns the number value
5858
 */
5859
double
5860
18.3k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861
18.3k
    xmlChar *strval;
5862
18.3k
    double ret;
5863
5864
18.3k
    if (node == NULL)
5865
0
  return(xmlXPathNAN);
5866
18.3k
    strval = xmlXPathCastNodeToString(node);
5867
18.3k
    if (strval == NULL)
5868
281
  return(xmlXPathNAN);
5869
18.0k
    ret = xmlXPathCastStringToNumber(strval);
5870
18.0k
    xmlFree(strval);
5871
5872
18.0k
    return(ret);
5873
18.3k
}
5874
5875
/**
5876
 * xmlXPathCastNodeSetToNumber:
5877
 * @ns:  a node-set
5878
 *
5879
 * Converts a node-set to its number value
5880
 *
5881
 * Returns the number value
5882
 */
5883
double
5884
1.44M
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885
1.44M
    xmlChar *str;
5886
1.44M
    double ret;
5887
5888
1.44M
    if (ns == NULL)
5889
47.6k
  return(xmlXPathNAN);
5890
1.40M
    str = xmlXPathCastNodeSetToString(ns);
5891
1.40M
    ret = xmlXPathCastStringToNumber(str);
5892
1.40M
    xmlFree(str);
5893
1.40M
    return(ret);
5894
1.44M
}
5895
5896
/**
5897
 * xmlXPathCastToNumber:
5898
 * @val:  an XPath object
5899
 *
5900
 * Converts an XPath object to its number value
5901
 *
5902
 * Returns the number value
5903
 */
5904
double
5905
2.51M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906
2.51M
    double ret = 0.0;
5907
5908
2.51M
    if (val == NULL)
5909
0
  return(xmlXPathNAN);
5910
2.51M
    switch (val->type) {
5911
0
    case XPATH_UNDEFINED:
5912
#ifdef DEBUG_EXPR
5913
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5914
#endif
5915
0
  ret = xmlXPathNAN;
5916
0
  break;
5917
1.44M
    case XPATH_NODESET:
5918
1.44M
    case XPATH_XSLT_TREE:
5919
1.44M
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920
1.44M
  break;
5921
202k
    case XPATH_STRING:
5922
202k
  ret = xmlXPathCastStringToNumber(val->stringval);
5923
202k
  break;
5924
567k
    case XPATH_NUMBER:
5925
567k
  ret = val->floatval;
5926
567k
  break;
5927
293k
    case XPATH_BOOLEAN:
5928
293k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5929
293k
  break;
5930
96
    case XPATH_USERS:
5931
#ifdef LIBXML_XPTR_LOCS_ENABLED
5932
    case XPATH_POINT:
5933
    case XPATH_RANGE:
5934
    case XPATH_LOCATIONSET:
5935
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5936
96
  TODO;
5937
96
  ret = xmlXPathNAN;
5938
96
  break;
5939
2.51M
    }
5940
2.51M
    return(ret);
5941
2.51M
}
5942
5943
/**
5944
 * xmlXPathConvertNumber:
5945
 * @val:  an XPath object
5946
 *
5947
 * Converts an existing object to its number() equivalent
5948
 *
5949
 * Returns the new object, the old one is freed (or the operation
5950
 *         is done directly on @val)
5951
 */
5952
xmlXPathObjectPtr
5953
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954
0
    xmlXPathObjectPtr ret;
5955
5956
0
    if (val == NULL)
5957
0
  return(xmlXPathNewFloat(0.0));
5958
0
    if (val->type == XPATH_NUMBER)
5959
0
  return(val);
5960
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961
0
    xmlXPathFreeObject(val);
5962
0
    return(ret);
5963
0
}
5964
5965
/**
5966
 * xmlXPathCastNumberToBoolean:
5967
 * @val:  a number
5968
 *
5969
 * Converts a number to its boolean value
5970
 *
5971
 * Returns the boolean value
5972
 */
5973
int
5974
238k
xmlXPathCastNumberToBoolean (double val) {
5975
238k
     if (xmlXPathIsNaN(val) || (val == 0.0))
5976
164k
   return(0);
5977
73.2k
     return(1);
5978
238k
}
5979
5980
/**
5981
 * xmlXPathCastStringToBoolean:
5982
 * @val:  a string
5983
 *
5984
 * Converts a string to its boolean value
5985
 *
5986
 * Returns the boolean value
5987
 */
5988
int
5989
1.08k
xmlXPathCastStringToBoolean (const xmlChar *val) {
5990
1.08k
    if ((val == NULL) || (xmlStrlen(val) == 0))
5991
342
  return(0);
5992
739
    return(1);
5993
1.08k
}
5994
5995
/**
5996
 * xmlXPathCastNodeSetToBoolean:
5997
 * @ns:  a node-set
5998
 *
5999
 * Converts a node-set to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
206k
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005
206k
    if ((ns == NULL) || (ns->nodeNr == 0))
6006
194k
  return(0);
6007
12.1k
    return(1);
6008
206k
}
6009
6010
/**
6011
 * xmlXPathCastToBoolean:
6012
 * @val:  an XPath object
6013
 *
6014
 * Converts an XPath object to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
265k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020
265k
    int ret = 0;
6021
6022
265k
    if (val == NULL)
6023
0
  return(0);
6024
265k
    switch (val->type) {
6025
0
    case XPATH_UNDEFINED:
6026
#ifdef DEBUG_EXPR
6027
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028
#endif
6029
0
  ret = 0;
6030
0
  break;
6031
206k
    case XPATH_NODESET:
6032
206k
    case XPATH_XSLT_TREE:
6033
206k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034
206k
  break;
6035
1.08k
    case XPATH_STRING:
6036
1.08k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6037
1.08k
  break;
6038
57.7k
    case XPATH_NUMBER:
6039
57.7k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040
57.7k
  break;
6041
0
    case XPATH_BOOLEAN:
6042
0
  ret = val->boolval;
6043
0
  break;
6044
0
    case XPATH_USERS:
6045
#ifdef LIBXML_XPTR_LOCS_ENABLED
6046
    case XPATH_POINT:
6047
    case XPATH_RANGE:
6048
    case XPATH_LOCATIONSET:
6049
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6050
0
  TODO;
6051
0
  ret = 0;
6052
0
  break;
6053
265k
    }
6054
265k
    return(ret);
6055
265k
}
6056
6057
6058
/**
6059
 * xmlXPathConvertBoolean:
6060
 * @val:  an XPath object
6061
 *
6062
 * Converts an existing object to its boolean() equivalent
6063
 *
6064
 * Returns the new object, the old one is freed (or the operation
6065
 *         is done directly on @val)
6066
 */
6067
xmlXPathObjectPtr
6068
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6069
0
    xmlXPathObjectPtr ret;
6070
6071
0
    if (val == NULL)
6072
0
  return(xmlXPathNewBoolean(0));
6073
0
    if (val->type == XPATH_BOOLEAN)
6074
0
  return(val);
6075
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6076
0
    xmlXPathFreeObject(val);
6077
0
    return(ret);
6078
0
}
6079
6080
/************************************************************************
6081
 *                  *
6082
 *    Routines to handle XPath contexts     *
6083
 *                  *
6084
 ************************************************************************/
6085
6086
/**
6087
 * xmlXPathNewContext:
6088
 * @doc:  the XML document
6089
 *
6090
 * Create a new xmlXPathContext
6091
 *
6092
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6093
 */
6094
xmlXPathContextPtr
6095
59.6k
xmlXPathNewContext(xmlDocPtr doc) {
6096
59.6k
    xmlXPathContextPtr ret;
6097
6098
59.6k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099
59.6k
    if (ret == NULL) {
6100
19
        xmlXPathErrMemory(NULL, "creating context\n");
6101
19
  return(NULL);
6102
19
    }
6103
59.6k
    memset(ret, 0 , sizeof(xmlXPathContext));
6104
59.6k
    ret->doc = doc;
6105
59.6k
    ret->node = NULL;
6106
6107
59.6k
    ret->varHash = NULL;
6108
6109
59.6k
    ret->nb_types = 0;
6110
59.6k
    ret->max_types = 0;
6111
59.6k
    ret->types = NULL;
6112
6113
59.6k
    ret->funcHash = xmlHashCreate(0);
6114
6115
59.6k
    ret->nb_axis = 0;
6116
59.6k
    ret->max_axis = 0;
6117
59.6k
    ret->axis = NULL;
6118
6119
59.6k
    ret->nsHash = NULL;
6120
59.6k
    ret->user = NULL;
6121
6122
59.6k
    ret->contextSize = -1;
6123
59.6k
    ret->proximityPosition = -1;
6124
6125
#ifdef XP_DEFAULT_CACHE_ON
6126
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6127
  xmlXPathFreeContext(ret);
6128
  return(NULL);
6129
    }
6130
#endif
6131
6132
59.6k
    xmlXPathRegisterAllFunctions(ret);
6133
6134
59.6k
    return(ret);
6135
59.6k
}
6136
6137
/**
6138
 * xmlXPathFreeContext:
6139
 * @ctxt:  the context to free
6140
 *
6141
 * Free up an xmlXPathContext
6142
 */
6143
void
6144
59.6k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145
59.6k
    if (ctxt == NULL) return;
6146
6147
59.6k
    if (ctxt->cache != NULL)
6148
37.2k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149
59.6k
    xmlXPathRegisteredNsCleanup(ctxt);
6150
59.6k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6151
59.6k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6152
59.6k
    xmlResetError(&ctxt->lastError);
6153
59.6k
    xmlFree(ctxt);
6154
59.6k
}
6155
6156
/************************************************************************
6157
 *                  *
6158
 *    Routines to handle XPath parser contexts    *
6159
 *                  *
6160
 ************************************************************************/
6161
6162
#define CHECK_CTXT(ctxt)            \
6163
40.4k
    if (ctxt == NULL) {           \
6164
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6165
0
    NULL, NULL, XML_FROM_XPATH,       \
6166
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6167
0
    __FILE__, __LINE__,         \
6168
0
    NULL, NULL, NULL, 0, 0,         \
6169
0
    "NULL context pointer\n");        \
6170
0
  return(NULL);             \
6171
0
    }                  \
6172
6173
#define CHECK_CTXT_NEG(ctxt)            \
6174
5.01M
    if (ctxt == NULL) {           \
6175
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6176
0
    NULL, NULL, XML_FROM_XPATH,       \
6177
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6178
0
    __FILE__, __LINE__,         \
6179
0
    NULL, NULL, NULL, 0, 0,         \
6180
0
    "NULL context pointer\n");        \
6181
0
  return(-1);             \
6182
0
    }                  \
6183
6184
6185
#define CHECK_CONTEXT(ctxt)           \
6186
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6187
        (ctxt->doc->children == NULL)) {        \
6188
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6189
  return(NULL);             \
6190
    }
6191
6192
6193
/**
6194
 * xmlXPathNewParserContext:
6195
 * @str:  the XPath expression
6196
 * @ctxt:  the XPath context
6197
 *
6198
 * Create a new xmlXPathParserContext
6199
 *
6200
 * Returns the xmlXPathParserContext just allocated.
6201
 */
6202
xmlXPathParserContextPtr
6203
1.11M
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204
1.11M
    xmlXPathParserContextPtr ret;
6205
6206
1.11M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207
1.11M
    if (ret == NULL) {
6208
3.17k
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6209
3.17k
  return(NULL);
6210
3.17k
    }
6211
1.11M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6212
1.11M
    ret->cur = ret->base = str;
6213
1.11M
    ret->context = ctxt;
6214
6215
1.11M
    ret->comp = xmlXPathNewCompExpr();
6216
1.11M
    if (ret->comp == NULL) {
6217
166
  xmlFree(ret->valueTab);
6218
166
  xmlFree(ret);
6219
166
  return(NULL);
6220
166
    }
6221
1.11M
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222
97.1k
        ret->comp->dict = ctxt->dict;
6223
97.1k
  xmlDictReference(ret->comp->dict);
6224
97.1k
    }
6225
6226
1.11M
    return(ret);
6227
1.11M
}
6228
6229
/**
6230
 * xmlXPathCompParserContext:
6231
 * @comp:  the XPath compiled expression
6232
 * @ctxt:  the XPath context
6233
 *
6234
 * Create a new xmlXPathParserContext when processing a compiled expression
6235
 *
6236
 * Returns the xmlXPathParserContext just allocated.
6237
 */
6238
static xmlXPathParserContextPtr
6239
5.01M
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240
5.01M
    xmlXPathParserContextPtr ret;
6241
6242
5.01M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243
5.01M
    if (ret == NULL) {
6244
44.3k
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245
44.3k
  return(NULL);
6246
44.3k
    }
6247
4.96M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6248
6249
    /* Allocate the value stack */
6250
4.96M
    ret->valueTab = (xmlXPathObjectPtr *)
6251
4.96M
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252
4.96M
    if (ret->valueTab == NULL) {
6253
266
  xmlFree(ret);
6254
266
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255
266
  return(NULL);
6256
266
    }
6257
4.96M
    ret->valueNr = 0;
6258
4.96M
    ret->valueMax = 10;
6259
4.96M
    ret->value = NULL;
6260
6261
4.96M
    ret->context = ctxt;
6262
4.96M
    ret->comp = comp;
6263
6264
4.96M
    return(ret);
6265
4.96M
}
6266
6267
/**
6268
 * xmlXPathFreeParserContext:
6269
 * @ctxt:  the context to free
6270
 *
6271
 * Free up an xmlXPathParserContext
6272
 */
6273
void
6274
6.08M
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275
6.08M
    int i;
6276
6277
6.08M
    if (ctxt->valueTab != NULL) {
6278
5.52M
        for (i = 0; i < ctxt->valueNr; i++) {
6279
517k
            if (ctxt->context)
6280
517k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281
0
            else
6282
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6283
517k
        }
6284
5.00M
        xmlFree(ctxt->valueTab);
6285
5.00M
    }
6286
6.08M
    if (ctxt->comp != NULL) {
6287
744k
#ifdef XPATH_STREAMING
6288
744k
  if (ctxt->comp->stream != NULL) {
6289
3.59k
      xmlFreePatternList(ctxt->comp->stream);
6290
3.59k
      ctxt->comp->stream = NULL;
6291
3.59k
  }
6292
744k
#endif
6293
744k
  xmlXPathFreeCompExpr(ctxt->comp);
6294
744k
    }
6295
6.08M
    xmlFree(ctxt);
6296
6.08M
}
6297
6298
/************************************************************************
6299
 *                  *
6300
 *    The implicit core function library      *
6301
 *                  *
6302
 ************************************************************************/
6303
6304
/**
6305
 * xmlXPathNodeValHash:
6306
 * @node:  a node pointer
6307
 *
6308
 * Function computing the beginning of the string value of the node,
6309
 * used to speed up comparisons
6310
 *
6311
 * Returns an int usable as a hash
6312
 */
6313
static unsigned int
6314
167k
xmlXPathNodeValHash(xmlNodePtr node) {
6315
167k
    int len = 2;
6316
167k
    const xmlChar * string = NULL;
6317
167k
    xmlNodePtr tmp = NULL;
6318
167k
    unsigned int ret = 0;
6319
6320
167k
    if (node == NULL)
6321
0
  return(0);
6322
6323
167k
    if (node->type == XML_DOCUMENT_NODE) {
6324
24.2k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325
24.2k
  if (tmp == NULL)
6326
8.73k
      node = node->children;
6327
15.4k
  else
6328
15.4k
      node = tmp;
6329
6330
24.2k
  if (node == NULL)
6331
785
      return(0);
6332
24.2k
    }
6333
6334
166k
    switch (node->type) {
6335
1.50k
  case XML_COMMENT_NODE:
6336
1.69k
  case XML_PI_NODE:
6337
1.69k
  case XML_CDATA_SECTION_NODE:
6338
31.4k
  case XML_TEXT_NODE:
6339
31.4k
      string = node->content;
6340
31.4k
      if (string == NULL)
6341
192
    return(0);
6342
31.2k
      if (string[0] == 0)
6343
0
    return(0);
6344
31.2k
      return(string[0] + (string[1] << 8));
6345
35.0k
  case XML_NAMESPACE_DECL:
6346
35.0k
      string = ((xmlNsPtr)node)->href;
6347
35.0k
      if (string == NULL)
6348
1
    return(0);
6349
35.0k
      if (string[0] == 0)
6350
618
    return(0);
6351
34.4k
      return(string[0] + (string[1] << 8));
6352
15.1k
  case XML_ATTRIBUTE_NODE:
6353
15.1k
      tmp = ((xmlAttrPtr) node)->children;
6354
15.1k
      break;
6355
85.0k
  case XML_ELEMENT_NODE:
6356
85.0k
      tmp = node->children;
6357
85.0k
      break;
6358
0
  default:
6359
0
      return(0);
6360
166k
    }
6361
137k
    while (tmp != NULL) {
6362
100k
  switch (tmp->type) {
6363
0
      case XML_CDATA_SECTION_NODE:
6364
68.9k
      case XML_TEXT_NODE:
6365
68.9k
    string = tmp->content;
6366
68.9k
    break;
6367
31.8k
      default:
6368
31.8k
                string = NULL;
6369
31.8k
    break;
6370
100k
  }
6371
100k
  if ((string != NULL) && (string[0] != 0)) {
6372
68.9k
      if (len == 1) {
6373
2.57k
    return(ret + (string[0] << 8));
6374
2.57k
      }
6375
66.3k
      if (string[1] == 0) {
6376
5.26k
    len = 1;
6377
5.26k
    ret = string[0];
6378
61.0k
      } else {
6379
61.0k
    return(string[0] + (string[1] << 8));
6380
61.0k
      }
6381
66.3k
  }
6382
  /*
6383
   * Skip to next node
6384
   */
6385
37.1k
        if ((tmp->children != NULL) &&
6386
37.1k
            (tmp->type != XML_DTD_NODE) &&
6387
37.1k
            (tmp->type != XML_ENTITY_REF_NODE) &&
6388
37.1k
            (tmp->children->type != XML_ENTITY_DECL)) {
6389
21.3k
            tmp = tmp->children;
6390
21.3k
            continue;
6391
21.3k
  }
6392
15.8k
  if (tmp == node)
6393
0
      break;
6394
6395
15.8k
  if (tmp->next != NULL) {
6396
9.81k
      tmp = tmp->next;
6397
9.81k
      continue;
6398
9.81k
  }
6399
6400
9.34k
  do {
6401
9.34k
      tmp = tmp->parent;
6402
9.34k
      if (tmp == NULL)
6403
0
    break;
6404
9.34k
      if (tmp == node) {
6405
3.20k
    tmp = NULL;
6406
3.20k
    break;
6407
3.20k
      }
6408
6.14k
      if (tmp->next != NULL) {
6409
2.80k
    tmp = tmp->next;
6410
2.80k
    break;
6411
2.80k
      }
6412
6.14k
  } while (tmp != NULL);
6413
6.01k
    }
6414
36.5k
    return(ret);
6415
100k
}
6416
6417
/**
6418
 * xmlXPathStringHash:
6419
 * @string:  a string
6420
 *
6421
 * Function computing the beginning of the string value of the node,
6422
 * used to speed up comparisons
6423
 *
6424
 * Returns an int usable as a hash
6425
 */
6426
static unsigned int
6427
8.07k
xmlXPathStringHash(const xmlChar * string) {
6428
8.07k
    if (string == NULL)
6429
0
  return(0);
6430
8.07k
    if (string[0] == 0)
6431
1.00k
  return(0);
6432
7.06k
    return(string[0] + (string[1] << 8));
6433
8.07k
}
6434
6435
/**
6436
 * xmlXPathCompareNodeSetFloat:
6437
 * @ctxt:  the XPath Parser context
6438
 * @inf:  less than (1) or greater than (0)
6439
 * @strict:  is the comparison strict
6440
 * @arg:  the node set
6441
 * @f:  the value
6442
 *
6443
 * Implement the compare operation between a nodeset and a number
6444
 *     @ns < @val    (1, 1, ...
6445
 *     @ns <= @val   (1, 0, ...
6446
 *     @ns > @val    (0, 1, ...
6447
 *     @ns >= @val   (0, 0, ...
6448
 *
6449
 * If one object to be compared is a node-set and the other is a number,
6450
 * then the comparison will be true if and only if there is a node in the
6451
 * node-set such that the result of performing the comparison on the number
6452
 * to be compared and on the result of converting the string-value of that
6453
 * node to a number using the number function is true.
6454
 *
6455
 * Returns 0 or 1 depending on the results of the test.
6456
 */
6457
static int
6458
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6459
163k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6460
163k
    int i, ret = 0;
6461
163k
    xmlNodeSetPtr ns;
6462
163k
    xmlChar *str2;
6463
6464
163k
    if ((f == NULL) || (arg == NULL) ||
6465
163k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6466
0
  xmlXPathReleaseObject(ctxt->context, arg);
6467
0
  xmlXPathReleaseObject(ctxt->context, f);
6468
0
        return(0);
6469
0
    }
6470
163k
    ns = arg->nodesetval;
6471
163k
    if (ns != NULL) {
6472
220k
  for (i = 0;i < ns->nodeNr;i++) {
6473
77.5k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6474
77.5k
       if (str2 != NULL) {
6475
76.5k
     valuePush(ctxt,
6476
76.5k
         xmlXPathCacheNewString(ctxt->context, str2));
6477
76.5k
     xmlFree(str2);
6478
76.5k
     xmlXPathNumberFunction(ctxt, 1);
6479
76.5k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6480
76.5k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6481
76.5k
     if (ret)
6482
926
         break;
6483
76.5k
       }
6484
77.5k
  }
6485
144k
    }
6486
163k
    xmlXPathReleaseObject(ctxt->context, arg);
6487
163k
    xmlXPathReleaseObject(ctxt->context, f);
6488
163k
    return(ret);
6489
163k
}
6490
6491
/**
6492
 * xmlXPathCompareNodeSetString:
6493
 * @ctxt:  the XPath Parser context
6494
 * @inf:  less than (1) or greater than (0)
6495
 * @strict:  is the comparison strict
6496
 * @arg:  the node set
6497
 * @s:  the value
6498
 *
6499
 * Implement the compare operation between a nodeset and a string
6500
 *     @ns < @val    (1, 1, ...
6501
 *     @ns <= @val   (1, 0, ...
6502
 *     @ns > @val    (0, 1, ...
6503
 *     @ns >= @val   (0, 0, ...
6504
 *
6505
 * If one object to be compared is a node-set and the other is a string,
6506
 * then the comparison will be true if and only if there is a node in
6507
 * the node-set such that the result of performing the comparison on the
6508
 * string-value of the node and the other string is true.
6509
 *
6510
 * Returns 0 or 1 depending on the results of the test.
6511
 */
6512
static int
6513
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6514
7.68k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6515
7.68k
    int i, ret = 0;
6516
7.68k
    xmlNodeSetPtr ns;
6517
7.68k
    xmlChar *str2;
6518
6519
7.68k
    if ((s == NULL) || (arg == NULL) ||
6520
7.68k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6521
0
  xmlXPathReleaseObject(ctxt->context, arg);
6522
0
  xmlXPathReleaseObject(ctxt->context, s);
6523
0
        return(0);
6524
0
    }
6525
7.68k
    ns = arg->nodesetval;
6526
7.68k
    if (ns != NULL) {
6527
10.3k
  for (i = 0;i < ns->nodeNr;i++) {
6528
3.60k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6529
3.60k
       if (str2 != NULL) {
6530
3.56k
     valuePush(ctxt,
6531
3.56k
         xmlXPathCacheNewString(ctxt->context, str2));
6532
3.56k
     xmlFree(str2);
6533
3.56k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6534
3.56k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6535
3.56k
     if (ret)
6536
0
         break;
6537
3.56k
       }
6538
3.60k
  }
6539
6.70k
    }
6540
7.68k
    xmlXPathReleaseObject(ctxt->context, arg);
6541
7.68k
    xmlXPathReleaseObject(ctxt->context, s);
6542
7.68k
    return(ret);
6543
7.68k
}
6544
6545
/**
6546
 * xmlXPathCompareNodeSets:
6547
 * @inf:  less than (1) or greater than (0)
6548
 * @strict:  is the comparison strict
6549
 * @arg1:  the first node set object
6550
 * @arg2:  the second node set object
6551
 *
6552
 * Implement the compare operation on nodesets:
6553
 *
6554
 * If both objects to be compared are node-sets, then the comparison
6555
 * will be true if and only if there is a node in the first node-set
6556
 * and a node in the second node-set such that the result of performing
6557
 * the comparison on the string-values of the two nodes is true.
6558
 * ....
6559
 * When neither object to be compared is a node-set and the operator
6560
 * is <=, <, >= or >, then the objects are compared by converting both
6561
 * objects to numbers and comparing the numbers according to IEEE 754.
6562
 * ....
6563
 * The number function converts its argument to a number as follows:
6564
 *  - a string that consists of optional whitespace followed by an
6565
 *    optional minus sign followed by a Number followed by whitespace
6566
 *    is converted to the IEEE 754 number that is nearest (according
6567
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6568
 *    represented by the string; any other string is converted to NaN
6569
 *
6570
 * Conclusion all nodes need to be converted first to their string value
6571
 * and then the comparison must be done when possible
6572
 */
6573
static int
6574
xmlXPathCompareNodeSets(int inf, int strict,
6575
284k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6576
284k
    int i, j, init = 0;
6577
284k
    double val1;
6578
284k
    double *values2;
6579
284k
    int ret = 0;
6580
284k
    xmlNodeSetPtr ns1;
6581
284k
    xmlNodeSetPtr ns2;
6582
6583
284k
    if ((arg1 == NULL) ||
6584
284k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6585
0
  xmlXPathFreeObject(arg2);
6586
0
        return(0);
6587
0
    }
6588
284k
    if ((arg2 == NULL) ||
6589
284k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6590
0
  xmlXPathFreeObject(arg1);
6591
0
  xmlXPathFreeObject(arg2);
6592
0
        return(0);
6593
0
    }
6594
6595
284k
    ns1 = arg1->nodesetval;
6596
284k
    ns2 = arg2->nodesetval;
6597
6598
284k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6599
268k
  xmlXPathFreeObject(arg1);
6600
268k
  xmlXPathFreeObject(arg2);
6601
268k
  return(0);
6602
268k
    }
6603
16.7k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6604
7.69k
  xmlXPathFreeObject(arg1);
6605
7.69k
  xmlXPathFreeObject(arg2);
6606
7.69k
  return(0);
6607
7.69k
    }
6608
6609
9.04k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6610
9.04k
    if (values2 == NULL) {
6611
        /* TODO: Propagate memory error. */
6612
76
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6613
76
  xmlXPathFreeObject(arg1);
6614
76
  xmlXPathFreeObject(arg2);
6615
76
  return(0);
6616
76
    }
6617
18.7k
    for (i = 0;i < ns1->nodeNr;i++) {
6618
10.9k
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6619
10.9k
  if (xmlXPathIsNaN(val1))
6620
9.46k
      continue;
6621
2.83k
  for (j = 0;j < ns2->nodeNr;j++) {
6622
2.51k
      if (init == 0) {
6623
1.96k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6624
1.96k
      }
6625
2.51k
      if (xmlXPathIsNaN(values2[j]))
6626
857
    continue;
6627
1.65k
      if (inf && strict)
6628
0
    ret = (val1 < values2[j]);
6629
1.65k
      else if (inf && !strict)
6630
0
    ret = (val1 <= values2[j]);
6631
1.65k
      else if (!inf && strict)
6632
540
    ret = (val1 > values2[j]);
6633
1.11k
      else if (!inf && !strict)
6634
1.11k
    ret = (val1 >= values2[j]);
6635
1.65k
      if (ret)
6636
1.19k
    break;
6637
1.65k
  }
6638
1.51k
  if (ret)
6639
1.19k
      break;
6640
318
  init = 1;
6641
318
    }
6642
8.97k
    xmlFree(values2);
6643
8.97k
    xmlXPathFreeObject(arg1);
6644
8.97k
    xmlXPathFreeObject(arg2);
6645
8.97k
    return(ret);
6646
9.04k
}
6647
6648
/**
6649
 * xmlXPathCompareNodeSetValue:
6650
 * @ctxt:  the XPath Parser context
6651
 * @inf:  less than (1) or greater than (0)
6652
 * @strict:  is the comparison strict
6653
 * @arg:  the node set
6654
 * @val:  the value
6655
 *
6656
 * Implement the compare operation between a nodeset and a value
6657
 *     @ns < @val    (1, 1, ...
6658
 *     @ns <= @val   (1, 0, ...
6659
 *     @ns > @val    (0, 1, ...
6660
 *     @ns >= @val   (0, 0, ...
6661
 *
6662
 * If one object to be compared is a node-set and the other is a boolean,
6663
 * then the comparison will be true if and only if the result of performing
6664
 * the comparison on the boolean and on the result of converting
6665
 * the node-set to a boolean using the boolean function is true.
6666
 *
6667
 * Returns 0 or 1 depending on the results of the test.
6668
 */
6669
static int
6670
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6671
312k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6672
312k
    if ((val == NULL) || (arg == NULL) ||
6673
312k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674
0
        return(0);
6675
6676
312k
    switch(val->type) {
6677
163k
        case XPATH_NUMBER:
6678
163k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6679
0
        case XPATH_NODESET:
6680
0
        case XPATH_XSLT_TREE:
6681
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6682
7.68k
        case XPATH_STRING:
6683
7.68k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6684
140k
        case XPATH_BOOLEAN:
6685
140k
      valuePush(ctxt, arg);
6686
140k
      xmlXPathBooleanFunction(ctxt, 1);
6687
140k
      valuePush(ctxt, val);
6688
140k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6689
0
  default:
6690
0
            xmlGenericError(xmlGenericErrorContext,
6691
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6692
0
                    "and object of type %d\n",
6693
0
                    val->type);
6694
0
            xmlXPathReleaseObject(ctxt->context, arg);
6695
0
            xmlXPathReleaseObject(ctxt->context, val);
6696
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6697
312k
    }
6698
0
    return(0);
6699
312k
}
6700
6701
/**
6702
 * xmlXPathEqualNodeSetString:
6703
 * @arg:  the nodeset object argument
6704
 * @str:  the string to compare to.
6705
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6706
 *
6707
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6708
 * If one object to be compared is a node-set and the other is a string,
6709
 * then the comparison will be true if and only if there is a node in
6710
 * the node-set such that the result of performing the comparison on the
6711
 * string-value of the node and the other string is true.
6712
 *
6713
 * Returns 0 or 1 depending on the results of the test.
6714
 */
6715
static int
6716
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6717
23.7k
{
6718
23.7k
    int i;
6719
23.7k
    xmlNodeSetPtr ns;
6720
23.7k
    xmlChar *str2;
6721
23.7k
    unsigned int hash;
6722
6723
23.7k
    if ((str == NULL) || (arg == NULL) ||
6724
23.7k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6725
0
        return (0);
6726
23.7k
    ns = arg->nodesetval;
6727
    /*
6728
     * A NULL nodeset compared with a string is always false
6729
     * (since there is no node equal, and no node not equal)
6730
     */
6731
23.7k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6732
15.6k
        return (0);
6733
8.07k
    hash = xmlXPathStringHash(str);
6734
69.7k
    for (i = 0; i < ns->nodeNr; i++) {
6735
63.9k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6736
17.5k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6737
17.5k
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6738
1.94k
                xmlFree(str2);
6739
1.94k
    if (neq)
6740
0
        continue;
6741
1.94k
                return (1);
6742
15.6k
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6743
6
    if (neq)
6744
0
        continue;
6745
6
                return (1);
6746
15.6k
            } else if (neq) {
6747
164
    if (str2 != NULL)
6748
162
        xmlFree(str2);
6749
164
    return (1);
6750
164
      }
6751
15.4k
            if (str2 != NULL)
6752
15.0k
                xmlFree(str2);
6753
46.4k
        } else if (neq)
6754
213
      return (1);
6755
63.9k
    }
6756
5.75k
    return (0);
6757
8.07k
}
6758
6759
/**
6760
 * xmlXPathEqualNodeSetFloat:
6761
 * @arg:  the nodeset object argument
6762
 * @f:  the float to compare to
6763
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6764
 *
6765
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6766
 * If one object to be compared is a node-set and the other is a number,
6767
 * then the comparison will be true if and only if there is a node in
6768
 * the node-set such that the result of performing the comparison on the
6769
 * number to be compared and on the result of converting the string-value
6770
 * of that node to a number using the number function is true.
6771
 *
6772
 * Returns 0 or 1 depending on the results of the test.
6773
 */
6774
static int
6775
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6776
93.6k
    xmlXPathObjectPtr arg, double f, int neq) {
6777
93.6k
  int i, ret=0;
6778
93.6k
  xmlNodeSetPtr ns;
6779
93.6k
  xmlChar *str2;
6780
93.6k
  xmlXPathObjectPtr val;
6781
93.6k
  double v;
6782
6783
93.6k
    if ((arg == NULL) ||
6784
93.6k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6785
0
        return(0);
6786
6787
93.6k
    ns = arg->nodesetval;
6788
93.6k
    if (ns != NULL) {
6789
141k
  for (i=0;i<ns->nodeNr;i++) {
6790
53.9k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6791
53.9k
      if (str2 != NULL) {
6792
53.2k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6793
53.2k
    xmlFree(str2);
6794
53.2k
    xmlXPathNumberFunction(ctxt, 1);
6795
53.2k
                CHECK_ERROR0;
6796
53.2k
    val = valuePop(ctxt);
6797
53.2k
    v = val->floatval;
6798
53.2k
    xmlXPathReleaseObject(ctxt->context, val);
6799
53.2k
    if (!xmlXPathIsNaN(v)) {
6800
4.07k
        if ((!neq) && (v==f)) {
6801
1.23k
      ret = 1;
6802
1.23k
      break;
6803
2.83k
        } else if ((neq) && (v!=f)) {
6804
277
      ret = 1;
6805
277
      break;
6806
277
        }
6807
49.1k
    } else { /* NaN is unequal to any value */
6808
49.1k
        if (neq)
6809
34.5k
      ret = 1;
6810
49.1k
    }
6811
53.2k
      }
6812
53.9k
  }
6813
89.5k
    }
6814
6815
93.6k
    return(ret);
6816
93.6k
}
6817
6818
6819
/**
6820
 * xmlXPathEqualNodeSets:
6821
 * @arg1:  first nodeset object argument
6822
 * @arg2:  second nodeset object argument
6823
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6824
 *
6825
 * Implement the equal / not equal operation on XPath nodesets:
6826
 * @arg1 == @arg2  or  @arg1 != @arg2
6827
 * If both objects to be compared are node-sets, then the comparison
6828
 * will be true if and only if there is a node in the first node-set and
6829
 * a node in the second node-set such that the result of performing the
6830
 * comparison on the string-values of the two nodes is true.
6831
 *
6832
 * (needless to say, this is a costly operation)
6833
 *
6834
 * Returns 0 or 1 depending on the results of the test.
6835
 */
6836
static int
6837
83.4k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6838
83.4k
    int i, j;
6839
83.4k
    unsigned int *hashs1;
6840
83.4k
    unsigned int *hashs2;
6841
83.4k
    xmlChar **values1;
6842
83.4k
    xmlChar **values2;
6843
83.4k
    int ret = 0;
6844
83.4k
    xmlNodeSetPtr ns1;
6845
83.4k
    xmlNodeSetPtr ns2;
6846
6847
83.4k
    if ((arg1 == NULL) ||
6848
83.4k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6849
0
        return(0);
6850
83.4k
    if ((arg2 == NULL) ||
6851
83.4k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6852
0
        return(0);
6853
6854
83.4k
    ns1 = arg1->nodesetval;
6855
83.4k
    ns2 = arg2->nodesetval;
6856
6857
83.4k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6858
29.3k
  return(0);
6859
54.1k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6860
18.8k
  return(0);
6861
6862
    /*
6863
     * for equal, check if there is a node pertaining to both sets
6864
     */
6865
35.3k
    if (neq == 0)
6866
77.3k
  for (i = 0;i < ns1->nodeNr;i++)
6867
120k
      for (j = 0;j < ns2->nodeNr;j++)
6868
61.6k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6869
2.09k
        return(1);
6870
6871
33.2k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6872
33.2k
    if (values1 == NULL) {
6873
        /* TODO: Propagate memory error. */
6874
302
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6875
302
  return(0);
6876
302
    }
6877
32.9k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6878
32.9k
    if (hashs1 == NULL) {
6879
        /* TODO: Propagate memory error. */
6880
6
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6881
6
  xmlFree(values1);
6882
6
  return(0);
6883
6
    }
6884
32.9k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6885
32.9k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6886
32.9k
    if (values2 == NULL) {
6887
        /* TODO: Propagate memory error. */
6888
5
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6889
5
  xmlFree(hashs1);
6890
5
  xmlFree(values1);
6891
5
  return(0);
6892
5
    }
6893
32.9k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6894
32.9k
    if (hashs2 == NULL) {
6895
        /* TODO: Propagate memory error. */
6896
7
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6897
7
  xmlFree(hashs1);
6898
7
  xmlFree(values1);
6899
7
  xmlFree(values2);
6900
7
  return(0);
6901
7
    }
6902
32.9k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6903
83.2k
    for (i = 0;i < ns1->nodeNr;i++) {
6904
70.0k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6905
121k
  for (j = 0;j < ns2->nodeNr;j++) {
6906
70.7k
      if (i == 0)
6907
33.5k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6908
70.7k
      if (hashs1[i] != hashs2[j]) {
6909
64.6k
    if (neq) {
6910
15.7k
        ret = 1;
6911
15.7k
        break;
6912
15.7k
    }
6913
64.6k
      }
6914
6.11k
      else {
6915
6.11k
    if (values1[i] == NULL)
6916
5.91k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6917
6.11k
    if (values2[j] == NULL)
6918
5.47k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6919
6.11k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6920
6.11k
    if (ret)
6921
3.91k
        break;
6922
6.11k
      }
6923
70.7k
  }
6924
70.0k
  if (ret)
6925
19.6k
      break;
6926
70.0k
    }
6927
108k
    for (i = 0;i < ns1->nodeNr;i++)
6928
75.2k
  if (values1[i] != NULL)
6929
5.89k
      xmlFree(values1[i]);
6930
86.7k
    for (j = 0;j < ns2->nodeNr;j++)
6931
53.8k
  if (values2[j] != NULL)
6932
5.45k
      xmlFree(values2[j]);
6933
32.9k
    xmlFree(values1);
6934
32.9k
    xmlFree(values2);
6935
32.9k
    xmlFree(hashs1);
6936
32.9k
    xmlFree(hashs2);
6937
32.9k
    return(ret);
6938
32.9k
}
6939
6940
static int
6941
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6942
325k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6943
325k
    int ret = 0;
6944
    /*
6945
     *At this point we are assured neither arg1 nor arg2
6946
     *is a nodeset, so we can just pick the appropriate routine.
6947
     */
6948
325k
    switch (arg1->type) {
6949
0
        case XPATH_UNDEFINED:
6950
#ifdef DEBUG_EXPR
6951
      xmlGenericError(xmlGenericErrorContext,
6952
        "Equal: undefined\n");
6953
#endif
6954
0
      break;
6955
198k
        case XPATH_BOOLEAN:
6956
198k
      switch (arg2->type) {
6957
0
          case XPATH_UNDEFINED:
6958
#ifdef DEBUG_EXPR
6959
        xmlGenericError(xmlGenericErrorContext,
6960
          "Equal: undefined\n");
6961
#endif
6962
0
        break;
6963
31.9k
    case XPATH_BOOLEAN:
6964
#ifdef DEBUG_EXPR
6965
        xmlGenericError(xmlGenericErrorContext,
6966
          "Equal: %d boolean %d \n",
6967
          arg1->boolval, arg2->boolval);
6968
#endif
6969
31.9k
        ret = (arg1->boolval == arg2->boolval);
6970
31.9k
        break;
6971
162k
    case XPATH_NUMBER:
6972
162k
        ret = (arg1->boolval ==
6973
162k
         xmlXPathCastNumberToBoolean(arg2->floatval));
6974
162k
        break;
6975
4.19k
    case XPATH_STRING:
6976
4.19k
        if ((arg2->stringval == NULL) ||
6977
4.19k
      (arg2->stringval[0] == 0)) ret = 0;
6978
3.21k
        else
6979
3.21k
      ret = 1;
6980
4.19k
        ret = (arg1->boolval == ret);
6981
4.19k
        break;
6982
10
    case XPATH_USERS:
6983
#ifdef LIBXML_XPTR_LOCS_ENABLED
6984
    case XPATH_POINT:
6985
    case XPATH_RANGE:
6986
    case XPATH_LOCATIONSET:
6987
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6988
10
        TODO
6989
10
        break;
6990
0
    case XPATH_NODESET:
6991
0
    case XPATH_XSLT_TREE:
6992
0
        break;
6993
198k
      }
6994
198k
      break;
6995
198k
        case XPATH_NUMBER:
6996
125k
      switch (arg2->type) {
6997
0
          case XPATH_UNDEFINED:
6998
#ifdef DEBUG_EXPR
6999
        xmlGenericError(xmlGenericErrorContext,
7000
          "Equal: undefined\n");
7001
#endif
7002
0
        break;
7003
17.7k
    case XPATH_BOOLEAN:
7004
17.7k
        ret = (arg2->boolval==
7005
17.7k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7006
17.7k
        break;
7007
31.9k
    case XPATH_STRING:
7008
31.9k
        valuePush(ctxt, arg2);
7009
31.9k
        xmlXPathNumberFunction(ctxt, 1);
7010
31.9k
        arg2 = valuePop(ctxt);
7011
31.9k
                    if (ctxt->error)
7012
1
                        break;
7013
                    /* Falls through. */
7014
107k
    case XPATH_NUMBER:
7015
        /* Hand check NaN and Infinity equalities */
7016
107k
        if (xmlXPathIsNaN(arg1->floatval) ||
7017
107k
          xmlXPathIsNaN(arg2->floatval)) {
7018
87.4k
            ret = 0;
7019
87.4k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020
289
            if (xmlXPathIsInf(arg2->floatval) == 1)
7021
78
          ret = 1;
7022
211
      else
7023
211
          ret = 0;
7024
19.8k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025
3.24k
      if (xmlXPathIsInf(arg2->floatval) == -1)
7026
105
          ret = 1;
7027
3.13k
      else
7028
3.13k
          ret = 0;
7029
16.6k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030
78
      if (xmlXPathIsInf(arg1->floatval) == 1)
7031
0
          ret = 1;
7032
78
      else
7033
78
          ret = 0;
7034
16.5k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035
134
      if (xmlXPathIsInf(arg1->floatval) == -1)
7036
0
          ret = 1;
7037
134
      else
7038
134
          ret = 0;
7039
16.4k
        } else {
7040
16.4k
            ret = (arg1->floatval == arg2->floatval);
7041
16.4k
        }
7042
107k
        break;
7043
21
    case XPATH_USERS:
7044
#ifdef LIBXML_XPTR_LOCS_ENABLED
7045
    case XPATH_POINT:
7046
    case XPATH_RANGE:
7047
    case XPATH_LOCATIONSET:
7048
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7049
21
        TODO
7050
21
        break;
7051
0
    case XPATH_NODESET:
7052
0
    case XPATH_XSLT_TREE:
7053
0
        break;
7054
125k
      }
7055
125k
      break;
7056
125k
        case XPATH_STRING:
7057
1.48k
      switch (arg2->type) {
7058
0
          case XPATH_UNDEFINED:
7059
#ifdef DEBUG_EXPR
7060
        xmlGenericError(xmlGenericErrorContext,
7061
          "Equal: undefined\n");
7062
#endif
7063
0
        break;
7064
227
    case XPATH_BOOLEAN:
7065
227
        if ((arg1->stringval == NULL) ||
7066
227
      (arg1->stringval[0] == 0)) ret = 0;
7067
135
        else
7068
135
      ret = 1;
7069
227
        ret = (arg2->boolval == ret);
7070
227
        break;
7071
497
    case XPATH_STRING:
7072
497
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7073
497
        break;
7074
759
    case XPATH_NUMBER:
7075
759
        valuePush(ctxt, arg1);
7076
759
        xmlXPathNumberFunction(ctxt, 1);
7077
759
        arg1 = valuePop(ctxt);
7078
759
                    if (ctxt->error)
7079
2
                        break;
7080
        /* Hand check NaN and Infinity equalities */
7081
757
        if (xmlXPathIsNaN(arg1->floatval) ||
7082
757
          xmlXPathIsNaN(arg2->floatval)) {
7083
735
            ret = 0;
7084
735
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7085
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7086
0
          ret = 1;
7087
0
      else
7088
0
          ret = 0;
7089
22
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7090
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7091
0
          ret = 1;
7092
0
      else
7093
0
          ret = 0;
7094
22
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7095
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7096
0
          ret = 1;
7097
0
      else
7098
0
          ret = 0;
7099
22
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7100
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7101
0
          ret = 1;
7102
0
      else
7103
0
          ret = 0;
7104
22
        } else {
7105
22
            ret = (arg1->floatval == arg2->floatval);
7106
22
        }
7107
757
        break;
7108
0
    case XPATH_USERS:
7109
#ifdef LIBXML_XPTR_LOCS_ENABLED
7110
    case XPATH_POINT:
7111
    case XPATH_RANGE:
7112
    case XPATH_LOCATIONSET:
7113
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7114
0
        TODO
7115
0
        break;
7116
0
    case XPATH_NODESET:
7117
0
    case XPATH_XSLT_TREE:
7118
0
        break;
7119
1.48k
      }
7120
1.48k
      break;
7121
1.48k
        case XPATH_USERS:
7122
#ifdef LIBXML_XPTR_LOCS_ENABLED
7123
  case XPATH_POINT:
7124
  case XPATH_RANGE:
7125
  case XPATH_LOCATIONSET:
7126
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7127
0
      TODO
7128
0
      break;
7129
0
  case XPATH_NODESET:
7130
0
  case XPATH_XSLT_TREE:
7131
0
      break;
7132
325k
    }
7133
325k
    xmlXPathReleaseObject(ctxt->context, arg1);
7134
325k
    xmlXPathReleaseObject(ctxt->context, arg2);
7135
325k
    return(ret);
7136
325k
}
7137
7138
/**
7139
 * xmlXPathEqualValues:
7140
 * @ctxt:  the XPath Parser context
7141
 *
7142
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7143
 *
7144
 * Returns 0 or 1 depending on the results of the test.
7145
 */
7146
int
7147
403k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7148
403k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7149
403k
    int ret = 0;
7150
7151
403k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7152
403k
    arg2 = valuePop(ctxt);
7153
403k
    arg1 = valuePop(ctxt);
7154
403k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7155
0
  if (arg1 != NULL)
7156
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7157
0
  else
7158
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7159
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7160
0
    }
7161
7162
403k
    if (arg1 == arg2) {
7163
#ifdef DEBUG_EXPR
7164
        xmlGenericError(xmlGenericErrorContext,
7165
    "Equal: by pointer\n");
7166
#endif
7167
0
  xmlXPathFreeObject(arg1);
7168
0
        return(1);
7169
0
    }
7170
7171
    /*
7172
     *If either argument is a nodeset, it's a 'special case'
7173
     */
7174
403k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7175
403k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7176
  /*
7177
   *Hack it to assure arg1 is the nodeset
7178
   */
7179
154k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7180
41.2k
    argtmp = arg2;
7181
41.2k
    arg2 = arg1;
7182
41.2k
    arg1 = argtmp;
7183
41.2k
  }
7184
154k
  switch (arg2->type) {
7185
0
      case XPATH_UNDEFINED:
7186
#ifdef DEBUG_EXPR
7187
    xmlGenericError(xmlGenericErrorContext,
7188
      "Equal: undefined\n");
7189
#endif
7190
0
    break;
7191
45.1k
      case XPATH_NODESET:
7192
54.7k
      case XPATH_XSLT_TREE:
7193
54.7k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7194
54.7k
    break;
7195
40.3k
      case XPATH_BOOLEAN:
7196
40.3k
    if ((arg1->nodesetval == NULL) ||
7197
40.3k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7198
5.51k
    else
7199
5.51k
        ret = 1;
7200
40.3k
    ret = (ret == arg2->boolval);
7201
40.3k
    break;
7202
36.7k
      case XPATH_NUMBER:
7203
36.7k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7204
36.7k
    break;
7205
22.9k
      case XPATH_STRING:
7206
22.9k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7207
22.9k
    break;
7208
1
      case XPATH_USERS:
7209
#ifdef LIBXML_XPTR_LOCS_ENABLED
7210
      case XPATH_POINT:
7211
      case XPATH_RANGE:
7212
      case XPATH_LOCATIONSET:
7213
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7214
1
    TODO
7215
1
    break;
7216
154k
  }
7217
154k
  xmlXPathReleaseObject(ctxt->context, arg1);
7218
154k
  xmlXPathReleaseObject(ctxt->context, arg2);
7219
154k
  return(ret);
7220
154k
    }
7221
7222
248k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223
403k
}
7224
7225
/**
7226
 * xmlXPathNotEqualValues:
7227
 * @ctxt:  the XPath Parser context
7228
 *
7229
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7230
 *
7231
 * Returns 0 or 1 depending on the results of the test.
7232
 */
7233
int
7234
282k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7235
282k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7236
282k
    int ret = 0;
7237
7238
282k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7239
282k
    arg2 = valuePop(ctxt);
7240
282k
    arg1 = valuePop(ctxt);
7241
282k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7242
0
  if (arg1 != NULL)
7243
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7244
0
  else
7245
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7246
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7247
0
    }
7248
7249
282k
    if (arg1 == arg2) {
7250
#ifdef DEBUG_EXPR
7251
        xmlGenericError(xmlGenericErrorContext,
7252
    "NotEqual: by pointer\n");
7253
#endif
7254
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7255
0
        return(0);
7256
0
    }
7257
7258
    /*
7259
     *If either argument is a nodeset, it's a 'special case'
7260
     */
7261
282k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7262
282k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7263
  /*
7264
   *Hack it to assure arg1 is the nodeset
7265
   */
7266
204k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7267
169k
    argtmp = arg2;
7268
169k
    arg2 = arg1;
7269
169k
    arg1 = argtmp;
7270
169k
  }
7271
204k
  switch (arg2->type) {
7272
0
      case XPATH_UNDEFINED:
7273
#ifdef DEBUG_EXPR
7274
    xmlGenericError(xmlGenericErrorContext,
7275
      "NotEqual: undefined\n");
7276
#endif
7277
0
    break;
7278
28.5k
      case XPATH_NODESET:
7279
28.7k
      case XPATH_XSLT_TREE:
7280
28.7k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7281
28.7k
    break;
7282
118k
      case XPATH_BOOLEAN:
7283
118k
    if ((arg1->nodesetval == NULL) ||
7284
118k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7285
104k
    else
7286
104k
        ret = 1;
7287
118k
    ret = (ret != arg2->boolval);
7288
118k
    break;
7289
56.8k
      case XPATH_NUMBER:
7290
56.8k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7291
56.8k
    break;
7292
746
      case XPATH_STRING:
7293
746
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7294
746
    break;
7295
0
      case XPATH_USERS:
7296
#ifdef LIBXML_XPTR_LOCS_ENABLED
7297
      case XPATH_POINT:
7298
      case XPATH_RANGE:
7299
      case XPATH_LOCATIONSET:
7300
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7301
0
    TODO
7302
0
    break;
7303
204k
  }
7304
204k
  xmlXPathReleaseObject(ctxt->context, arg1);
7305
204k
  xmlXPathReleaseObject(ctxt->context, arg2);
7306
204k
  return(ret);
7307
204k
    }
7308
7309
77.3k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7310
282k
}
7311
7312
/**
7313
 * xmlXPathCompareValues:
7314
 * @ctxt:  the XPath Parser context
7315
 * @inf:  less than (1) or greater than (0)
7316
 * @strict:  is the comparison strict
7317
 *
7318
 * Implement the compare operation on XPath objects:
7319
 *     @arg1 < @arg2    (1, 1, ...
7320
 *     @arg1 <= @arg2   (1, 0, ...
7321
 *     @arg1 > @arg2    (0, 1, ...
7322
 *     @arg1 >= @arg2   (0, 0, ...
7323
 *
7324
 * When neither object to be compared is a node-set and the operator is
7325
 * <=, <, >=, >, then the objects are compared by converted both objects
7326
 * to numbers and comparing the numbers according to IEEE 754. The <
7327
 * comparison will be true if and only if the first number is less than the
7328
 * second number. The <= comparison will be true if and only if the first
7329
 * number is less than or equal to the second number. The > comparison
7330
 * will be true if and only if the first number is greater than the second
7331
 * number. The >= comparison will be true if and only if the first number
7332
 * is greater than or equal to the second number.
7333
 *
7334
 * Returns 1 if the comparison succeeded, 0 if it failed
7335
 */
7336
int
7337
860k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7338
860k
    int ret = 0, arg1i = 0, arg2i = 0;
7339
860k
    xmlXPathObjectPtr arg1, arg2;
7340
7341
860k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7342
860k
    arg2 = valuePop(ctxt);
7343
860k
    arg1 = valuePop(ctxt);
7344
860k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7345
331
  if (arg1 != NULL)
7346
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7347
331
  else
7348
331
      xmlXPathReleaseObject(ctxt->context, arg2);
7349
331
  XP_ERROR0(XPATH_INVALID_OPERAND);
7350
0
    }
7351
7352
860k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7353
860k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7354
  /*
7355
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7356
   * are not freed from within this routine; they will be freed from the
7357
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7358
   */
7359
597k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7360
597k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7361
284k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7362
312k
  } else {
7363
312k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7364
121k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7365
121k
                                arg1, arg2);
7366
190k
      } else {
7367
190k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7368
190k
                                arg2, arg1);
7369
190k
      }
7370
312k
  }
7371
597k
  return(ret);
7372
597k
    }
7373
7374
262k
    if (arg1->type != XPATH_NUMBER) {
7375
155k
  valuePush(ctxt, arg1);
7376
155k
  xmlXPathNumberFunction(ctxt, 1);
7377
155k
  arg1 = valuePop(ctxt);
7378
155k
    }
7379
262k
    if (arg2->type != XPATH_NUMBER) {
7380
143k
  valuePush(ctxt, arg2);
7381
143k
  xmlXPathNumberFunction(ctxt, 1);
7382
143k
  arg2 = valuePop(ctxt);
7383
143k
    }
7384
262k
    if (ctxt->error)
7385
291
        goto error;
7386
    /*
7387
     * Add tests for infinity and nan
7388
     * => feedback on 3.4 for Inf and NaN
7389
     */
7390
    /* Hand check NaN and Infinity comparisons */
7391
262k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7392
91.9k
  ret=0;
7393
170k
    } else {
7394
170k
  arg1i=xmlXPathIsInf(arg1->floatval);
7395
170k
  arg2i=xmlXPathIsInf(arg2->floatval);
7396
170k
  if (inf && strict) {
7397
141k
      if ((arg1i == -1 && arg2i != -1) ||
7398
141k
    (arg2i == 1 && arg1i != 1)) {
7399
0
    ret = 1;
7400
141k
      } else if (arg1i == 0 && arg2i == 0) {
7401
140k
    ret = (arg1->floatval < arg2->floatval);
7402
140k
      } else {
7403
850
    ret = 0;
7404
850
      }
7405
141k
  }
7406
29.1k
  else if (inf && !strict) {
7407
353
      if (arg1i == -1 || arg2i == 1) {
7408
45
    ret = 1;
7409
308
      } else if (arg1i == 0 && arg2i == 0) {
7410
269
    ret = (arg1->floatval <= arg2->floatval);
7411
269
      } else {
7412
39
    ret = 0;
7413
39
      }
7414
353
  }
7415
28.8k
  else if (!inf && strict) {
7416
20.9k
      if ((arg1i == 1 && arg2i != 1) ||
7417
20.9k
    (arg2i == -1 && arg1i != -1)) {
7418
411
    ret = 1;
7419
20.5k
      } else if (arg1i == 0 && arg2i == 0) {
7420
17.4k
    ret = (arg1->floatval > arg2->floatval);
7421
17.4k
      } else {
7422
3.11k
    ret = 0;
7423
3.11k
      }
7424
20.9k
  }
7425
7.84k
  else if (!inf && !strict) {
7426
7.84k
      if (arg1i == 1 || arg2i == -1) {
7427
4.10k
    ret = 1;
7428
4.10k
      } else if (arg1i == 0 && arg2i == 0) {
7429
3.37k
    ret = (arg1->floatval >= arg2->floatval);
7430
3.37k
      } else {
7431
364
    ret = 0;
7432
364
      }
7433
7.84k
  }
7434
170k
    }
7435
262k
error:
7436
262k
    xmlXPathReleaseObject(ctxt->context, arg1);
7437
262k
    xmlXPathReleaseObject(ctxt->context, arg2);
7438
262k
    return(ret);
7439
262k
}
7440
7441
/**
7442
 * xmlXPathValueFlipSign:
7443
 * @ctxt:  the XPath Parser context
7444
 *
7445
 * Implement the unary - operation on an XPath object
7446
 * The numeric operators convert their operands to numbers as if
7447
 * by calling the number function.
7448
 */
7449
void
7450
595k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7451
595k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7452
595k
    CAST_TO_NUMBER;
7453
595k
    CHECK_TYPE(XPATH_NUMBER);
7454
594k
    ctxt->value->floatval = -ctxt->value->floatval;
7455
594k
}
7456
7457
/**
7458
 * xmlXPathAddValues:
7459
 * @ctxt:  the XPath Parser context
7460
 *
7461
 * Implement the add operation on XPath objects:
7462
 * The numeric operators convert their operands to numbers as if
7463
 * by calling the number function.
7464
 */
7465
void
7466
135k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7467
135k
    xmlXPathObjectPtr arg;
7468
135k
    double val;
7469
7470
135k
    arg = valuePop(ctxt);
7471
135k
    if (arg == NULL)
7472
135k
  XP_ERROR(XPATH_INVALID_OPERAND);
7473
135k
    val = xmlXPathCastToNumber(arg);
7474
135k
    xmlXPathReleaseObject(ctxt->context, arg);
7475
135k
    CAST_TO_NUMBER;
7476
135k
    CHECK_TYPE(XPATH_NUMBER);
7477
135k
    ctxt->value->floatval += val;
7478
135k
}
7479
7480
/**
7481
 * xmlXPathSubValues:
7482
 * @ctxt:  the XPath Parser context
7483
 *
7484
 * Implement the subtraction operation on XPath objects:
7485
 * The numeric operators convert their operands to numbers as if
7486
 * by calling the number function.
7487
 */
7488
void
7489
545k
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7490
545k
    xmlXPathObjectPtr arg;
7491
545k
    double val;
7492
7493
545k
    arg = valuePop(ctxt);
7494
545k
    if (arg == NULL)
7495
545k
  XP_ERROR(XPATH_INVALID_OPERAND);
7496
545k
    val = xmlXPathCastToNumber(arg);
7497
545k
    xmlXPathReleaseObject(ctxt->context, arg);
7498
545k
    CAST_TO_NUMBER;
7499
545k
    CHECK_TYPE(XPATH_NUMBER);
7500
545k
    ctxt->value->floatval -= val;
7501
545k
}
7502
7503
/**
7504
 * xmlXPathMultValues:
7505
 * @ctxt:  the XPath Parser context
7506
 *
7507
 * Implement the multiply operation on XPath objects:
7508
 * The numeric operators convert their operands to numbers as if
7509
 * by calling the number function.
7510
 */
7511
void
7512
162k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7513
162k
    xmlXPathObjectPtr arg;
7514
162k
    double val;
7515
7516
162k
    arg = valuePop(ctxt);
7517
162k
    if (arg == NULL)
7518
162k
  XP_ERROR(XPATH_INVALID_OPERAND);
7519
162k
    val = xmlXPathCastToNumber(arg);
7520
162k
    xmlXPathReleaseObject(ctxt->context, arg);
7521
162k
    CAST_TO_NUMBER;
7522
162k
    CHECK_TYPE(XPATH_NUMBER);
7523
162k
    ctxt->value->floatval *= val;
7524
162k
}
7525
7526
/**
7527
 * xmlXPathDivValues:
7528
 * @ctxt:  the XPath Parser context
7529
 *
7530
 * Implement the div operation on XPath objects @arg1 / @arg2:
7531
 * The numeric operators convert their operands to numbers as if
7532
 * by calling the number function.
7533
 */
7534
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7535
void
7536
1.25k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7537
1.25k
    xmlXPathObjectPtr arg;
7538
1.25k
    double val;
7539
7540
1.25k
    arg = valuePop(ctxt);
7541
1.25k
    if (arg == NULL)
7542
1.25k
  XP_ERROR(XPATH_INVALID_OPERAND);
7543
1.25k
    val = xmlXPathCastToNumber(arg);
7544
1.25k
    xmlXPathReleaseObject(ctxt->context, arg);
7545
1.25k
    CAST_TO_NUMBER;
7546
1.25k
    CHECK_TYPE(XPATH_NUMBER);
7547
1.25k
    ctxt->value->floatval /= val;
7548
1.25k
}
7549
7550
/**
7551
 * xmlXPathModValues:
7552
 * @ctxt:  the XPath Parser context
7553
 *
7554
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7555
 * The numeric operators convert their operands to numbers as if
7556
 * by calling the number function.
7557
 */
7558
void
7559
156k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7560
156k
    xmlXPathObjectPtr arg;
7561
156k
    double arg1, arg2;
7562
7563
156k
    arg = valuePop(ctxt);
7564
156k
    if (arg == NULL)
7565
156k
  XP_ERROR(XPATH_INVALID_OPERAND);
7566
156k
    arg2 = xmlXPathCastToNumber(arg);
7567
156k
    xmlXPathReleaseObject(ctxt->context, arg);
7568
156k
    CAST_TO_NUMBER;
7569
156k
    CHECK_TYPE(XPATH_NUMBER);
7570
156k
    arg1 = ctxt->value->floatval;
7571
156k
    if (arg2 == 0)
7572
4.42k
  ctxt->value->floatval = xmlXPathNAN;
7573
151k
    else {
7574
151k
  ctxt->value->floatval = fmod(arg1, arg2);
7575
151k
    }
7576
156k
}
7577
7578
/************************************************************************
7579
 *                  *
7580
 *    The traversal functions         *
7581
 *                  *
7582
 ************************************************************************/
7583
7584
/*
7585
 * A traversal function enumerates nodes along an axis.
7586
 * Initially it must be called with NULL, and it indicates
7587
 * termination on the axis by returning NULL.
7588
 */
7589
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7590
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7591
7592
/*
7593
 * xmlXPathTraversalFunctionExt:
7594
 * A traversal function enumerates nodes along an axis.
7595
 * Initially it must be called with NULL, and it indicates
7596
 * termination on the axis by returning NULL.
7597
 * The context node of the traversal is specified via @contextNode.
7598
 */
7599
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7600
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7601
7602
/*
7603
 * xmlXPathNodeSetMergeFunction:
7604
 * Used for merging node sets in xmlXPathCollectAndTest().
7605
 */
7606
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7607
        (xmlNodeSetPtr, xmlNodeSetPtr);
7608
7609
7610
/**
7611
 * xmlXPathNextSelf:
7612
 * @ctxt:  the XPath Parser context
7613
 * @cur:  the current node in the traversal
7614
 *
7615
 * Traversal function for the "self" direction
7616
 * The self axis contains just the context node itself
7617
 *
7618
 * Returns the next element following that axis
7619
 */
7620
xmlNodePtr
7621
910
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7622
910
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7623
910
    if (cur == NULL)
7624
508
        return(ctxt->context->node);
7625
402
    return(NULL);
7626
910
}
7627
7628
/**
7629
 * xmlXPathNextChild:
7630
 * @ctxt:  the XPath Parser context
7631
 * @cur:  the current node in the traversal
7632
 *
7633
 * Traversal function for the "child" direction
7634
 * The child axis contains the children of the context node in document order.
7635
 *
7636
 * Returns the next element following that axis
7637
 */
7638
xmlNodePtr
7639
1.30M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7640
1.30M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7641
1.30M
    if (cur == NULL) {
7642
604k
  if (ctxt->context->node == NULL) return(NULL);
7643
604k
  switch (ctxt->context->node->type) {
7644
322k
            case XML_ELEMENT_NODE:
7645
511k
            case XML_TEXT_NODE:
7646
511k
            case XML_CDATA_SECTION_NODE:
7647
511k
            case XML_ENTITY_REF_NODE:
7648
511k
            case XML_ENTITY_NODE:
7649
518k
            case XML_PI_NODE:
7650
524k
            case XML_COMMENT_NODE:
7651
524k
            case XML_NOTATION_NODE:
7652
524k
            case XML_DTD_NODE:
7653
524k
    return(ctxt->context->node->children);
7654
76.0k
            case XML_DOCUMENT_NODE:
7655
76.0k
            case XML_DOCUMENT_TYPE_NODE:
7656
76.0k
            case XML_DOCUMENT_FRAG_NODE:
7657
76.0k
            case XML_HTML_DOCUMENT_NODE:
7658
76.0k
    return(((xmlDocPtr) ctxt->context->node)->children);
7659
0
      case XML_ELEMENT_DECL:
7660
0
      case XML_ATTRIBUTE_DECL:
7661
0
      case XML_ENTITY_DECL:
7662
497
            case XML_ATTRIBUTE_NODE:
7663
2.93k
      case XML_NAMESPACE_DECL:
7664
2.93k
      case XML_XINCLUDE_START:
7665
2.93k
      case XML_XINCLUDE_END:
7666
2.93k
    return(NULL);
7667
604k
  }
7668
0
  return(NULL);
7669
604k
    }
7670
704k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7671
704k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7672
0
  return(NULL);
7673
704k
    return(cur->next);
7674
704k
}
7675
7676
/**
7677
 * xmlXPathNextChildElement:
7678
 * @ctxt:  the XPath Parser context
7679
 * @cur:  the current node in the traversal
7680
 *
7681
 * Traversal function for the "child" direction and nodes of type element.
7682
 * The child axis contains the children of the context node in document order.
7683
 *
7684
 * Returns the next element following that axis
7685
 */
7686
static xmlNodePtr
7687
4.99M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7688
4.99M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7689
4.99M
    if (cur == NULL) {
7690
2.66M
  cur = ctxt->context->node;
7691
2.66M
  if (cur == NULL) return(NULL);
7692
  /*
7693
  * Get the first element child.
7694
  */
7695
2.66M
  switch (cur->type) {
7696
1.54M
            case XML_ELEMENT_NODE:
7697
1.54M
      case XML_DOCUMENT_FRAG_NODE:
7698
1.54M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7699
1.54M
            case XML_ENTITY_NODE:
7700
1.54M
    cur = cur->children;
7701
1.54M
    if (cur != NULL) {
7702
1.09M
        if (cur->type == XML_ELEMENT_NODE)
7703
266k
      return(cur);
7704
887k
        do {
7705
887k
      cur = cur->next;
7706
887k
        } while ((cur != NULL) &&
7707
887k
      (cur->type != XML_ELEMENT_NODE));
7708
832k
        return(cur);
7709
1.09M
    }
7710
450k
    return(NULL);
7711
283k
            case XML_DOCUMENT_NODE:
7712
283k
            case XML_HTML_DOCUMENT_NODE:
7713
283k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7714
827k
      default:
7715
827k
    return(NULL);
7716
2.66M
  }
7717
0
  return(NULL);
7718
2.66M
    }
7719
    /*
7720
    * Get the next sibling element node.
7721
    */
7722
2.33M
    switch (cur->type) {
7723
2.33M
  case XML_ELEMENT_NODE:
7724
2.33M
  case XML_TEXT_NODE:
7725
2.33M
  case XML_ENTITY_REF_NODE:
7726
2.33M
  case XML_ENTITY_NODE:
7727
2.33M
  case XML_CDATA_SECTION_NODE:
7728
2.33M
  case XML_PI_NODE:
7729
2.33M
  case XML_COMMENT_NODE:
7730
2.33M
  case XML_XINCLUDE_END:
7731
2.33M
      break;
7732
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7733
0
  default:
7734
0
      return(NULL);
7735
2.33M
    }
7736
2.33M
    if (cur->next != NULL) {
7737
1.67M
  if (cur->next->type == XML_ELEMENT_NODE)
7738
548k
      return(cur->next);
7739
1.12M
  cur = cur->next;
7740
1.17M
  do {
7741
1.17M
      cur = cur->next;
7742
1.17M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7743
1.12M
  return(cur);
7744
1.67M
    }
7745
656k
    return(NULL);
7746
2.33M
}
7747
7748
#if 0
7749
/**
7750
 * xmlXPathNextDescendantOrSelfElemParent:
7751
 * @ctxt:  the XPath Parser context
7752
 * @cur:  the current node in the traversal
7753
 *
7754
 * Traversal function for the "descendant-or-self" axis.
7755
 * Additionally it returns only nodes which can be parents of
7756
 * element nodes.
7757
 *
7758
 *
7759
 * Returns the next element following that axis
7760
 */
7761
static xmlNodePtr
7762
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7763
               xmlNodePtr contextNode)
7764
{
7765
    if (cur == NULL) {
7766
  if (contextNode == NULL)
7767
      return(NULL);
7768
  switch (contextNode->type) {
7769
      case XML_ELEMENT_NODE:
7770
      case XML_XINCLUDE_START:
7771
      case XML_DOCUMENT_FRAG_NODE:
7772
      case XML_DOCUMENT_NODE:
7773
      case XML_HTML_DOCUMENT_NODE:
7774
    return(contextNode);
7775
      default:
7776
    return(NULL);
7777
  }
7778
  return(NULL);
7779
    } else {
7780
  xmlNodePtr start = cur;
7781
7782
  while (cur != NULL) {
7783
      switch (cur->type) {
7784
    case XML_ELEMENT_NODE:
7785
    /* TODO: OK to have XInclude here? */
7786
    case XML_XINCLUDE_START:
7787
    case XML_DOCUMENT_FRAG_NODE:
7788
        if (cur != start)
7789
      return(cur);
7790
        if (cur->children != NULL) {
7791
      cur = cur->children;
7792
      continue;
7793
        }
7794
        break;
7795
    /* Not sure if we need those here. */
7796
    case XML_DOCUMENT_NODE:
7797
    case XML_HTML_DOCUMENT_NODE:
7798
        if (cur != start)
7799
      return(cur);
7800
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7801
    default:
7802
        break;
7803
      }
7804
7805
next_sibling:
7806
      if ((cur == NULL) || (cur == contextNode))
7807
    return(NULL);
7808
      if (cur->next != NULL) {
7809
    cur = cur->next;
7810
      } else {
7811
    cur = cur->parent;
7812
    goto next_sibling;
7813
      }
7814
  }
7815
    }
7816
    return(NULL);
7817
}
7818
#endif
7819
7820
/**
7821
 * xmlXPathNextDescendant:
7822
 * @ctxt:  the XPath Parser context
7823
 * @cur:  the current node in the traversal
7824
 *
7825
 * Traversal function for the "descendant" direction
7826
 * the descendant axis contains the descendants of the context node in document
7827
 * order; a descendant is a child or a child of a child and so on.
7828
 *
7829
 * Returns the next element following that axis
7830
 */
7831
xmlNodePtr
7832
17.1M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7833
17.1M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7834
17.1M
    if (cur == NULL) {
7835
808k
  if (ctxt->context->node == NULL)
7836
0
      return(NULL);
7837
808k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7838
808k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7839
1.36k
      return(NULL);
7840
7841
806k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7842
772k
      return(ctxt->context->doc->children);
7843
34.7k
        return(ctxt->context->node->children);
7844
806k
    }
7845
7846
16.3M
    if (cur->type == XML_NAMESPACE_DECL)
7847
0
        return(NULL);
7848
16.3M
    if (cur->children != NULL) {
7849
  /*
7850
   * Do not descend on entities declarations
7851
   */
7852
4.45M
  if (cur->children->type != XML_ENTITY_DECL) {
7853
4.45M
      cur = cur->children;
7854
      /*
7855
       * Skip DTDs
7856
       */
7857
4.45M
      if (cur->type != XML_DTD_NODE)
7858
4.45M
    return(cur);
7859
4.45M
  }
7860
4.45M
    }
7861
7862
11.8M
    if (cur == ctxt->context->node) return(NULL);
7863
7864
11.8M
    while (cur->next != NULL) {
7865
8.58M
  cur = cur->next;
7866
8.58M
  if ((cur->type != XML_ENTITY_DECL) &&
7867
8.58M
      (cur->type != XML_DTD_NODE))
7868
8.58M
      return(cur);
7869
8.58M
    }
7870
7871
5.23M
    do {
7872
5.23M
        cur = cur->parent;
7873
5.23M
  if (cur == NULL) break;
7874
5.23M
  if (cur == ctxt->context->node) return(NULL);
7875
4.38M
  if (cur->next != NULL) {
7876
2.43M
      cur = cur->next;
7877
2.43M
      return(cur);
7878
2.43M
  }
7879
4.38M
    } while (cur != NULL);
7880
0
    return(cur);
7881
3.28M
}
7882
7883
/**
7884
 * xmlXPathNextDescendantOrSelf:
7885
 * @ctxt:  the XPath Parser context
7886
 * @cur:  the current node in the traversal
7887
 *
7888
 * Traversal function for the "descendant-or-self" direction
7889
 * the descendant-or-self axis contains the context node and the descendants
7890
 * of the context node in document order; thus the context node is the first
7891
 * node on the axis, and the first child of the context node is the second node
7892
 * on the axis
7893
 *
7894
 * Returns the next element following that axis
7895
 */
7896
xmlNodePtr
7897
1.65M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7898
1.65M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7899
1.65M
    if (cur == NULL)
7900
140k
        return(ctxt->context->node);
7901
7902
1.50M
    if (ctxt->context->node == NULL)
7903
0
        return(NULL);
7904
1.50M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7905
1.50M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7906
69.0k
        return(NULL);
7907
7908
1.44M
    return(xmlXPathNextDescendant(ctxt, cur));
7909
1.50M
}
7910
7911
/**
7912
 * xmlXPathNextParent:
7913
 * @ctxt:  the XPath Parser context
7914
 * @cur:  the current node in the traversal
7915
 *
7916
 * Traversal function for the "parent" direction
7917
 * The parent axis contains the parent of the context node, if there is one.
7918
 *
7919
 * Returns the next element following that axis
7920
 */
7921
xmlNodePtr
7922
291k
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7923
291k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7924
    /*
7925
     * the parent of an attribute or namespace node is the element
7926
     * to which the attribute or namespace node is attached
7927
     * Namespace handling !!!
7928
     */
7929
291k
    if (cur == NULL) {
7930
160k
  if (ctxt->context->node == NULL) return(NULL);
7931
160k
  switch (ctxt->context->node->type) {
7932
75.3k
            case XML_ELEMENT_NODE:
7933
129k
            case XML_TEXT_NODE:
7934
129k
            case XML_CDATA_SECTION_NODE:
7935
129k
            case XML_ENTITY_REF_NODE:
7936
129k
            case XML_ENTITY_NODE:
7937
130k
            case XML_PI_NODE:
7938
131k
            case XML_COMMENT_NODE:
7939
131k
            case XML_NOTATION_NODE:
7940
131k
            case XML_DTD_NODE:
7941
131k
      case XML_ELEMENT_DECL:
7942
131k
      case XML_ATTRIBUTE_DECL:
7943
131k
      case XML_XINCLUDE_START:
7944
131k
      case XML_XINCLUDE_END:
7945
131k
      case XML_ENTITY_DECL:
7946
131k
    if (ctxt->context->node->parent == NULL)
7947
0
        return((xmlNodePtr) ctxt->context->doc);
7948
131k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7949
131k
        ((ctxt->context->node->parent->name[0] == ' ') ||
7950
103k
         (xmlStrEqual(ctxt->context->node->parent->name,
7951
103k
         BAD_CAST "fake node libxslt"))))
7952
0
        return(NULL);
7953
131k
    return(ctxt->context->node->parent);
7954
484
            case XML_ATTRIBUTE_NODE: {
7955
484
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7956
7957
484
    return(att->parent);
7958
131k
      }
7959
27.4k
            case XML_DOCUMENT_NODE:
7960
27.4k
            case XML_DOCUMENT_TYPE_NODE:
7961
27.4k
            case XML_DOCUMENT_FRAG_NODE:
7962
27.4k
            case XML_HTML_DOCUMENT_NODE:
7963
27.4k
                return(NULL);
7964
820
      case XML_NAMESPACE_DECL: {
7965
820
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7966
7967
820
    if ((ns->next != NULL) &&
7968
820
        (ns->next->type != XML_NAMESPACE_DECL))
7969
820
        return((xmlNodePtr) ns->next);
7970
0
                return(NULL);
7971
820
      }
7972
160k
  }
7973
160k
    }
7974
131k
    return(NULL);
7975
291k
}
7976
7977
/**
7978
 * xmlXPathNextAncestor:
7979
 * @ctxt:  the XPath Parser context
7980
 * @cur:  the current node in the traversal
7981
 *
7982
 * Traversal function for the "ancestor" direction
7983
 * the ancestor axis contains the ancestors of the context node; the ancestors
7984
 * of the context node consist of the parent of context node and the parent's
7985
 * parent and so on; the nodes are ordered in reverse document order; thus the
7986
 * parent is the first node on the axis, and the parent's parent is the second
7987
 * node on the axis
7988
 *
7989
 * Returns the next element following that axis
7990
 */
7991
xmlNodePtr
7992
307k
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7993
307k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7994
    /*
7995
     * the parent of an attribute or namespace node is the element
7996
     * to which the attribute or namespace node is attached
7997
     * !!!!!!!!!!!!!
7998
     */
7999
307k
    if (cur == NULL) {
8000
23.7k
  if (ctxt->context->node == NULL) return(NULL);
8001
23.7k
  switch (ctxt->context->node->type) {
8002
9.66k
            case XML_ELEMENT_NODE:
8003
22.4k
            case XML_TEXT_NODE:
8004
22.4k
            case XML_CDATA_SECTION_NODE:
8005
22.4k
            case XML_ENTITY_REF_NODE:
8006
22.4k
            case XML_ENTITY_NODE:
8007
22.9k
            case XML_PI_NODE:
8008
23.2k
            case XML_COMMENT_NODE:
8009
23.2k
      case XML_DTD_NODE:
8010
23.2k
      case XML_ELEMENT_DECL:
8011
23.2k
      case XML_ATTRIBUTE_DECL:
8012
23.2k
      case XML_ENTITY_DECL:
8013
23.2k
            case XML_NOTATION_NODE:
8014
23.2k
      case XML_XINCLUDE_START:
8015
23.2k
      case XML_XINCLUDE_END:
8016
23.2k
    if (ctxt->context->node->parent == NULL)
8017
0
        return((xmlNodePtr) ctxt->context->doc);
8018
23.2k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8019
23.2k
        ((ctxt->context->node->parent->name[0] == ' ') ||
8020
22.8k
         (xmlStrEqual(ctxt->context->node->parent->name,
8021
22.8k
         BAD_CAST "fake node libxslt"))))
8022
0
        return(NULL);
8023
23.2k
    return(ctxt->context->node->parent);
8024
0
            case XML_ATTRIBUTE_NODE: {
8025
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8026
8027
0
    return(tmp->parent);
8028
23.2k
      }
8029
488
            case XML_DOCUMENT_NODE:
8030
488
            case XML_DOCUMENT_TYPE_NODE:
8031
488
            case XML_DOCUMENT_FRAG_NODE:
8032
488
            case XML_HTML_DOCUMENT_NODE:
8033
488
                return(NULL);
8034
0
      case XML_NAMESPACE_DECL: {
8035
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8036
8037
0
    if ((ns->next != NULL) &&
8038
0
        (ns->next->type != XML_NAMESPACE_DECL))
8039
0
        return((xmlNodePtr) ns->next);
8040
    /* Bad, how did that namespace end up here ? */
8041
0
                return(NULL);
8042
0
      }
8043
23.7k
  }
8044
0
  return(NULL);
8045
23.7k
    }
8046
283k
    if (cur == ctxt->context->doc->children)
8047
29.9k
  return((xmlNodePtr) ctxt->context->doc);
8048
253k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8049
34.1k
  return(NULL);
8050
219k
    switch (cur->type) {
8051
212k
  case XML_ELEMENT_NODE:
8052
218k
  case XML_TEXT_NODE:
8053
218k
  case XML_CDATA_SECTION_NODE:
8054
218k
  case XML_ENTITY_REF_NODE:
8055
218k
  case XML_ENTITY_NODE:
8056
218k
  case XML_PI_NODE:
8057
219k
  case XML_COMMENT_NODE:
8058
219k
  case XML_NOTATION_NODE:
8059
219k
  case XML_DTD_NODE:
8060
219k
        case XML_ELEMENT_DECL:
8061
219k
        case XML_ATTRIBUTE_DECL:
8062
219k
        case XML_ENTITY_DECL:
8063
219k
  case XML_XINCLUDE_START:
8064
219k
  case XML_XINCLUDE_END:
8065
219k
      if (cur->parent == NULL)
8066
0
    return(NULL);
8067
219k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8068
219k
    ((cur->parent->name[0] == ' ') ||
8069
210k
     (xmlStrEqual(cur->parent->name,
8070
210k
            BAD_CAST "fake node libxslt"))))
8071
0
    return(NULL);
8072
219k
      return(cur->parent);
8073
0
  case XML_ATTRIBUTE_NODE: {
8074
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8075
8076
0
      return(att->parent);
8077
219k
  }
8078
0
  case XML_NAMESPACE_DECL: {
8079
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8080
8081
0
      if ((ns->next != NULL) &&
8082
0
          (ns->next->type != XML_NAMESPACE_DECL))
8083
0
          return((xmlNodePtr) ns->next);
8084
      /* Bad, how did that namespace end up here ? */
8085
0
            return(NULL);
8086
0
  }
8087
0
  case XML_DOCUMENT_NODE:
8088
0
  case XML_DOCUMENT_TYPE_NODE:
8089
0
  case XML_DOCUMENT_FRAG_NODE:
8090
0
  case XML_HTML_DOCUMENT_NODE:
8091
0
      return(NULL);
8092
219k
    }
8093
0
    return(NULL);
8094
219k
}
8095
8096
/**
8097
 * xmlXPathNextAncestorOrSelf:
8098
 * @ctxt:  the XPath Parser context
8099
 * @cur:  the current node in the traversal
8100
 *
8101
 * Traversal function for the "ancestor-or-self" direction
8102
 * he ancestor-or-self axis contains the context node and ancestors of
8103
 * the context node in reverse document order; thus the context node is
8104
 * the first node on the axis, and the context node's parent the second;
8105
 * parent here is defined the same as with the parent axis.
8106
 *
8107
 * Returns the next element following that axis
8108
 */
8109
xmlNodePtr
8110
59.8k
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8111
59.8k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8112
59.8k
    if (cur == NULL)
8113
10.8k
        return(ctxt->context->node);
8114
49.0k
    return(xmlXPathNextAncestor(ctxt, cur));
8115
59.8k
}
8116
8117
/**
8118
 * xmlXPathNextFollowingSibling:
8119
 * @ctxt:  the XPath Parser context
8120
 * @cur:  the current node in the traversal
8121
 *
8122
 * Traversal function for the "following-sibling" direction
8123
 * The following-sibling axis contains the following siblings of the context
8124
 * node in document order.
8125
 *
8126
 * Returns the next element following that axis
8127
 */
8128
xmlNodePtr
8129
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8130
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8131
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8132
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8133
0
  return(NULL);
8134
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8135
0
        return(NULL);
8136
0
    if (cur == NULL)
8137
0
        return(ctxt->context->node->next);
8138
0
    return(cur->next);
8139
0
}
8140
8141
/**
8142
 * xmlXPathNextPrecedingSibling:
8143
 * @ctxt:  the XPath Parser context
8144
 * @cur:  the current node in the traversal
8145
 *
8146
 * Traversal function for the "preceding-sibling" direction
8147
 * The preceding-sibling axis contains the preceding siblings of the context
8148
 * node in reverse document order; the first preceding sibling is first on the
8149
 * axis; the sibling preceding that node is the second on the axis and so on.
8150
 *
8151
 * Returns the next element following that axis
8152
 */
8153
xmlNodePtr
8154
218M
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8155
218M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8156
218M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8157
218M
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8158
750
  return(NULL);
8159
218M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8160
0
        return(NULL);
8161
218M
    if (cur == NULL)
8162
0
        return(ctxt->context->node->prev);
8163
218M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8164
0
  cur = cur->prev;
8165
0
  if (cur == NULL)
8166
0
      return(ctxt->context->node->prev);
8167
0
    }
8168
218M
    return(cur->prev);
8169
218M
}
8170
8171
/**
8172
 * xmlXPathNextFollowing:
8173
 * @ctxt:  the XPath Parser context
8174
 * @cur:  the current node in the traversal
8175
 *
8176
 * Traversal function for the "following" direction
8177
 * The following axis contains all nodes in the same document as the context
8178
 * node that are after the context node in document order, excluding any
8179
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8180
 * are ordered in document order
8181
 *
8182
 * Returns the next element following that axis
8183
 */
8184
xmlNodePtr
8185
243k
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8186
243k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8187
243k
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8188
243k
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8189
42.8k
        return(cur->children);
8190
8191
200k
    if (cur == NULL) {
8192
4.16k
        cur = ctxt->context->node;
8193
4.16k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8194
0
            cur = cur->parent;
8195
4.16k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8196
3.85k
            xmlNsPtr ns = (xmlNsPtr) cur;
8197
8198
3.85k
            if ((ns->next == NULL) ||
8199
3.85k
                (ns->next->type == XML_NAMESPACE_DECL))
8200
0
                return (NULL);
8201
3.85k
            cur = (xmlNodePtr) ns->next;
8202
3.85k
        }
8203
4.16k
    }
8204
200k
    if (cur == NULL) return(NULL) ; /* ERROR */
8205
200k
    if (cur->next != NULL) return(cur->next) ;
8206
53.7k
    do {
8207
53.7k
        cur = cur->parent;
8208
53.7k
        if (cur == NULL) break;
8209
53.4k
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8210
49.6k
        if (cur->next != NULL) return(cur->next);
8211
49.6k
    } while (cur != NULL);
8212
281
    return(cur);
8213
40.7k
}
8214
8215
/*
8216
 * xmlXPathIsAncestor:
8217
 * @ancestor:  the ancestor node
8218
 * @node:  the current node
8219
 *
8220
 * Check that @ancestor is a @node's ancestor
8221
 *
8222
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8223
 */
8224
static int
8225
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8226
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8227
0
    if (node->type == XML_NAMESPACE_DECL)
8228
0
        return(0);
8229
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8230
0
        return(0);
8231
    /* nodes need to be in the same document */
8232
0
    if (ancestor->doc != node->doc) return(0);
8233
    /* avoid searching if ancestor or node is the root node */
8234
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8235
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8236
0
    while (node->parent != NULL) {
8237
0
        if (node->parent == ancestor)
8238
0
            return(1);
8239
0
  node = node->parent;
8240
0
    }
8241
0
    return(0);
8242
0
}
8243
8244
/**
8245
 * xmlXPathNextPreceding:
8246
 * @ctxt:  the XPath Parser context
8247
 * @cur:  the current node in the traversal
8248
 *
8249
 * Traversal function for the "preceding" direction
8250
 * the preceding axis contains all nodes in the same document as the context
8251
 * node that are before the context node in document order, excluding any
8252
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253
 * ordered in reverse document order
8254
 *
8255
 * Returns the next element following that axis
8256
 */
8257
xmlNodePtr
8258
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8259
0
{
8260
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8261
0
    if (cur == NULL) {
8262
0
        cur = ctxt->context->node;
8263
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8264
0
            cur = cur->parent;
8265
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8266
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8267
8268
0
            if ((ns->next == NULL) ||
8269
0
                (ns->next->type == XML_NAMESPACE_DECL))
8270
0
                return (NULL);
8271
0
            cur = (xmlNodePtr) ns->next;
8272
0
        }
8273
0
    }
8274
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8275
0
  return (NULL);
8276
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8277
0
  cur = cur->prev;
8278
0
    do {
8279
0
        if (cur->prev != NULL) {
8280
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8281
0
            return (cur);
8282
0
        }
8283
8284
0
        cur = cur->parent;
8285
0
        if (cur == NULL)
8286
0
            return (NULL);
8287
0
        if (cur == ctxt->context->doc->children)
8288
0
            return (NULL);
8289
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8290
0
    return (cur);
8291
0
}
8292
8293
/**
8294
 * xmlXPathNextPrecedingInternal:
8295
 * @ctxt:  the XPath Parser context
8296
 * @cur:  the current node in the traversal
8297
 *
8298
 * Traversal function for the "preceding" direction
8299
 * the preceding axis contains all nodes in the same document as the context
8300
 * node that are before the context node in document order, excluding any
8301
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8302
 * ordered in reverse document order
8303
 * This is a faster implementation but internal only since it requires a
8304
 * state kept in the parser context: ctxt->ancestor.
8305
 *
8306
 * Returns the next element following that axis
8307
 */
8308
static xmlNodePtr
8309
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8310
                              xmlNodePtr cur)
8311
19.0k
{
8312
19.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8313
19.0k
    if (cur == NULL) {
8314
1.26k
        cur = ctxt->context->node;
8315
1.26k
        if (cur == NULL)
8316
0
            return (NULL);
8317
1.26k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8318
215
            cur = cur->parent;
8319
1.04k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8320
164
            xmlNsPtr ns = (xmlNsPtr) cur;
8321
8322
164
            if ((ns->next == NULL) ||
8323
164
                (ns->next->type == XML_NAMESPACE_DECL))
8324
0
                return (NULL);
8325
164
            cur = (xmlNodePtr) ns->next;
8326
164
        }
8327
1.26k
        ctxt->ancestor = cur->parent;
8328
1.26k
    }
8329
19.0k
    if (cur->type == XML_NAMESPACE_DECL)
8330
0
        return(NULL);
8331
19.0k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8332
0
  cur = cur->prev;
8333
21.0k
    while (cur->prev == NULL) {
8334
4.50k
        cur = cur->parent;
8335
4.50k
        if (cur == NULL)
8336
151
            return (NULL);
8337
4.34k
        if (cur == ctxt->context->doc->children)
8338
1.11k
            return (NULL);
8339
3.23k
        if (cur != ctxt->ancestor)
8340
1.30k
            return (cur);
8341
1.93k
        ctxt->ancestor = cur->parent;
8342
1.93k
    }
8343
16.5k
    cur = cur->prev;
8344
17.8k
    while (cur->last != NULL)
8345
1.30k
        cur = cur->last;
8346
16.5k
    return (cur);
8347
19.0k
}
8348
8349
/**
8350
 * xmlXPathNextNamespace:
8351
 * @ctxt:  the XPath Parser context
8352
 * @cur:  the current attribute in the traversal
8353
 *
8354
 * Traversal function for the "namespace" direction
8355
 * the namespace axis contains the namespace nodes of the context node;
8356
 * the order of nodes on this axis is implementation-defined; the axis will
8357
 * be empty unless the context node is an element
8358
 *
8359
 * We keep the XML namespace node at the end of the list.
8360
 *
8361
 * Returns the next element following that axis
8362
 */
8363
xmlNodePtr
8364
466k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8365
466k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8366
466k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8367
419k
    if (cur == NULL) {
8368
84.9k
        if (ctxt->context->tmpNsList != NULL)
8369
2.44k
      xmlFree(ctxt->context->tmpNsList);
8370
84.9k
  ctxt->context->tmpNsList =
8371
84.9k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8372
84.9k
  ctxt->context->tmpNsNr = 0;
8373
84.9k
  if (ctxt->context->tmpNsList != NULL) {
8374
345k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8375
265k
    ctxt->context->tmpNsNr++;
8376
265k
      }
8377
80.2k
  }
8378
84.9k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8379
84.9k
    }
8380
334k
    if (ctxt->context->tmpNsNr > 0) {
8381
253k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8382
253k
    } else {
8383
80.5k
  if (ctxt->context->tmpNsList != NULL)
8384
75.9k
      xmlFree(ctxt->context->tmpNsList);
8385
80.5k
  ctxt->context->tmpNsList = NULL;
8386
80.5k
  return(NULL);
8387
80.5k
    }
8388
334k
}
8389
8390
/**
8391
 * xmlXPathNextAttribute:
8392
 * @ctxt:  the XPath Parser context
8393
 * @cur:  the current attribute in the traversal
8394
 *
8395
 * Traversal function for the "attribute" direction
8396
 * TODO: support DTD inherited default attributes
8397
 *
8398
 * Returns the next element following that axis
8399
 */
8400
xmlNodePtr
8401
1.16M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8402
1.16M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8403
1.16M
    if (ctxt->context->node == NULL)
8404
0
  return(NULL);
8405
1.16M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8406
58.3k
  return(NULL);
8407
1.11M
    if (cur == NULL) {
8408
536k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8409
0
      return(NULL);
8410
536k
        return((xmlNodePtr)ctxt->context->node->properties);
8411
536k
    }
8412
574k
    return((xmlNodePtr)cur->next);
8413
1.11M
}
8414
8415
/************************************************************************
8416
 *                  *
8417
 *    NodeTest Functions          *
8418
 *                  *
8419
 ************************************************************************/
8420
8421
#define IS_FUNCTION     200
8422
8423
8424
/************************************************************************
8425
 *                  *
8426
 *    Implicit tree core function library     *
8427
 *                  *
8428
 ************************************************************************/
8429
8430
/**
8431
 * xmlXPathRoot:
8432
 * @ctxt:  the XPath Parser context
8433
 *
8434
 * Initialize the context to the root of the document
8435
 */
8436
void
8437
1.89M
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8438
1.89M
    if ((ctxt == NULL) || (ctxt->context == NULL))
8439
0
  return;
8440
1.89M
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8441
1.89M
  (xmlNodePtr) ctxt->context->doc));
8442
1.89M
}
8443
8444
/************************************************************************
8445
 *                  *
8446
 *    The explicit core function library      *
8447
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8448
 *                  *
8449
 ************************************************************************/
8450
8451
8452
/**
8453
 * xmlXPathLastFunction:
8454
 * @ctxt:  the XPath Parser context
8455
 * @nargs:  the number of arguments
8456
 *
8457
 * Implement the last() XPath function
8458
 *    number last()
8459
 * The last function returns the number of nodes in the context node list.
8460
 */
8461
void
8462
70.9k
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8463
212k
    CHECK_ARITY(0);
8464
212k
    if (ctxt->context->contextSize >= 0) {
8465
70.7k
  valuePush(ctxt,
8466
70.7k
      xmlXPathCacheNewFloat(ctxt->context,
8467
70.7k
    (double) ctxt->context->contextSize));
8468
#ifdef DEBUG_EXPR
8469
  xmlGenericError(xmlGenericErrorContext,
8470
    "last() : %d\n", ctxt->context->contextSize);
8471
#endif
8472
70.7k
    } else {
8473
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8474
0
    }
8475
212k
}
8476
8477
/**
8478
 * xmlXPathPositionFunction:
8479
 * @ctxt:  the XPath Parser context
8480
 * @nargs:  the number of arguments
8481
 *
8482
 * Implement the position() XPath function
8483
 *    number position()
8484
 * The position function returns the position of the context node in the
8485
 * context node list. The first position is 1, and so the last position
8486
 * will be equal to last().
8487
 */
8488
void
8489
81.3k
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490
243k
    CHECK_ARITY(0);
8491
243k
    if (ctxt->context->proximityPosition >= 0) {
8492
81.0k
  valuePush(ctxt,
8493
81.0k
        xmlXPathCacheNewFloat(ctxt->context,
8494
81.0k
    (double) ctxt->context->proximityPosition));
8495
#ifdef DEBUG_EXPR
8496
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8497
    ctxt->context->proximityPosition);
8498
#endif
8499
81.0k
    } else {
8500
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8501
0
    }
8502
243k
}
8503
8504
/**
8505
 * xmlXPathCountFunction:
8506
 * @ctxt:  the XPath Parser context
8507
 * @nargs:  the number of arguments
8508
 *
8509
 * Implement the count() XPath function
8510
 *    number count(node-set)
8511
 */
8512
void
8513
12.1k
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514
12.1k
    xmlXPathObjectPtr cur;
8515
8516
26.6k
    CHECK_ARITY(1);
8517
26.6k
    if ((ctxt->value == NULL) ||
8518
7.24k
  ((ctxt->value->type != XPATH_NODESET) &&
8519
7.24k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8520
4.76k
  XP_ERROR(XPATH_INVALID_TYPE);
8521
2.47k
    cur = valuePop(ctxt);
8522
8523
2.47k
    if ((cur == NULL) || (cur->nodesetval == NULL))
8524
416
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8525
2.06k
    else
8526
2.06k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8527
2.06k
      (double) cur->nodesetval->nodeNr));
8528
2.47k
    xmlXPathReleaseObject(ctxt->context, cur);
8529
2.47k
}
8530
8531
/**
8532
 * xmlXPathGetElementsByIds:
8533
 * @doc:  the document
8534
 * @ids:  a whitespace separated list of IDs
8535
 *
8536
 * Selects elements by their unique ID.
8537
 *
8538
 * Returns a node-set of selected elements.
8539
 */
8540
static xmlNodeSetPtr
8541
19.5k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8542
19.5k
    xmlNodeSetPtr ret;
8543
19.5k
    const xmlChar *cur = ids;
8544
19.5k
    xmlChar *ID;
8545
19.5k
    xmlAttrPtr attr;
8546
19.5k
    xmlNodePtr elem = NULL;
8547
8548
19.5k
    if (ids == NULL) return(NULL);
8549
8550
19.3k
    ret = xmlXPathNodeSetCreate(NULL);
8551
19.3k
    if (ret == NULL)
8552
5
        return(ret);
8553
8554
19.3k
    while (IS_BLANK_CH(*cur)) cur++;
8555
42.4k
    while (*cur != 0) {
8556
1.77M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8557
1.75M
      cur++;
8558
8559
23.0k
        ID = xmlStrndup(ids, cur - ids);
8560
23.0k
  if (ID != NULL) {
8561
      /*
8562
       * We used to check the fact that the value passed
8563
       * was an NCName, but this generated much troubles for
8564
       * me and Aleksey Sanin, people blatantly violated that
8565
       * constraint, like Visa3D spec.
8566
       * if (xmlValidateNCName(ID, 1) == 0)
8567
       */
8568
22.8k
      attr = xmlGetID(doc, ID);
8569
22.8k
      if (attr != NULL) {
8570
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8571
0
        elem = attr->parent;
8572
0
    else if (attr->type == XML_ELEMENT_NODE)
8573
0
        elem = (xmlNodePtr) attr;
8574
0
    else
8575
0
        elem = NULL;
8576
                /* TODO: Check memory error. */
8577
0
    if (elem != NULL)
8578
0
        xmlXPathNodeSetAdd(ret, elem);
8579
0
      }
8580
22.8k
      xmlFree(ID);
8581
22.8k
  }
8582
8583
23.0k
  while (IS_BLANK_CH(*cur)) cur++;
8584
23.0k
  ids = cur;
8585
23.0k
    }
8586
19.3k
    return(ret);
8587
19.3k
}
8588
8589
/**
8590
 * xmlXPathIdFunction:
8591
 * @ctxt:  the XPath Parser context
8592
 * @nargs:  the number of arguments
8593
 *
8594
 * Implement the id() XPath function
8595
 *    node-set id(object)
8596
 * The id function selects elements by their unique ID
8597
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8598
 * then the result is the union of the result of applying id to the
8599
 * string value of each of the nodes in the argument node-set. When the
8600
 * argument to id is of any other type, the argument is converted to a
8601
 * string as if by a call to the string function; the string is split
8602
 * into a whitespace-separated list of tokens (whitespace is any sequence
8603
 * of characters matching the production S); the result is a node-set
8604
 * containing the elements in the same document as the context node that
8605
 * have a unique ID equal to any of the tokens in the list.
8606
 */
8607
void
8608
20.6k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8609
20.6k
    xmlChar *tokens;
8610
20.6k
    xmlNodeSetPtr ret;
8611
20.6k
    xmlXPathObjectPtr obj;
8612
8613
61.8k
    CHECK_ARITY(1);
8614
61.8k
    obj = valuePop(ctxt);
8615
61.8k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8616
20.6k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8617
2.08k
  xmlNodeSetPtr ns;
8618
2.08k
  int i;
8619
8620
        /* TODO: Check memory error. */
8621
2.08k
  ret = xmlXPathNodeSetCreate(NULL);
8622
8623
2.08k
  if (obj->nodesetval != NULL) {
8624
2.89k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8625
993
    tokens =
8626
993
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8627
993
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8628
                /* TODO: Check memory error. */
8629
993
    ret = xmlXPathNodeSetMerge(ret, ns);
8630
993
    xmlXPathFreeNodeSet(ns);
8631
993
    if (tokens != NULL)
8632
868
        xmlFree(tokens);
8633
993
      }
8634
1.90k
  }
8635
2.08k
  xmlXPathReleaseObject(ctxt->context, obj);
8636
2.08k
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8637
2.08k
  return;
8638
2.08k
    }
8639
18.5k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8640
18.5k
    if (obj == NULL) return;
8641
18.5k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8642
18.5k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8643
18.5k
    xmlXPathReleaseObject(ctxt->context, obj);
8644
18.5k
    return;
8645
18.5k
}
8646
8647
/**
8648
 * xmlXPathLocalNameFunction:
8649
 * @ctxt:  the XPath Parser context
8650
 * @nargs:  the number of arguments
8651
 *
8652
 * Implement the local-name() XPath function
8653
 *    string local-name(node-set?)
8654
 * The local-name function returns a string containing the local part
8655
 * of the name of the node in the argument node-set that is first in
8656
 * document order. If the node-set is empty or the first node has no
8657
 * name, an empty string is returned. If the argument is omitted it
8658
 * defaults to the context node.
8659
 */
8660
void
8661
8.86k
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8662
8.86k
    xmlXPathObjectPtr cur;
8663
8664
8.86k
    if (ctxt == NULL) return;
8665
8666
8.86k
    if (nargs == 0) {
8667
141
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8668
141
      ctxt->context->node));
8669
141
  nargs = 1;
8670
141
    }
8671
8672
26.5k
    CHECK_ARITY(1);
8673
26.5k
    if ((ctxt->value == NULL) ||
8674
8.86k
  ((ctxt->value->type != XPATH_NODESET) &&
8675
8.86k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8676
8.86k
  XP_ERROR(XPATH_INVALID_TYPE);
8677
8.86k
    cur = valuePop(ctxt);
8678
8679
8.86k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8680
96
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8681
8.76k
    } else {
8682
8.76k
  int i = 0; /* Should be first in document order !!!!! */
8683
8.76k
  switch (cur->nodesetval->nodeTab[i]->type) {
8684
35
  case XML_ELEMENT_NODE:
8685
35
  case XML_ATTRIBUTE_NODE:
8686
680
  case XML_PI_NODE:
8687
680
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8688
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8689
680
      else
8690
680
    valuePush(ctxt,
8691
680
          xmlXPathCacheNewString(ctxt->context,
8692
680
      cur->nodesetval->nodeTab[i]->name));
8693
680
      break;
8694
1.18k
  case XML_NAMESPACE_DECL:
8695
1.18k
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8696
1.18k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8697
1.18k
      break;
8698
6.89k
  default:
8699
6.89k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8700
8.76k
  }
8701
8.76k
    }
8702
8.86k
    xmlXPathReleaseObject(ctxt->context, cur);
8703
8.86k
}
8704
8705
/**
8706
 * xmlXPathNamespaceURIFunction:
8707
 * @ctxt:  the XPath Parser context
8708
 * @nargs:  the number of arguments
8709
 *
8710
 * Implement the namespace-uri() XPath function
8711
 *    string namespace-uri(node-set?)
8712
 * The namespace-uri function returns a string containing the
8713
 * namespace URI of the expanded name of the node in the argument
8714
 * node-set that is first in document order. If the node-set is empty,
8715
 * the first node has no name, or the expanded name has no namespace
8716
 * URI, an empty string is returned. If the argument is omitted it
8717
 * defaults to the context node.
8718
 */
8719
void
8720
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8721
0
    xmlXPathObjectPtr cur;
8722
8723
0
    if (ctxt == NULL) return;
8724
8725
0
    if (nargs == 0) {
8726
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8727
0
      ctxt->context->node));
8728
0
  nargs = 1;
8729
0
    }
8730
0
    CHECK_ARITY(1);
8731
0
    if ((ctxt->value == NULL) ||
8732
0
  ((ctxt->value->type != XPATH_NODESET) &&
8733
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8734
0
  XP_ERROR(XPATH_INVALID_TYPE);
8735
0
    cur = valuePop(ctxt);
8736
8737
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8738
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8739
0
    } else {
8740
0
  int i = 0; /* Should be first in document order !!!!! */
8741
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8742
0
  case XML_ELEMENT_NODE:
8743
0
  case XML_ATTRIBUTE_NODE:
8744
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8745
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8746
0
      else
8747
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8748
0
        cur->nodesetval->nodeTab[i]->ns->href));
8749
0
      break;
8750
0
  default:
8751
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8752
0
  }
8753
0
    }
8754
0
    xmlXPathReleaseObject(ctxt->context, cur);
8755
0
}
8756
8757
/**
8758
 * xmlXPathNameFunction:
8759
 * @ctxt:  the XPath Parser context
8760
 * @nargs:  the number of arguments
8761
 *
8762
 * Implement the name() XPath function
8763
 *    string name(node-set?)
8764
 * The name function returns a string containing a QName representing
8765
 * the name of the node in the argument node-set that is first in document
8766
 * order. The QName must represent the name with respect to the namespace
8767
 * declarations in effect on the node whose name is being represented.
8768
 * Typically, this will be the form in which the name occurred in the XML
8769
 * source. This need not be the case if there are namespace declarations
8770
 * in effect on the node that associate multiple prefixes with the same
8771
 * namespace. However, an implementation may include information about
8772
 * the original prefix in its representation of nodes; in this case, an
8773
 * implementation can ensure that the returned string is always the same
8774
 * as the QName used in the XML source. If the argument it omitted it
8775
 * defaults to the context node.
8776
 * Libxml keep the original prefix so the "real qualified name" used is
8777
 * returned.
8778
 */
8779
static void
8780
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8781
26.4k
{
8782
26.4k
    xmlXPathObjectPtr cur;
8783
8784
26.4k
    if (nargs == 0) {
8785
19.1k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8786
19.1k
      ctxt->context->node));
8787
19.1k
        nargs = 1;
8788
19.1k
    }
8789
8790
78.7k
    CHECK_ARITY(1);
8791
78.7k
    if ((ctxt->value == NULL) ||
8792
26.1k
        ((ctxt->value->type != XPATH_NODESET) &&
8793
26.1k
         (ctxt->value->type != XPATH_XSLT_TREE)))
8794
21.1k
        XP_ERROR(XPATH_INVALID_TYPE);
8795
21.1k
    cur = valuePop(ctxt);
8796
8797
21.1k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8798
1.97k
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799
19.1k
    } else {
8800
19.1k
        int i = 0;              /* Should be first in document order !!!!! */
8801
8802
19.1k
        switch (cur->nodesetval->nodeTab[i]->type) {
8803
10.4k
            case XML_ELEMENT_NODE:
8804
10.4k
            case XML_ATTRIBUTE_NODE:
8805
10.4k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8806
0
        valuePush(ctxt,
8807
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8808
10.4k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8809
10.4k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8810
5.35k
        valuePush(ctxt,
8811
5.35k
            xmlXPathCacheNewString(ctxt->context,
8812
5.35k
          cur->nodesetval->nodeTab[i]->name));
8813
5.35k
    } else {
8814
5.08k
        xmlChar *fullname;
8815
8816
5.08k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8817
5.08k
             cur->nodesetval->nodeTab[i]->ns->prefix,
8818
5.08k
             NULL, 0);
8819
5.08k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8820
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8821
5.08k
        if (fullname == NULL)
8822
2
                        xmlXPathPErrMemory(ctxt, NULL);
8823
5.08k
        valuePush(ctxt, xmlXPathCacheWrapString(
8824
5.08k
      ctxt->context, fullname));
8825
5.08k
                }
8826
10.4k
                break;
8827
8.72k
            default:
8828
8.72k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8829
8.72k
        cur->nodesetval->nodeTab[i]));
8830
8.72k
                xmlXPathLocalNameFunction(ctxt, 1);
8831
19.1k
        }
8832
19.1k
    }
8833
21.1k
    xmlXPathReleaseObject(ctxt->context, cur);
8834
21.1k
}
8835
8836
8837
/**
8838
 * xmlXPathStringFunction:
8839
 * @ctxt:  the XPath Parser context
8840
 * @nargs:  the number of arguments
8841
 *
8842
 * Implement the string() XPath function
8843
 *    string string(object?)
8844
 * The string function converts an object to a string as follows:
8845
 *    - A node-set is converted to a string by returning the value of
8846
 *      the node in the node-set that is first in document order.
8847
 *      If the node-set is empty, an empty string is returned.
8848
 *    - A number is converted to a string as follows
8849
 *      + NaN is converted to the string NaN
8850
 *      + positive zero is converted to the string 0
8851
 *      + negative zero is converted to the string 0
8852
 *      + positive infinity is converted to the string Infinity
8853
 *      + negative infinity is converted to the string -Infinity
8854
 *      + if the number is an integer, the number is represented in
8855
 *        decimal form as a Number with no decimal point and no leading
8856
 *        zeros, preceded by a minus sign (-) if the number is negative
8857
 *      + otherwise, the number is represented in decimal form as a
8858
 *        Number including a decimal point with at least one digit
8859
 *        before the decimal point and at least one digit after the
8860
 *        decimal point, preceded by a minus sign (-) if the number
8861
 *        is negative; there must be no leading zeros before the decimal
8862
 *        point apart possibly from the one required digit immediately
8863
 *        before the decimal point; beyond the one required digit
8864
 *        after the decimal point there must be as many, but only as
8865
 *        many, more digits as are needed to uniquely distinguish the
8866
 *        number from all other IEEE 754 numeric values.
8867
 *    - The boolean false value is converted to the string false.
8868
 *      The boolean true value is converted to the string true.
8869
 *
8870
 * If the argument is omitted, it defaults to a node-set with the
8871
 * context node as its only member.
8872
 */
8873
void
8874
882k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8875
882k
    xmlXPathObjectPtr cur;
8876
8877
882k
    if (ctxt == NULL) return;
8878
882k
    if (nargs == 0) {
8879
7
    valuePush(ctxt,
8880
7
  xmlXPathCacheWrapString(ctxt->context,
8881
7
      xmlXPathCastNodeToString(ctxt->context->node)));
8882
7
  return;
8883
7
    }
8884
8885
3.52M
    CHECK_ARITY(1);
8886
3.52M
    cur = valuePop(ctxt);
8887
3.52M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8888
882k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8889
882k
}
8890
8891
/**
8892
 * xmlXPathStringLengthFunction:
8893
 * @ctxt:  the XPath Parser context
8894
 * @nargs:  the number of arguments
8895
 *
8896
 * Implement the string-length() XPath function
8897
 *    number string-length(string?)
8898
 * The string-length returns the number of characters in the string
8899
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8900
 * the context node converted to a string, in other words the value
8901
 * of the context node.
8902
 */
8903
void
8904
207
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905
207
    xmlXPathObjectPtr cur;
8906
8907
207
    if (nargs == 0) {
8908
22
        if ((ctxt == NULL) || (ctxt->context == NULL))
8909
0
      return;
8910
22
  if (ctxt->context->node == NULL) {
8911
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8912
22
  } else {
8913
22
      xmlChar *content;
8914
8915
22
      content = xmlXPathCastNodeToString(ctxt->context->node);
8916
22
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8917
22
    xmlUTF8Strlen(content)));
8918
22
      xmlFree(content);
8919
22
  }
8920
22
  return;
8921
22
    }
8922
740
    CHECK_ARITY(1);
8923
740
    CAST_TO_STRING;
8924
740
    CHECK_TYPE(XPATH_STRING);
8925
182
    cur = valuePop(ctxt);
8926
182
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8927
182
  xmlUTF8Strlen(cur->stringval)));
8928
182
    xmlXPathReleaseObject(ctxt->context, cur);
8929
182
}
8930
8931
/**
8932
 * xmlXPathConcatFunction:
8933
 * @ctxt:  the XPath Parser context
8934
 * @nargs:  the number of arguments
8935
 *
8936
 * Implement the concat() XPath function
8937
 *    string concat(string, string, string*)
8938
 * The concat function returns the concatenation of its arguments.
8939
 */
8940
void
8941
733
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8942
733
    xmlXPathObjectPtr cur, newobj;
8943
733
    xmlChar *tmp;
8944
8945
733
    if (ctxt == NULL) return;
8946
733
    if (nargs < 2) {
8947
79
  CHECK_ARITY(2);
8948
79
    }
8949
8950
654
    CAST_TO_STRING;
8951
654
    cur = valuePop(ctxt);
8952
654
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8953
4
  xmlXPathReleaseObject(ctxt->context, cur);
8954
4
  return;
8955
4
    }
8956
650
    nargs--;
8957
8958
2.66k
    while (nargs > 0) {
8959
2.01k
  CAST_TO_STRING;
8960
2.01k
  newobj = valuePop(ctxt);
8961
2.01k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8962
8
      xmlXPathReleaseObject(ctxt->context, newobj);
8963
8
      xmlXPathReleaseObject(ctxt->context, cur);
8964
8
      XP_ERROR(XPATH_INVALID_TYPE);
8965
0
  }
8966
2.01k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8967
2.01k
  newobj->stringval = cur->stringval;
8968
2.01k
  cur->stringval = tmp;
8969
2.01k
  xmlXPathReleaseObject(ctxt->context, newobj);
8970
2.01k
  nargs--;
8971
2.01k
    }
8972
642
    valuePush(ctxt, cur);
8973
642
}
8974
8975
/**
8976
 * xmlXPathContainsFunction:
8977
 * @ctxt:  the XPath Parser context
8978
 * @nargs:  the number of arguments
8979
 *
8980
 * Implement the contains() XPath function
8981
 *    boolean contains(string, string)
8982
 * The contains function returns true if the first argument string
8983
 * contains the second argument string, and otherwise returns false.
8984
 */
8985
void
8986
8.45k
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8987
8.45k
    xmlXPathObjectPtr hay, needle;
8988
8989
25.2k
    CHECK_ARITY(2);
8990
25.2k
    CAST_TO_STRING;
8991
25.2k
    CHECK_TYPE(XPATH_STRING);
8992
8.41k
    needle = valuePop(ctxt);
8993
8.41k
    CAST_TO_STRING;
8994
8.41k
    hay = valuePop(ctxt);
8995
8996
8.41k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8997
3
  xmlXPathReleaseObject(ctxt->context, hay);
8998
3
  xmlXPathReleaseObject(ctxt->context, needle);
8999
3
  XP_ERROR(XPATH_INVALID_TYPE);
9000
0
    }
9001
8.41k
    if (xmlStrstr(hay->stringval, needle->stringval))
9002
4.32k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9003
4.08k
    else
9004
4.08k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9005
8.41k
    xmlXPathReleaseObject(ctxt->context, hay);
9006
8.41k
    xmlXPathReleaseObject(ctxt->context, needle);
9007
8.41k
}
9008
9009
/**
9010
 * xmlXPathStartsWithFunction:
9011
 * @ctxt:  the XPath Parser context
9012
 * @nargs:  the number of arguments
9013
 *
9014
 * Implement the starts-with() XPath function
9015
 *    boolean starts-with(string, string)
9016
 * The starts-with function returns true if the first argument string
9017
 * starts with the second argument string, and otherwise returns false.
9018
 */
9019
void
9020
789
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9021
789
    xmlXPathObjectPtr hay, needle;
9022
789
    int n;
9023
9024
2.14k
    CHECK_ARITY(2);
9025
2.14k
    CAST_TO_STRING;
9026
2.14k
    CHECK_TYPE(XPATH_STRING);
9027
608
    needle = valuePop(ctxt);
9028
608
    CAST_TO_STRING;
9029
608
    hay = valuePop(ctxt);
9030
9031
608
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9032
1
  xmlXPathReleaseObject(ctxt->context, hay);
9033
1
  xmlXPathReleaseObject(ctxt->context, needle);
9034
1
  XP_ERROR(XPATH_INVALID_TYPE);
9035
0
    }
9036
607
    n = xmlStrlen(needle->stringval);
9037
607
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9038
452
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9039
155
    else
9040
155
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9041
607
    xmlXPathReleaseObject(ctxt->context, hay);
9042
607
    xmlXPathReleaseObject(ctxt->context, needle);
9043
607
}
9044
9045
/**
9046
 * xmlXPathSubstringFunction:
9047
 * @ctxt:  the XPath Parser context
9048
 * @nargs:  the number of arguments
9049
 *
9050
 * Implement the substring() XPath function
9051
 *    string substring(string, number, number?)
9052
 * The substring function returns the substring of the first argument
9053
 * starting at the position specified in the second argument with
9054
 * length specified in the third argument. For example,
9055
 * substring("12345",2,3) returns "234". If the third argument is not
9056
 * specified, it returns the substring starting at the position specified
9057
 * in the second argument and continuing to the end of the string. For
9058
 * example, substring("12345",2) returns "2345".  More precisely, each
9059
 * character in the string (see [3.6 Strings]) is considered to have a
9060
 * numeric position: the position of the first character is 1, the position
9061
 * of the second character is 2 and so on. The returned substring contains
9062
 * those characters for which the position of the character is greater than
9063
 * or equal to the second argument and, if the third argument is specified,
9064
 * less than the sum of the second and third arguments; the comparisons
9065
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9066
 *  - substring("12345", 1.5, 2.6) returns "234"
9067
 *  - substring("12345", 0, 3) returns "12"
9068
 *  - substring("12345", 0 div 0, 3) returns ""
9069
 *  - substring("12345", 1, 0 div 0) returns ""
9070
 *  - substring("12345", -42, 1 div 0) returns "12345"
9071
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9072
 */
9073
void
9074
6.27k
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9075
6.27k
    xmlXPathObjectPtr str, start, len;
9076
6.27k
    double le=0, in;
9077
6.27k
    int i = 1, j = INT_MAX;
9078
9079
6.27k
    if (nargs < 2) {
9080
67
  CHECK_ARITY(2);
9081
67
    }
9082
6.21k
    if (nargs > 3) {
9083
20
  CHECK_ARITY(3);
9084
20
    }
9085
    /*
9086
     * take care of possible last (position) argument
9087
    */
9088
6.19k
    if (nargs == 3) {
9089
1.39k
  CAST_TO_NUMBER;
9090
1.39k
  CHECK_TYPE(XPATH_NUMBER);
9091
1.39k
  len = valuePop(ctxt);
9092
1.39k
  le = len->floatval;
9093
1.39k
  xmlXPathReleaseObject(ctxt->context, len);
9094
1.39k
    }
9095
9096
6.19k
    CAST_TO_NUMBER;
9097
6.19k
    CHECK_TYPE(XPATH_NUMBER);
9098
6.19k
    start = valuePop(ctxt);
9099
6.19k
    in = start->floatval;
9100
6.19k
    xmlXPathReleaseObject(ctxt->context, start);
9101
6.19k
    CAST_TO_STRING;
9102
6.19k
    CHECK_TYPE(XPATH_STRING);
9103
6.18k
    str = valuePop(ctxt);
9104
9105
6.18k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9106
398
        i = INT_MAX;
9107
5.79k
    } else if (in >= 1.0) {
9108
4.72k
        i = (int)in;
9109
4.72k
        if (in - floor(in) >= 0.5)
9110
21
            i += 1;
9111
4.72k
    }
9112
9113
6.18k
    if (nargs == 3) {
9114
1.39k
        double rin, rle, end;
9115
9116
1.39k
        rin = floor(in);
9117
1.39k
        if (in - rin >= 0.5)
9118
28
            rin += 1.0;
9119
9120
1.39k
        rle = floor(le);
9121
1.39k
        if (le - rle >= 0.5)
9122
0
            rle += 1.0;
9123
9124
1.39k
        end = rin + rle;
9125
1.39k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9126
312
            j = 1;
9127
1.07k
        } else if (end < INT_MAX) {
9128
929
            j = (int)end;
9129
929
        }
9130
1.39k
    }
9131
9132
6.18k
    if (i < j) {
9133
5.52k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9134
5.52k
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9135
5.52k
  xmlFree(ret);
9136
5.52k
    } else {
9137
662
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9138
662
    }
9139
9140
6.18k
    xmlXPathReleaseObject(ctxt->context, str);
9141
6.18k
}
9142
9143
/**
9144
 * xmlXPathSubstringBeforeFunction:
9145
 * @ctxt:  the XPath Parser context
9146
 * @nargs:  the number of arguments
9147
 *
9148
 * Implement the substring-before() XPath function
9149
 *    string substring-before(string, string)
9150
 * The substring-before function returns the substring of the first
9151
 * argument string that precedes the first occurrence of the second
9152
 * argument string in the first argument string, or the empty string
9153
 * if the first argument string does not contain the second argument
9154
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9155
 */
9156
void
9157
2.10k
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9158
2.10k
  xmlXPathObjectPtr str;
9159
2.10k
  xmlXPathObjectPtr find;
9160
2.10k
  xmlBufPtr target;
9161
2.10k
  const xmlChar *point;
9162
2.10k
  int offset;
9163
9164
6.17k
  CHECK_ARITY(2);
9165
6.17k
  CAST_TO_STRING;
9166
6.17k
  find = valuePop(ctxt);
9167
6.17k
  CAST_TO_STRING;
9168
6.17k
  str = valuePop(ctxt);
9169
9170
6.17k
  target = xmlBufCreate();
9171
6.17k
  if (target) {
9172
2.03k
    point = xmlStrstr(str->stringval, find->stringval);
9173
2.03k
    if (point) {
9174
829
      offset = point - str->stringval;
9175
829
      xmlBufAdd(target, str->stringval, offset);
9176
829
    }
9177
2.03k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9178
2.03k
  xmlBufContent(target)));
9179
2.03k
    xmlBufFree(target);
9180
2.03k
  }
9181
6.17k
  xmlXPathReleaseObject(ctxt->context, str);
9182
6.17k
  xmlXPathReleaseObject(ctxt->context, find);
9183
6.17k
}
9184
9185
/**
9186
 * xmlXPathSubstringAfterFunction:
9187
 * @ctxt:  the XPath Parser context
9188
 * @nargs:  the number of arguments
9189
 *
9190
 * Implement the substring-after() XPath function
9191
 *    string substring-after(string, string)
9192
 * The substring-after function returns the substring of the first
9193
 * argument string that follows the first occurrence of the second
9194
 * argument string in the first argument string, or the empty stringi
9195
 * if the first argument string does not contain the second argument
9196
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9197
 * and substring-after("1999/04/01","19") returns 99/04/01.
9198
 */
9199
void
9200
1.15k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9201
1.15k
  xmlXPathObjectPtr str;
9202
1.15k
  xmlXPathObjectPtr find;
9203
1.15k
  xmlBufPtr target;
9204
1.15k
  const xmlChar *point;
9205
1.15k
  int offset;
9206
9207
3.37k
  CHECK_ARITY(2);
9208
3.37k
  CAST_TO_STRING;
9209
3.37k
  find = valuePop(ctxt);
9210
3.37k
  CAST_TO_STRING;
9211
3.37k
  str = valuePop(ctxt);
9212
9213
3.37k
  target = xmlBufCreate();
9214
3.37k
  if (target) {
9215
1.10k
    point = xmlStrstr(str->stringval, find->stringval);
9216
1.10k
    if (point) {
9217
836
      offset = point - str->stringval + xmlStrlen(find->stringval);
9218
836
      xmlBufAdd(target, &str->stringval[offset],
9219
836
       xmlStrlen(str->stringval) - offset);
9220
836
    }
9221
1.10k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9222
1.10k
  xmlBufContent(target)));
9223
1.10k
    xmlBufFree(target);
9224
1.10k
  }
9225
3.37k
  xmlXPathReleaseObject(ctxt->context, str);
9226
3.37k
  xmlXPathReleaseObject(ctxt->context, find);
9227
3.37k
}
9228
9229
/**
9230
 * xmlXPathNormalizeFunction:
9231
 * @ctxt:  the XPath Parser context
9232
 * @nargs:  the number of arguments
9233
 *
9234
 * Implement the normalize-space() XPath function
9235
 *    string normalize-space(string?)
9236
 * The normalize-space function returns the argument string with white
9237
 * space normalized by stripping leading and trailing whitespace
9238
 * and replacing sequences of whitespace characters by a single
9239
 * space. Whitespace characters are the same allowed by the S production
9240
 * in XML. If the argument is omitted, it defaults to the context
9241
 * node converted to a string, in other words the value of the context node.
9242
 */
9243
void
9244
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245
0
    xmlChar *source, *target;
9246
0
    int blank;
9247
9248
0
    if (ctxt == NULL) return;
9249
0
    if (nargs == 0) {
9250
        /* Use current context node */
9251
0
        valuePush(ctxt,
9252
0
            xmlXPathCacheWrapString(ctxt->context,
9253
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9254
0
        nargs = 1;
9255
0
    }
9256
9257
0
    CHECK_ARITY(1);
9258
0
    CAST_TO_STRING;
9259
0
    CHECK_TYPE(XPATH_STRING);
9260
0
    source = ctxt->value->stringval;
9261
0
    if (source == NULL)
9262
0
        return;
9263
0
    target = source;
9264
9265
    /* Skip leading whitespaces */
9266
0
    while (IS_BLANK_CH(*source))
9267
0
        source++;
9268
9269
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9270
0
    blank = 0;
9271
0
    while (*source) {
9272
0
        if (IS_BLANK_CH(*source)) {
9273
0
      blank = 1;
9274
0
        } else {
9275
0
            if (blank) {
9276
0
                *target++ = 0x20;
9277
0
                blank = 0;
9278
0
            }
9279
0
            *target++ = *source;
9280
0
        }
9281
0
        source++;
9282
0
    }
9283
0
    *target = 0;
9284
0
}
9285
9286
/**
9287
 * xmlXPathTranslateFunction:
9288
 * @ctxt:  the XPath Parser context
9289
 * @nargs:  the number of arguments
9290
 *
9291
 * Implement the translate() XPath function
9292
 *    string translate(string, string, string)
9293
 * The translate function returns the first argument string with
9294
 * occurrences of characters in the second argument string replaced
9295
 * by the character at the corresponding position in the third argument
9296
 * string. For example, translate("bar","abc","ABC") returns the string
9297
 * BAr. If there is a character in the second argument string with no
9298
 * character at a corresponding position in the third argument string
9299
 * (because the second argument string is longer than the third argument
9300
 * string), then occurrences of that character in the first argument
9301
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9302
 * returns "AAA". If a character occurs more than once in second
9303
 * argument string, then the first occurrence determines the replacement
9304
 * character. If the third argument string is longer than the second
9305
 * argument string, then excess characters are ignored.
9306
 */
9307
void
9308
682
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9309
682
    xmlXPathObjectPtr str;
9310
682
    xmlXPathObjectPtr from;
9311
682
    xmlXPathObjectPtr to;
9312
682
    xmlBufPtr target;
9313
682
    int offset, max;
9314
682
    int ch;
9315
682
    const xmlChar *point;
9316
682
    xmlChar *cptr;
9317
9318
1.56k
    CHECK_ARITY(3);
9319
9320
1.56k
    CAST_TO_STRING;
9321
1.56k
    to = valuePop(ctxt);
9322
1.56k
    CAST_TO_STRING;
9323
1.56k
    from = valuePop(ctxt);
9324
1.56k
    CAST_TO_STRING;
9325
1.56k
    str = valuePop(ctxt);
9326
9327
1.56k
    target = xmlBufCreate();
9328
1.56k
    if (target) {
9329
439
  max = xmlUTF8Strlen(to->stringval);
9330
191k
  for (cptr = str->stringval; (ch=*cptr); ) {
9331
190k
      offset = xmlUTF8Strloc(from->stringval, cptr);
9332
190k
      if (offset >= 0) {
9333
4.14k
    if (offset < max) {
9334
3.22k
        point = xmlUTF8Strpos(to->stringval, offset);
9335
3.22k
        if (point)
9336
3.22k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9337
3.22k
    }
9338
4.14k
      } else
9339
186k
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9340
9341
      /* Step to next character in input */
9342
190k
      cptr++;
9343
190k
      if ( ch & 0x80 ) {
9344
    /* if not simple ascii, verify proper format */
9345
390
    if ( (ch & 0xc0) != 0xc0 ) {
9346
0
        xmlGenericError(xmlGenericErrorContext,
9347
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9348
                    /* not asserting an XPath error is probably better */
9349
0
        break;
9350
0
    }
9351
    /* then skip over remaining bytes for this char */
9352
1.14k
    while ( (ch <<= 1) & 0x80 )
9353
753
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9354
0
      xmlGenericError(xmlGenericErrorContext,
9355
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9356
                        /* not asserting an XPath error is probably better */
9357
0
      break;
9358
0
        }
9359
390
    if (ch & 0x80) /* must have had error encountered */
9360
0
        break;
9361
390
      }
9362
190k
  }
9363
439
    }
9364
1.56k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9365
1.56k
  xmlBufContent(target)));
9366
1.56k
    xmlBufFree(target);
9367
1.56k
    xmlXPathReleaseObject(ctxt->context, str);
9368
1.56k
    xmlXPathReleaseObject(ctxt->context, from);
9369
1.56k
    xmlXPathReleaseObject(ctxt->context, to);
9370
1.56k
}
9371
9372
/**
9373
 * xmlXPathBooleanFunction:
9374
 * @ctxt:  the XPath Parser context
9375
 * @nargs:  the number of arguments
9376
 *
9377
 * Implement the boolean() XPath function
9378
 *    boolean boolean(object)
9379
 * The boolean function converts its argument to a boolean as follows:
9380
 *    - a number is true if and only if it is neither positive or
9381
 *      negative zero nor NaN
9382
 *    - a node-set is true if and only if it is non-empty
9383
 *    - a string is true if and only if its length is non-zero
9384
 */
9385
void
9386
305k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9387
305k
    xmlXPathObjectPtr cur;
9388
9389
917k
    CHECK_ARITY(1);
9390
917k
    cur = valuePop(ctxt);
9391
917k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9392
305k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9393
305k
    valuePush(ctxt, cur);
9394
305k
}
9395
9396
/**
9397
 * xmlXPathNotFunction:
9398
 * @ctxt:  the XPath Parser context
9399
 * @nargs:  the number of arguments
9400
 *
9401
 * Implement the not() XPath function
9402
 *    boolean not(boolean)
9403
 * The not function returns true if its argument is false,
9404
 * and false otherwise.
9405
 */
9406
void
9407
802
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9408
2.40k
    CHECK_ARITY(1);
9409
2.40k
    CAST_TO_BOOLEAN;
9410
2.40k
    CHECK_TYPE(XPATH_BOOLEAN);
9411
801
    ctxt->value->boolval = ! ctxt->value->boolval;
9412
801
}
9413
9414
/**
9415
 * xmlXPathTrueFunction:
9416
 * @ctxt:  the XPath Parser context
9417
 * @nargs:  the number of arguments
9418
 *
9419
 * Implement the true() XPath function
9420
 *    boolean true()
9421
 */
9422
void
9423
401
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9424
1.20k
    CHECK_ARITY(0);
9425
1.20k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9426
1.20k
}
9427
9428
/**
9429
 * xmlXPathFalseFunction:
9430
 * @ctxt:  the XPath Parser context
9431
 * @nargs:  the number of arguments
9432
 *
9433
 * Implement the false() XPath function
9434
 *    boolean false()
9435
 */
9436
void
9437
87
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438
241
    CHECK_ARITY(0);
9439
241
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9440
241
}
9441
9442
/**
9443
 * xmlXPathLangFunction:
9444
 * @ctxt:  the XPath Parser context
9445
 * @nargs:  the number of arguments
9446
 *
9447
 * Implement the lang() XPath function
9448
 *    boolean lang(string)
9449
 * The lang function returns true or false depending on whether the
9450
 * language of the context node as specified by xml:lang attributes
9451
 * is the same as or is a sublanguage of the language specified by
9452
 * the argument string. The language of the context node is determined
9453
 * by the value of the xml:lang attribute on the context node, or, if
9454
 * the context node has no xml:lang attribute, by the value of the
9455
 * xml:lang attribute on the nearest ancestor of the context node that
9456
 * has an xml:lang attribute. If there is no such attribute, then lang
9457
 * returns false. If there is such an attribute, then lang returns
9458
 * true if the attribute value is equal to the argument ignoring case,
9459
 * or if there is some suffix starting with - such that the attribute
9460
 * value is equal to the argument ignoring that suffix of the attribute
9461
 * value and ignoring case.
9462
 */
9463
void
9464
1.21k
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9465
1.21k
    xmlXPathObjectPtr val = NULL;
9466
1.21k
    const xmlChar *theLang = NULL;
9467
1.21k
    const xmlChar *lang;
9468
1.21k
    int ret = 0;
9469
1.21k
    int i;
9470
9471
3.23k
    CHECK_ARITY(1);
9472
3.23k
    CAST_TO_STRING;
9473
3.23k
    CHECK_TYPE(XPATH_STRING);
9474
851
    val = valuePop(ctxt);
9475
851
    lang = val->stringval;
9476
851
    theLang = xmlNodeGetLang(ctxt->context->node);
9477
851
    if ((theLang != NULL) && (lang != NULL)) {
9478
0
        for (i = 0;lang[i] != 0;i++)
9479
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9480
0
          goto not_equal;
9481
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9482
0
      ret = 1;
9483
0
    }
9484
851
not_equal:
9485
851
    if (theLang != NULL)
9486
0
  xmlFree((void *)theLang);
9487
9488
851
    xmlXPathReleaseObject(ctxt->context, val);
9489
851
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9490
851
}
9491
9492
/**
9493
 * xmlXPathNumberFunction:
9494
 * @ctxt:  the XPath Parser context
9495
 * @nargs:  the number of arguments
9496
 *
9497
 * Implement the number() XPath function
9498
 *    number number(object?)
9499
 */
9500
void
9501
1.51M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9502
1.51M
    xmlXPathObjectPtr cur;
9503
1.51M
    double res;
9504
9505
1.51M
    if (ctxt == NULL) return;
9506
1.51M
    if (nargs == 0) {
9507
273
  if (ctxt->context->node == NULL) {
9508
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9509
273
  } else {
9510
273
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9511
9512
273
      res = xmlXPathStringEvalNumber(content);
9513
273
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9514
273
      xmlFree(content);
9515
273
  }
9516
273
  return;
9517
273
    }
9518
9519
6.05M
    CHECK_ARITY(1);
9520
6.05M
    cur = valuePop(ctxt);
9521
6.05M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9522
6.05M
}
9523
9524
/**
9525
 * xmlXPathSumFunction:
9526
 * @ctxt:  the XPath Parser context
9527
 * @nargs:  the number of arguments
9528
 *
9529
 * Implement the sum() XPath function
9530
 *    number sum(node-set)
9531
 * The sum function returns the sum of the values of the nodes in
9532
 * the argument node-set.
9533
 */
9534
void
9535
665
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9536
665
    xmlXPathObjectPtr cur;
9537
665
    int i;
9538
665
    double res = 0.0;
9539
9540
1.99k
    CHECK_ARITY(1);
9541
1.99k
    if ((ctxt->value == NULL) ||
9542
665
  ((ctxt->value->type != XPATH_NODESET) &&
9543
665
   (ctxt->value->type != XPATH_XSLT_TREE)))
9544
665
  XP_ERROR(XPATH_INVALID_TYPE);
9545
665
    cur = valuePop(ctxt);
9546
9547
665
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9548
448
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9549
301
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9550
301
  }
9551
147
    }
9552
665
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9553
665
    xmlXPathReleaseObject(ctxt->context, cur);
9554
665
}
9555
9556
/**
9557
 * xmlXPathFloorFunction:
9558
 * @ctxt:  the XPath Parser context
9559
 * @nargs:  the number of arguments
9560
 *
9561
 * Implement the floor() XPath function
9562
 *    number floor(number)
9563
 * The floor function returns the largest (closest to positive infinity)
9564
 * number that is not greater than the argument and that is an integer.
9565
 */
9566
void
9567
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9568
0
    CHECK_ARITY(1);
9569
0
    CAST_TO_NUMBER;
9570
0
    CHECK_TYPE(XPATH_NUMBER);
9571
9572
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9573
0
}
9574
9575
/**
9576
 * xmlXPathCeilingFunction:
9577
 * @ctxt:  the XPath Parser context
9578
 * @nargs:  the number of arguments
9579
 *
9580
 * Implement the ceiling() XPath function
9581
 *    number ceiling(number)
9582
 * The ceiling function returns the smallest (closest to negative infinity)
9583
 * number that is not less than the argument and that is an integer.
9584
 */
9585
void
9586
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9587
0
    CHECK_ARITY(1);
9588
0
    CAST_TO_NUMBER;
9589
0
    CHECK_TYPE(XPATH_NUMBER);
9590
9591
#ifdef _AIX
9592
    /* Work around buggy ceil() function on AIX */
9593
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9594
#else
9595
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9596
0
#endif
9597
0
}
9598
9599
/**
9600
 * xmlXPathRoundFunction:
9601
 * @ctxt:  the XPath Parser context
9602
 * @nargs:  the number of arguments
9603
 *
9604
 * Implement the round() XPath function
9605
 *    number round(number)
9606
 * The round function returns the number that is closest to the
9607
 * argument and that is an integer. If there are two such numbers,
9608
 * then the one that is closest to positive infinity is returned.
9609
 */
9610
void
9611
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612
0
    double f;
9613
9614
0
    CHECK_ARITY(1);
9615
0
    CAST_TO_NUMBER;
9616
0
    CHECK_TYPE(XPATH_NUMBER);
9617
9618
0
    f = ctxt->value->floatval;
9619
9620
0
    if ((f >= -0.5) && (f < 0.5)) {
9621
        /* Handles negative zero. */
9622
0
        ctxt->value->floatval *= 0.0;
9623
0
    }
9624
0
    else {
9625
0
        double rounded = floor(f);
9626
0
        if (f - rounded >= 0.5)
9627
0
            rounded += 1.0;
9628
0
        ctxt->value->floatval = rounded;
9629
0
    }
9630
0
}
9631
9632
/************************************************************************
9633
 *                  *
9634
 *      The Parser          *
9635
 *                  *
9636
 ************************************************************************/
9637
9638
/*
9639
 * a few forward declarations since we use a recursive call based
9640
 * implementation.
9641
 */
9642
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9643
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9644
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9645
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9646
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9647
                                    int qualified);
9648
9649
/**
9650
 * xmlXPathCurrentChar:
9651
 * @ctxt:  the XPath parser context
9652
 * @cur:  pointer to the beginning of the char
9653
 * @len:  pointer to the length of the char read
9654
 *
9655
 * The current char value, if using UTF-8 this may actually span multiple
9656
 * bytes in the input buffer.
9657
 *
9658
 * Returns the current char value and its length
9659
 */
9660
9661
static int
9662
33.1M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9663
33.1M
    unsigned char c;
9664
33.1M
    unsigned int val;
9665
33.1M
    const xmlChar *cur;
9666
9667
33.1M
    if (ctxt == NULL)
9668
0
  return(0);
9669
33.1M
    cur = ctxt->cur;
9670
9671
    /*
9672
     * We are supposed to handle UTF8, check it's valid
9673
     * From rfc2044: encoding of the Unicode values on UTF-8:
9674
     *
9675
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9676
     * 0000 0000-0000 007F   0xxxxxxx
9677
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9678
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9679
     *
9680
     * Check for the 0x110000 limit too
9681
     */
9682
33.1M
    c = *cur;
9683
33.1M
    if (c & 0x80) {
9684
2.74M
  if ((cur[1] & 0xc0) != 0x80)
9685
73
      goto encoding_error;
9686
2.74M
  if ((c & 0xe0) == 0xe0) {
9687
9688
367k
      if ((cur[2] & 0xc0) != 0x80)
9689
0
    goto encoding_error;
9690
367k
      if ((c & 0xf0) == 0xf0) {
9691
9.68k
    if (((c & 0xf8) != 0xf0) ||
9692
9.68k
        ((cur[3] & 0xc0) != 0x80))
9693
0
        goto encoding_error;
9694
    /* 4-byte code */
9695
9.68k
    *len = 4;
9696
9.68k
    val = (cur[0] & 0x7) << 18;
9697
9.68k
    val |= (cur[1] & 0x3f) << 12;
9698
9.68k
    val |= (cur[2] & 0x3f) << 6;
9699
9.68k
    val |= cur[3] & 0x3f;
9700
357k
      } else {
9701
        /* 3-byte code */
9702
357k
    *len = 3;
9703
357k
    val = (cur[0] & 0xf) << 12;
9704
357k
    val |= (cur[1] & 0x3f) << 6;
9705
357k
    val |= cur[2] & 0x3f;
9706
357k
      }
9707
2.37M
  } else {
9708
    /* 2-byte code */
9709
2.37M
      *len = 2;
9710
2.37M
      val = (cur[0] & 0x1f) << 6;
9711
2.37M
      val |= cur[1] & 0x3f;
9712
2.37M
  }
9713
2.74M
  if (!IS_CHAR(val)) {
9714
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9715
0
  }
9716
2.74M
  return(val);
9717
30.3M
    } else {
9718
  /* 1-byte code */
9719
30.3M
  *len = 1;
9720
30.3M
  return(*cur);
9721
30.3M
    }
9722
73
encoding_error:
9723
    /*
9724
     * If we detect an UTF8 error that probably means that the
9725
     * input encoding didn't get properly advertised in the
9726
     * declaration header. Report the error and switch the encoding
9727
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9728
     * encoding !)
9729
     */
9730
73
    *len = 0;
9731
73
    XP_ERROR0(XPATH_ENCODING_ERROR);
9732
0
}
9733
9734
/**
9735
 * xmlXPathParseNCName:
9736
 * @ctxt:  the XPath Parser context
9737
 *
9738
 * parse an XML namespace non qualified name.
9739
 *
9740
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9741
 *
9742
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9743
 *                       CombiningChar | Extender
9744
 *
9745
 * Returns the namespace name or NULL
9746
 */
9747
9748
xmlChar *
9749
4.56M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9750
4.56M
    const xmlChar *in;
9751
4.56M
    xmlChar *ret;
9752
4.56M
    int count = 0;
9753
9754
4.56M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9755
    /*
9756
     * Accelerator for simple ASCII names
9757
     */
9758
4.56M
    in = ctxt->cur;
9759
4.56M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9760
4.56M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9761
4.56M
  (*in == '_')) {
9762
4.31M
  in++;
9763
24.7M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9764
24.7M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9765
24.7M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9766
24.7M
         (*in == '_') || (*in == '.') ||
9767
24.7M
         (*in == '-'))
9768
20.4M
      in++;
9769
4.31M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9770
4.31M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9771
4.31M
            (*in == '@') || (*in == '*')) {
9772
1.98M
      count = in - ctxt->cur;
9773
1.98M
      if (count == 0)
9774
0
    return(NULL);
9775
1.98M
      ret = xmlStrndup(ctxt->cur, count);
9776
1.98M
      ctxt->cur = in;
9777
1.98M
      return(ret);
9778
1.98M
  }
9779
4.31M
    }
9780
2.57M
    return(xmlXPathParseNameComplex(ctxt, 0));
9781
4.56M
}
9782
9783
9784
/**
9785
 * xmlXPathParseQName:
9786
 * @ctxt:  the XPath Parser context
9787
 * @prefix:  a xmlChar **
9788
 *
9789
 * parse an XML qualified name
9790
 *
9791
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9792
 *
9793
 * [NS 6] Prefix ::= NCName
9794
 *
9795
 * [NS 7] LocalPart ::= NCName
9796
 *
9797
 * Returns the function returns the local part, and prefix is updated
9798
 *   to get the Prefix if any.
9799
 */
9800
9801
static xmlChar *
9802
1.15M
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9803
1.15M
    xmlChar *ret = NULL;
9804
9805
1.15M
    *prefix = NULL;
9806
1.15M
    ret = xmlXPathParseNCName(ctxt);
9807
1.15M
    if (ret && CUR == ':') {
9808
900k
        *prefix = ret;
9809
900k
  NEXT;
9810
900k
  ret = xmlXPathParseNCName(ctxt);
9811
900k
    }
9812
1.15M
    return(ret);
9813
1.15M
}
9814
9815
/**
9816
 * xmlXPathParseName:
9817
 * @ctxt:  the XPath Parser context
9818
 *
9819
 * parse an XML name
9820
 *
9821
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9822
 *                  CombiningChar | Extender
9823
 *
9824
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9825
 *
9826
 * Returns the namespace name or NULL
9827
 */
9828
9829
xmlChar *
9830
21.8k
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9831
21.8k
    const xmlChar *in;
9832
21.8k
    xmlChar *ret;
9833
21.8k
    size_t count = 0;
9834
9835
21.8k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9836
    /*
9837
     * Accelerator for simple ASCII names
9838
     */
9839
21.8k
    in = ctxt->cur;
9840
21.8k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9841
21.8k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9842
21.8k
  (*in == '_') || (*in == ':')) {
9843
19.2k
  in++;
9844
6.07M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9845
6.07M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9846
6.07M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9847
6.07M
         (*in == '_') || (*in == '-') ||
9848
6.07M
         (*in == ':') || (*in == '.'))
9849
6.06M
      in++;
9850
19.2k
  if ((*in > 0) && (*in < 0x80)) {
9851
16.8k
      count = in - ctxt->cur;
9852
16.8k
            if (count > XML_MAX_NAME_LENGTH) {
9853
62
                ctxt->cur = in;
9854
62
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9855
0
            }
9856
16.7k
      ret = xmlStrndup(ctxt->cur, count);
9857
16.7k
      ctxt->cur = in;
9858
16.7k
      return(ret);
9859
16.8k
  }
9860
19.2k
    }
9861
5.05k
    return(xmlXPathParseNameComplex(ctxt, 1));
9862
21.8k
}
9863
9864
static xmlChar *
9865
2.58M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9866
2.58M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9867
2.58M
    int len = 0, l;
9868
2.58M
    int c;
9869
9870
    /*
9871
     * Handler for more complex cases
9872
     */
9873
2.58M
    c = CUR_CHAR(l);
9874
2.58M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9875
2.58M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9876
2.58M
        (c == '*') || /* accelerators */
9877
2.58M
  (!IS_LETTER(c) && (c != '_') &&
9878
2.46M
         ((!qualified) || (c != ':')))) {
9879
180k
  return(NULL);
9880
180k
    }
9881
9882
13.0M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9883
13.0M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9884
13.0M
            (c == '.') || (c == '-') ||
9885
13.0M
      (c == '_') || ((qualified) && (c == ':')) ||
9886
13.0M
      (IS_COMBINING(c)) ||
9887
13.0M
      (IS_EXTENDER(c)))) {
9888
10.6M
  COPY_BUF(l,buf,len,c);
9889
10.6M
  NEXTL(l);
9890
10.6M
  c = CUR_CHAR(l);
9891
10.6M
  if (len >= XML_MAX_NAMELEN) {
9892
      /*
9893
       * Okay someone managed to make a huge name, so he's ready to pay
9894
       * for the processing speed.
9895
       */
9896
6.35k
      xmlChar *buffer;
9897
6.35k
      int max = len * 2;
9898
9899
6.35k
            if (len > XML_MAX_NAME_LENGTH) {
9900
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9901
0
            }
9902
6.35k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9903
6.35k
      if (buffer == NULL) {
9904
3
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9905
0
      }
9906
6.35k
      memcpy(buffer, buf, len);
9907
2.37M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9908
2.37M
       (c == '.') || (c == '-') ||
9909
2.37M
       (c == '_') || ((qualified) && (c == ':')) ||
9910
2.37M
       (IS_COMBINING(c)) ||
9911
2.37M
       (IS_EXTENDER(c))) {
9912
2.36M
    if (len + 10 > max) {
9913
1.82k
                    xmlChar *tmp;
9914
1.82k
                    if (max > XML_MAX_NAME_LENGTH) {
9915
82
                        xmlFree(buffer);
9916
82
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9917
0
                    }
9918
1.74k
        max *= 2;
9919
1.74k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9920
1.74k
        if (tmp == NULL) {
9921
1
                        xmlFree(buffer);
9922
1
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9923
0
        }
9924
1.74k
                    buffer = tmp;
9925
1.74k
    }
9926
2.36M
    COPY_BUF(l,buffer,len,c);
9927
2.36M
    NEXTL(l);
9928
2.36M
    c = CUR_CHAR(l);
9929
2.36M
      }
9930
6.26k
      buffer[len] = 0;
9931
6.26k
      return(buffer);
9932
6.35k
  }
9933
10.6M
    }
9934
2.39M
    if (len == 0)
9935
0
  return(NULL);
9936
2.39M
    return(xmlStrndup(buf, len));
9937
2.39M
}
9938
9939
185k
#define MAX_FRAC 20
9940
9941
/**
9942
 * xmlXPathStringEvalNumber:
9943
 * @str:  A string to scan
9944
 *
9945
 *  [30a]  Float  ::= Number ('e' Digits?)?
9946
 *
9947
 *  [30]   Number ::=   Digits ('.' Digits?)?
9948
 *                    | '.' Digits
9949
 *  [31]   Digits ::=   [0-9]+
9950
 *
9951
 * Compile a Number in the string
9952
 * In complement of the Number expression, this function also handles
9953
 * negative values : '-' Number.
9954
 *
9955
 * Returns the double value.
9956
 */
9957
double
9958
1.62M
xmlXPathStringEvalNumber(const xmlChar *str) {
9959
1.62M
    const xmlChar *cur = str;
9960
1.62M
    double ret;
9961
1.62M
    int ok = 0;
9962
1.62M
    int isneg = 0;
9963
1.62M
    int exponent = 0;
9964
1.62M
    int is_exponent_negative = 0;
9965
1.62M
#ifdef __GNUC__
9966
1.62M
    unsigned long tmp = 0;
9967
1.62M
    double temp;
9968
1.62M
#endif
9969
1.62M
    if (cur == NULL) return(0);
9970
1.62M
    while (IS_BLANK_CH(*cur)) cur++;
9971
1.62M
    if (*cur == '-') {
9972
27.6k
  isneg = 1;
9973
27.6k
  cur++;
9974
27.6k
    }
9975
1.62M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9976
1.32M
        return(xmlXPathNAN);
9977
1.32M
    }
9978
9979
297k
#ifdef __GNUC__
9980
    /*
9981
     * tmp/temp is a workaround against a gcc compiler bug
9982
     * http://veillard.com/gcc.bug
9983
     */
9984
297k
    ret = 0;
9985
428k
    while ((*cur >= '0') && (*cur <= '9')) {
9986
131k
  ret = ret * 10;
9987
131k
  tmp = (*cur - '0');
9988
131k
  ok = 1;
9989
131k
  cur++;
9990
131k
  temp = (double) tmp;
9991
131k
  ret = ret + temp;
9992
131k
    }
9993
#else
9994
    ret = 0;
9995
    while ((*cur >= '0') && (*cur <= '9')) {
9996
  ret = ret * 10 + (*cur - '0');
9997
  ok = 1;
9998
  cur++;
9999
    }
10000
#endif
10001
10002
297k
    if (*cur == '.') {
10003
253k
  int v, frac = 0, max;
10004
253k
  double fraction = 0;
10005
10006
253k
        cur++;
10007
253k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10008
234k
      return(xmlXPathNAN);
10009
234k
  }
10010
25.7k
        while (*cur == '0') {
10011
6.73k
      frac = frac + 1;
10012
6.73k
      cur++;
10013
6.73k
        }
10014
19.0k
        max = frac + MAX_FRAC;
10015
46.7k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10016
27.7k
      v = (*cur - '0');
10017
27.7k
      fraction = fraction * 10 + v;
10018
27.7k
      frac = frac + 1;
10019
27.7k
      cur++;
10020
27.7k
  }
10021
19.0k
  fraction /= pow(10.0, frac);
10022
19.0k
  ret = ret + fraction;
10023
19.3k
  while ((*cur >= '0') && (*cur <= '9'))
10024
296
      cur++;
10025
19.0k
    }
10026
62.6k
    if ((*cur == 'e') || (*cur == 'E')) {
10027
14.1k
      cur++;
10028
14.1k
      if (*cur == '-') {
10029
279
  is_exponent_negative = 1;
10030
279
  cur++;
10031
13.8k
      } else if (*cur == '+') {
10032
554
        cur++;
10033
554
      }
10034
102k
      while ((*cur >= '0') && (*cur <= '9')) {
10035
88.2k
        if (exponent < 1000000)
10036
70.2k
    exponent = exponent * 10 + (*cur - '0');
10037
88.2k
  cur++;
10038
88.2k
      }
10039
14.1k
    }
10040
62.6k
    while (IS_BLANK_CH(*cur)) cur++;
10041
62.6k
    if (*cur != 0) return(xmlXPathNAN);
10042
31.6k
    if (isneg) ret = -ret;
10043
31.6k
    if (is_exponent_negative) exponent = -exponent;
10044
31.6k
    ret *= pow(10.0, (double)exponent);
10045
31.6k
    return(ret);
10046
62.6k
}
10047
10048
/**
10049
 * xmlXPathCompNumber:
10050
 * @ctxt:  the XPath Parser context
10051
 *
10052
 *  [30]   Number ::=   Digits ('.' Digits?)?
10053
 *                    | '.' Digits
10054
 *  [31]   Digits ::=   [0-9]+
10055
 *
10056
 * Compile a Number, then push it on the stack
10057
 *
10058
 */
10059
static void
10060
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10061
967k
{
10062
967k
    double ret = 0.0;
10063
967k
    int ok = 0;
10064
967k
    int exponent = 0;
10065
967k
    int is_exponent_negative = 0;
10066
967k
    xmlXPathObjectPtr num;
10067
967k
#ifdef __GNUC__
10068
967k
    unsigned long tmp = 0;
10069
967k
    double temp;
10070
967k
#endif
10071
10072
967k
    CHECK_ERROR;
10073
966k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10074
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10075
0
    }
10076
966k
#ifdef __GNUC__
10077
    /*
10078
     * tmp/temp is a workaround against a gcc compiler bug
10079
     * http://veillard.com/gcc.bug
10080
     */
10081
966k
    ret = 0;
10082
2.84M
    while ((CUR >= '0') && (CUR <= '9')) {
10083
1.87M
  ret = ret * 10;
10084
1.87M
  tmp = (CUR - '0');
10085
1.87M
        ok = 1;
10086
1.87M
        NEXT;
10087
1.87M
  temp = (double) tmp;
10088
1.87M
  ret = ret + temp;
10089
1.87M
    }
10090
#else
10091
    ret = 0;
10092
    while ((CUR >= '0') && (CUR <= '9')) {
10093
  ret = ret * 10 + (CUR - '0');
10094
  ok = 1;
10095
  NEXT;
10096
    }
10097
#endif
10098
966k
    if (CUR == '.') {
10099
166k
  int v, frac = 0, max;
10100
166k
  double fraction = 0;
10101
10102
166k
        NEXT;
10103
166k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10104
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10105
0
        }
10106
240k
        while (CUR == '0') {
10107
74.2k
            frac = frac + 1;
10108
74.2k
            NEXT;
10109
74.2k
        }
10110
166k
        max = frac + MAX_FRAC;
10111
465k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10112
298k
      v = (CUR - '0');
10113
298k
      fraction = fraction * 10 + v;
10114
298k
      frac = frac + 1;
10115
298k
            NEXT;
10116
298k
        }
10117
166k
        fraction /= pow(10.0, frac);
10118
166k
        ret = ret + fraction;
10119
166k
        while ((CUR >= '0') && (CUR <= '9'))
10120
377
            NEXT;
10121
166k
    }
10122
966k
    if ((CUR == 'e') || (CUR == 'E')) {
10123
63.3k
        NEXT;
10124
63.3k
        if (CUR == '-') {
10125
574
            is_exponent_negative = 1;
10126
574
            NEXT;
10127
62.7k
        } else if (CUR == '+') {
10128
727
      NEXT;
10129
727
  }
10130
328k
        while ((CUR >= '0') && (CUR <= '9')) {
10131
265k
            if (exponent < 1000000)
10132
237k
                exponent = exponent * 10 + (CUR - '0');
10133
265k
            NEXT;
10134
265k
        }
10135
63.3k
        if (is_exponent_negative)
10136
574
            exponent = -exponent;
10137
63.3k
        ret *= pow(10.0, (double) exponent);
10138
63.3k
    }
10139
966k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10140
966k
    if (num == NULL) {
10141
21
  ctxt->error = XPATH_MEMORY_ERROR;
10142
966k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10143
966k
                              NULL) == -1) {
10144
7
        xmlXPathReleaseObject(ctxt->context, num);
10145
7
    }
10146
966k
}
10147
10148
/**
10149
 * xmlXPathParseLiteral:
10150
 * @ctxt:  the XPath Parser context
10151
 *
10152
 * Parse a Literal
10153
 *
10154
 *  [29]   Literal ::=   '"' [^"]* '"'
10155
 *                    | "'" [^']* "'"
10156
 *
10157
 * Returns the value found or NULL in case of error
10158
 */
10159
static xmlChar *
10160
2.26k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10161
2.26k
    const xmlChar *q;
10162
2.26k
    xmlChar *ret = NULL;
10163
10164
2.26k
    if (CUR == '"') {
10165
1.41k
        NEXT;
10166
1.41k
  q = CUR_PTR;
10167
54.9k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10168
53.5k
      NEXT;
10169
1.41k
  if (!IS_CHAR_CH(CUR)) {
10170
423
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10171
994
  } else {
10172
994
      ret = xmlStrndup(q, CUR_PTR - q);
10173
994
      NEXT;
10174
994
        }
10175
1.41k
    } else if (CUR == '\'') {
10176
492
        NEXT;
10177
492
  q = CUR_PTR;
10178
29.0k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10179
28.5k
      NEXT;
10180
492
  if (!IS_CHAR_CH(CUR)) {
10181
302
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10182
190
  } else {
10183
190
      ret = xmlStrndup(q, CUR_PTR - q);
10184
190
      NEXT;
10185
190
        }
10186
492
    } else {
10187
359
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10188
0
    }
10189
1.18k
    return(ret);
10190
2.26k
}
10191
10192
/**
10193
 * xmlXPathCompLiteral:
10194
 * @ctxt:  the XPath Parser context
10195
 *
10196
 * Parse a Literal and push it on the stack.
10197
 *
10198
 *  [29]   Literal ::=   '"' [^"]* '"'
10199
 *                    | "'" [^']* "'"
10200
 *
10201
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10202
 */
10203
static void
10204
250k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10205
250k
    const xmlChar *q;
10206
250k
    xmlChar *ret = NULL;
10207
250k
    xmlXPathObjectPtr lit;
10208
10209
250k
    if (CUR == '"') {
10210
143k
        NEXT;
10211
143k
  q = CUR_PTR;
10212
473k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10213
329k
      NEXT;
10214
143k
  if (!IS_CHAR_CH(CUR)) {
10215
6.17k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10216
137k
  } else {
10217
137k
      ret = xmlStrndup(q, CUR_PTR - q);
10218
137k
      NEXT;
10219
137k
        }
10220
143k
    } else if (CUR == '\'') {
10221
107k
        NEXT;
10222
107k
  q = CUR_PTR;
10223
549k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10224
441k
      NEXT;
10225
107k
  if (!IS_CHAR_CH(CUR)) {
10226
6.37k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10227
100k
  } else {
10228
100k
      ret = xmlStrndup(q, CUR_PTR - q);
10229
100k
      NEXT;
10230
100k
        }
10231
107k
    } else {
10232
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10233
0
    }
10234
237k
    if (ret == NULL) {
10235
12
        xmlXPathPErrMemory(ctxt, NULL);
10236
12
        return;
10237
12
    }
10238
237k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10239
237k
    if (lit == NULL) {
10240
13
  ctxt->error = XPATH_MEMORY_ERROR;
10241
237k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10242
237k
                              NULL) == -1) {
10243
2
        xmlXPathReleaseObject(ctxt->context, lit);
10244
2
    }
10245
237k
    xmlFree(ret);
10246
237k
}
10247
10248
/**
10249
 * xmlXPathCompVariableReference:
10250
 * @ctxt:  the XPath Parser context
10251
 *
10252
 * Parse a VariableReference, evaluate it and push it on the stack.
10253
 *
10254
 * The variable bindings consist of a mapping from variable names
10255
 * to variable values. The value of a variable is an object, which can be
10256
 * of any of the types that are possible for the value of an expression,
10257
 * and may also be of additional types not specified here.
10258
 *
10259
 * Early evaluation is possible since:
10260
 * The variable bindings [...] used to evaluate a subexpression are
10261
 * always the same as those used to evaluate the containing expression.
10262
 *
10263
 *  [36]   VariableReference ::=   '$' QName
10264
 */
10265
static void
10266
88.0k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10267
88.0k
    xmlChar *name;
10268
88.0k
    xmlChar *prefix;
10269
10270
88.0k
    SKIP_BLANKS;
10271
88.0k
    if (CUR != '$') {
10272
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10273
0
    }
10274
88.0k
    NEXT;
10275
88.0k
    name = xmlXPathParseQName(ctxt, &prefix);
10276
88.0k
    if (name == NULL) {
10277
2.93k
        xmlFree(prefix);
10278
2.93k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10279
0
    }
10280
85.1k
    ctxt->comp->last = -1;
10281
85.1k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10282
1
        xmlFree(prefix);
10283
1
        xmlFree(name);
10284
1
    }
10285
85.1k
    SKIP_BLANKS;
10286
85.1k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10287
223
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10288
0
    }
10289
85.1k
}
10290
10291
/**
10292
 * xmlXPathIsNodeType:
10293
 * @name:  a name string
10294
 *
10295
 * Is the name given a NodeType one.
10296
 *
10297
 *  [38]   NodeType ::=   'comment'
10298
 *                    | 'text'
10299
 *                    | 'processing-instruction'
10300
 *                    | 'node'
10301
 *
10302
 * Returns 1 if true 0 otherwise
10303
 */
10304
int
10305
1.14M
xmlXPathIsNodeType(const xmlChar *name) {
10306
1.14M
    if (name == NULL)
10307
0
  return(0);
10308
10309
1.14M
    if (xmlStrEqual(name, BAD_CAST "node"))
10310
12.4k
  return(1);
10311
1.13M
    if (xmlStrEqual(name, BAD_CAST "text"))
10312
37.4k
  return(1);
10313
1.09M
    if (xmlStrEqual(name, BAD_CAST "comment"))
10314
345
  return(1);
10315
1.09M
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10316
774
  return(1);
10317
1.09M
    return(0);
10318
1.09M
}
10319
10320
/**
10321
 * xmlXPathCompFunctionCall:
10322
 * @ctxt:  the XPath Parser context
10323
 *
10324
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10325
 *  [17]   Argument ::=   Expr
10326
 *
10327
 * Compile a function call, the evaluation of all arguments are
10328
 * pushed on the stack
10329
 */
10330
static void
10331
1.07M
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10332
1.07M
    xmlChar *name;
10333
1.07M
    xmlChar *prefix;
10334
1.07M
    int nbargs = 0;
10335
1.07M
    int sort = 1;
10336
10337
1.07M
    name = xmlXPathParseQName(ctxt, &prefix);
10338
1.07M
    if (name == NULL) {
10339
817
  xmlFree(prefix);
10340
817
  XP_ERROR(XPATH_EXPR_ERROR);
10341
0
    }
10342
1.07M
    SKIP_BLANKS;
10343
#ifdef DEBUG_EXPR
10344
    if (prefix == NULL)
10345
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10346
      name);
10347
    else
10348
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10349
      prefix, name);
10350
#endif
10351
10352
1.07M
    if (CUR != '(') {
10353
989
  xmlFree(name);
10354
989
  xmlFree(prefix);
10355
989
  XP_ERROR(XPATH_EXPR_ERROR);
10356
0
    }
10357
1.06M
    NEXT;
10358
1.06M
    SKIP_BLANKS;
10359
10360
    /*
10361
    * Optimization for count(): we don't need the node-set to be sorted.
10362
    */
10363
1.06M
    if ((prefix == NULL) && (name[0] == 'c') &&
10364
1.06M
  xmlStrEqual(name, BAD_CAST "count"))
10365
2.35k
    {
10366
2.35k
  sort = 0;
10367
2.35k
    }
10368
1.06M
    ctxt->comp->last = -1;
10369
1.06M
    if (CUR != ')') {
10370
1.75M
  while (CUR != 0) {
10371
1.74M
      int op1 = ctxt->comp->last;
10372
1.74M
      ctxt->comp->last = -1;
10373
1.74M
      xmlXPathCompileExpr(ctxt, sort);
10374
1.74M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10375
152k
    xmlFree(name);
10376
152k
    xmlFree(prefix);
10377
152k
    return;
10378
152k
      }
10379
1.59M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10380
1.59M
      nbargs++;
10381
1.59M
      if (CUR == ')') break;
10382
805k
      if (CUR != ',') {
10383
5.12k
    xmlFree(name);
10384
5.12k
    xmlFree(prefix);
10385
5.12k
    XP_ERROR(XPATH_EXPR_ERROR);
10386
0
      }
10387
800k
      NEXT;
10388
800k
      SKIP_BLANKS;
10389
800k
  }
10390
957k
    }
10391
911k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10392
13
        xmlFree(prefix);
10393
13
        xmlFree(name);
10394
13
    }
10395
911k
    NEXT;
10396
911k
    SKIP_BLANKS;
10397
911k
}
10398
10399
/**
10400
 * xmlXPathCompPrimaryExpr:
10401
 * @ctxt:  the XPath Parser context
10402
 *
10403
 *  [15]   PrimaryExpr ::=   VariableReference
10404
 *                | '(' Expr ')'
10405
 *                | Literal
10406
 *                | Number
10407
 *                | FunctionCall
10408
 *
10409
 * Compile a primary expression.
10410
 */
10411
static void
10412
2.55M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10413
2.55M
    SKIP_BLANKS;
10414
2.55M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10415
2.46M
    else if (CUR == '(') {
10416
178k
  NEXT;
10417
178k
  SKIP_BLANKS;
10418
178k
  xmlXPathCompileExpr(ctxt, 1);
10419
178k
  CHECK_ERROR;
10420
101k
  if (CUR != ')') {
10421
19.2k
      XP_ERROR(XPATH_EXPR_ERROR);
10422
0
  }
10423
81.9k
  NEXT;
10424
81.9k
  SKIP_BLANKS;
10425
2.28M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10426
967k
  xmlXPathCompNumber(ctxt);
10427
1.32M
    } else if ((CUR == '\'') || (CUR == '"')) {
10428
250k
  xmlXPathCompLiteral(ctxt);
10429
1.07M
    } else {
10430
1.07M
  xmlXPathCompFunctionCall(ctxt);
10431
1.07M
    }
10432
2.45M
    SKIP_BLANKS;
10433
2.45M
}
10434
10435
/**
10436
 * xmlXPathCompFilterExpr:
10437
 * @ctxt:  the XPath Parser context
10438
 *
10439
 *  [20]   FilterExpr ::=   PrimaryExpr
10440
 *               | FilterExpr Predicate
10441
 *
10442
 * Compile a filter expression.
10443
 * Square brackets are used to filter expressions in the same way that
10444
 * they are used in location paths. It is an error if the expression to
10445
 * be filtered does not evaluate to a node-set. The context node list
10446
 * used for evaluating the expression in square brackets is the node-set
10447
 * to be filtered listed in document order.
10448
 */
10449
10450
static void
10451
2.55M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10452
2.55M
    xmlXPathCompPrimaryExpr(ctxt);
10453
2.55M
    CHECK_ERROR;
10454
2.28M
    SKIP_BLANKS;
10455
10456
2.62M
    while (CUR == '[') {
10457
339k
  xmlXPathCompPredicate(ctxt, 1);
10458
339k
  SKIP_BLANKS;
10459
339k
    }
10460
10461
10462
2.28M
}
10463
10464
/**
10465
 * xmlXPathScanName:
10466
 * @ctxt:  the XPath Parser context
10467
 *
10468
 * Trickery: parse an XML name but without consuming the input flow
10469
 * Needed to avoid insanity in the parser state.
10470
 *
10471
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10472
 *                  CombiningChar | Extender
10473
 *
10474
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10475
 *
10476
 * [6] Names ::= Name (S Name)*
10477
 *
10478
 * Returns the Name parsed or NULL
10479
 */
10480
10481
static xmlChar *
10482
2.46M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10483
2.46M
    int l;
10484
2.46M
    int c;
10485
2.46M
    const xmlChar *cur;
10486
2.46M
    xmlChar *ret;
10487
10488
2.46M
    cur = ctxt->cur;
10489
10490
2.46M
    c = CUR_CHAR(l);
10491
2.46M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10492
2.46M
  (!IS_LETTER(c) && (c != '_') &&
10493
2.45M
         (c != ':'))) {
10494
180k
  return(NULL);
10495
180k
    }
10496
10497
17.3M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10498
17.3M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10499
16.8M
            (c == '.') || (c == '-') ||
10500
16.8M
      (c == '_') || (c == ':') ||
10501
16.8M
      (IS_COMBINING(c)) ||
10502
16.8M
      (IS_EXTENDER(c)))) {
10503
15.0M
  NEXTL(l);
10504
15.0M
  c = CUR_CHAR(l);
10505
15.0M
    }
10506
2.28M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10507
2.28M
    ctxt->cur = cur;
10508
2.28M
    return(ret);
10509
2.46M
}
10510
10511
/**
10512
 * xmlXPathCompPathExpr:
10513
 * @ctxt:  the XPath Parser context
10514
 *
10515
 *  [19]   PathExpr ::=   LocationPath
10516
 *               | FilterExpr
10517
 *               | FilterExpr '/' RelativeLocationPath
10518
 *               | FilterExpr '//' RelativeLocationPath
10519
 *
10520
 * Compile a path expression.
10521
 * The / operator and // operators combine an arbitrary expression
10522
 * and a relative location path. It is an error if the expression
10523
 * does not evaluate to a node-set.
10524
 * The / operator does composition in the same way as when / is
10525
 * used in a location path. As in location paths, // is short for
10526
 * /descendant-or-self::node()/.
10527
 */
10528
10529
static void
10530
42.5M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10531
42.5M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10532
42.5M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10533
10534
42.5M
    SKIP_BLANKS;
10535
42.5M
    if ((CUR == '$') || (CUR == '(') ||
10536
42.5M
  (IS_ASCII_DIGIT(CUR)) ||
10537
42.5M
        (CUR == '\'') || (CUR == '"') ||
10538
42.5M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10539
1.48M
  lc = 0;
10540
41.0M
    } else if (CUR == '*') {
10541
  /* relative or absolute location path */
10542
36.0M
  lc = 1;
10543
36.0M
    } else if (CUR == '/') {
10544
  /* relative or absolute location path */
10545
1.34M
  lc = 1;
10546
3.67M
    } else if (CUR == '@') {
10547
  /* relative abbreviated attribute location path */
10548
66.7k
  lc = 1;
10549
3.61M
    } else if (CUR == '.') {
10550
  /* relative abbreviated attribute location path */
10551
1.14M
  lc = 1;
10552
2.46M
    } else {
10553
  /*
10554
   * Problem is finding if we have a name here whether it's:
10555
   *   - a nodetype
10556
   *   - a function call in which case it's followed by '('
10557
   *   - an axis in which case it's followed by ':'
10558
   *   - a element name
10559
   * We do an a priori analysis here rather than having to
10560
   * maintain parsed token content through the recursive function
10561
   * calls. This looks uglier but makes the code easier to
10562
   * read/write/debug.
10563
   */
10564
2.46M
  SKIP_BLANKS;
10565
2.46M
  name = xmlXPathScanName(ctxt);
10566
2.46M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10567
#ifdef DEBUG_STEP
10568
      xmlGenericError(xmlGenericErrorContext,
10569
        "PathExpr: Axis\n");
10570
#endif
10571
8.40k
      lc = 1;
10572
8.40k
      xmlFree(name);
10573
2.45M
  } else if (name != NULL) {
10574
2.27M
      int len =xmlStrlen(name);
10575
10576
10577
2.87M
      while (NXT(len) != 0) {
10578
2.84M
    if (NXT(len) == '/') {
10579
        /* element name */
10580
#ifdef DEBUG_STEP
10581
        xmlGenericError(xmlGenericErrorContext,
10582
          "PathExpr: AbbrRelLocation\n");
10583
#endif
10584
197k
        lc = 1;
10585
197k
        break;
10586
2.64M
    } else if (IS_BLANK_CH(NXT(len))) {
10587
        /* ignore blanks */
10588
596k
        ;
10589
2.04M
    } else if (NXT(len) == ':') {
10590
#ifdef DEBUG_STEP
10591
        xmlGenericError(xmlGenericErrorContext,
10592
          "PathExpr: AbbrRelLocation\n");
10593
#endif
10594
1.15k
        lc = 1;
10595
1.15k
        break;
10596
2.04M
    } else if ((NXT(len) == '(')) {
10597
        /* Node Type or Function */
10598
1.12M
        if (xmlXPathIsNodeType(name)) {
10599
#ifdef DEBUG_STEP
10600
            xmlGenericError(xmlGenericErrorContext,
10601
        "PathExpr: Type search\n");
10602
#endif
10603
48.4k
      lc = 1;
10604
#ifdef LIBXML_XPTR_LOCS_ENABLED
10605
                    } else if (ctxt->xptr &&
10606
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10607
                        lc = 1;
10608
#endif
10609
1.07M
        } else {
10610
#ifdef DEBUG_STEP
10611
            xmlGenericError(xmlGenericErrorContext,
10612
        "PathExpr: function call\n");
10613
#endif
10614
1.07M
      lc = 0;
10615
1.07M
        }
10616
1.12M
                    break;
10617
1.12M
    } else if ((NXT(len) == '[')) {
10618
        /* element name */
10619
#ifdef DEBUG_STEP
10620
        xmlGenericError(xmlGenericErrorContext,
10621
          "PathExpr: AbbrRelLocation\n");
10622
#endif
10623
30.4k
        lc = 1;
10624
30.4k
        break;
10625
897k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10626
897k
         (NXT(len) == '=')) {
10627
474k
        lc = 1;
10628
474k
        break;
10629
474k
    } else {
10630
423k
        lc = 1;
10631
423k
        break;
10632
423k
    }
10633
596k
    len++;
10634
596k
      }
10635
2.27M
      if (NXT(len) == 0) {
10636
#ifdef DEBUG_STEP
10637
    xmlGenericError(xmlGenericErrorContext,
10638
      "PathExpr: AbbrRelLocation\n");
10639
#endif
10640
    /* element name */
10641
27.8k
    lc = 1;
10642
27.8k
      }
10643
2.27M
      xmlFree(name);
10644
2.27M
  } else {
10645
      /* make sure all cases are covered explicitly */
10646
180k
      XP_ERROR(XPATH_EXPR_ERROR);
10647
0
  }
10648
2.46M
    }
10649
10650
42.3M
    if (lc) {
10651
39.7M
  if (CUR == '/') {
10652
1.34M
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10653
38.4M
  } else {
10654
38.4M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10655
38.4M
  }
10656
39.7M
  xmlXPathCompLocationPath(ctxt);
10657
39.7M
    } else {
10658
2.55M
  xmlXPathCompFilterExpr(ctxt);
10659
2.55M
  CHECK_ERROR;
10660
2.23M
  if ((CUR == '/') && (NXT(1) == '/')) {
10661
11.1k
      SKIP(2);
10662
11.1k
      SKIP_BLANKS;
10663
10664
11.1k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10665
11.1k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10666
10667
11.1k
      xmlXPathCompRelativeLocationPath(ctxt);
10668
2.22M
  } else if (CUR == '/') {
10669
302k
      xmlXPathCompRelativeLocationPath(ctxt);
10670
302k
  }
10671
2.23M
    }
10672
42.0M
    SKIP_BLANKS;
10673
42.0M
}
10674
10675
/**
10676
 * xmlXPathCompUnionExpr:
10677
 * @ctxt:  the XPath Parser context
10678
 *
10679
 *  [18]   UnionExpr ::=   PathExpr
10680
 *               | UnionExpr '|' PathExpr
10681
 *
10682
 * Compile an union expression.
10683
 */
10684
10685
static void
10686
42.0M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10687
42.0M
    xmlXPathCompPathExpr(ctxt);
10688
42.0M
    CHECK_ERROR;
10689
41.4M
    SKIP_BLANKS;
10690
41.9M
    while (CUR == '|') {
10691
486k
  int op1 = ctxt->comp->last;
10692
486k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10693
10694
486k
  NEXT;
10695
486k
  SKIP_BLANKS;
10696
486k
  xmlXPathCompPathExpr(ctxt);
10697
10698
486k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10699
10700
486k
  SKIP_BLANKS;
10701
486k
    }
10702
41.4M
}
10703
10704
/**
10705
 * xmlXPathCompUnaryExpr:
10706
 * @ctxt:  the XPath Parser context
10707
 *
10708
 *  [27]   UnaryExpr ::=   UnionExpr
10709
 *                   | '-' UnaryExpr
10710
 *
10711
 * Compile an unary expression.
10712
 */
10713
10714
static void
10715
42.0M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10716
42.0M
    int minus = 0;
10717
42.0M
    int found = 0;
10718
10719
42.0M
    SKIP_BLANKS;
10720
46.7M
    while (CUR == '-') {
10721
4.70M
        minus = 1 - minus;
10722
4.70M
  found = 1;
10723
4.70M
  NEXT;
10724
4.70M
  SKIP_BLANKS;
10725
4.70M
    }
10726
10727
42.0M
    xmlXPathCompUnionExpr(ctxt);
10728
42.0M
    CHECK_ERROR;
10729
41.4M
    if (found) {
10730
948k
  if (minus)
10731
560k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10732
388k
  else
10733
388k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10734
948k
    }
10735
41.4M
}
10736
10737
/**
10738
 * xmlXPathCompMultiplicativeExpr:
10739
 * @ctxt:  the XPath Parser context
10740
 *
10741
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10742
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10743
 *                   | MultiplicativeExpr 'div' UnaryExpr
10744
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10745
 *  [34]   MultiplyOperator ::=   '*'
10746
 *
10747
 * Compile an Additive expression.
10748
 */
10749
10750
static void
10751
6.14M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10752
6.14M
    xmlXPathCompUnaryExpr(ctxt);
10753
6.14M
    CHECK_ERROR;
10754
5.55M
    SKIP_BLANKS;
10755
41.4M
    while ((CUR == '*') ||
10756
41.4M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10757
41.4M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10758
35.8M
  int op = -1;
10759
35.8M
  int op1 = ctxt->comp->last;
10760
10761
35.8M
        if (CUR == '*') {
10762
35.6M
      op = 0;
10763
35.6M
      NEXT;
10764
35.6M
  } else if (CUR == 'd') {
10765
1.43k
      op = 1;
10766
1.43k
      SKIP(3);
10767
196k
  } else if (CUR == 'm') {
10768
196k
      op = 2;
10769
196k
      SKIP(3);
10770
196k
  }
10771
35.8M
  SKIP_BLANKS;
10772
35.8M
        xmlXPathCompUnaryExpr(ctxt);
10773
35.8M
  CHECK_ERROR;
10774
35.8M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10775
35.8M
  SKIP_BLANKS;
10776
35.8M
    }
10777
5.55M
}
10778
10779
/**
10780
 * xmlXPathCompAdditiveExpr:
10781
 * @ctxt:  the XPath Parser context
10782
 *
10783
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10784
 *                   | AdditiveExpr '+' MultiplicativeExpr
10785
 *                   | AdditiveExpr '-' MultiplicativeExpr
10786
 *
10787
 * Compile an Additive expression.
10788
 */
10789
10790
static void
10791
4.92M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10792
10793
4.92M
    xmlXPathCompMultiplicativeExpr(ctxt);
10794
4.92M
    CHECK_ERROR;
10795
4.44M
    SKIP_BLANKS;
10796
5.54M
    while ((CUR == '+') || (CUR == '-')) {
10797
1.21M
  int plus;
10798
1.21M
  int op1 = ctxt->comp->last;
10799
10800
1.21M
        if (CUR == '+') plus = 1;
10801
970k
  else plus = 0;
10802
1.21M
  NEXT;
10803
1.21M
  SKIP_BLANKS;
10804
1.21M
        xmlXPathCompMultiplicativeExpr(ctxt);
10805
1.21M
  CHECK_ERROR;
10806
1.09M
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10807
1.09M
  SKIP_BLANKS;
10808
1.09M
    }
10809
4.44M
}
10810
10811
/**
10812
 * xmlXPathCompRelationalExpr:
10813
 * @ctxt:  the XPath Parser context
10814
 *
10815
 *  [24]   RelationalExpr ::=   AdditiveExpr
10816
 *                 | RelationalExpr '<' AdditiveExpr
10817
 *                 | RelationalExpr '>' AdditiveExpr
10818
 *                 | RelationalExpr '<=' AdditiveExpr
10819
 *                 | RelationalExpr '>=' AdditiveExpr
10820
 *
10821
 *  A <= B > C is allowed ? Answer from James, yes with
10822
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10823
 *  which is basically what got implemented.
10824
 *
10825
 * Compile a Relational expression, then push the result
10826
 * on the stack
10827
 */
10828
10829
static void
10830
4.36M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10831
4.36M
    xmlXPathCompAdditiveExpr(ctxt);
10832
4.36M
    CHECK_ERROR;
10833
3.83M
    SKIP_BLANKS;
10834
4.33M
    while ((CUR == '<') || (CUR == '>')) {
10835
560k
  int inf, strict;
10836
560k
  int op1 = ctxt->comp->last;
10837
10838
560k
        if (CUR == '<') inf = 1;
10839
560k
  else inf = 0;
10840
560k
  if (NXT(1) == '=') strict = 0;
10841
544k
  else strict = 1;
10842
560k
  NEXT;
10843
560k
  if (!strict) NEXT;
10844
560k
  SKIP_BLANKS;
10845
560k
        xmlXPathCompAdditiveExpr(ctxt);
10846
560k
  CHECK_ERROR;
10847
496k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10848
496k
  SKIP_BLANKS;
10849
496k
    }
10850
3.83M
}
10851
10852
/**
10853
 * xmlXPathCompEqualityExpr:
10854
 * @ctxt:  the XPath Parser context
10855
 *
10856
 *  [23]   EqualityExpr ::=   RelationalExpr
10857
 *                 | EqualityExpr '=' RelationalExpr
10858
 *                 | EqualityExpr '!=' RelationalExpr
10859
 *
10860
 *  A != B != C is allowed ? Answer from James, yes with
10861
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10862
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10863
 *  which is basically what got implemented.
10864
 *
10865
 * Compile an Equality expression.
10866
 *
10867
 */
10868
static void
10869
3.34M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10870
3.34M
    xmlXPathCompRelationalExpr(ctxt);
10871
3.34M
    CHECK_ERROR;
10872
2.89M
    SKIP_BLANKS;
10873
3.77M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10874
1.02M
  int eq;
10875
1.02M
  int op1 = ctxt->comp->last;
10876
10877
1.02M
        if (CUR == '=') eq = 1;
10878
404k
  else eq = 0;
10879
1.02M
  NEXT;
10880
1.02M
  if (!eq) NEXT;
10881
1.02M
  SKIP_BLANKS;
10882
1.02M
        xmlXPathCompRelationalExpr(ctxt);
10883
1.02M
  CHECK_ERROR;
10884
877k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10885
877k
  SKIP_BLANKS;
10886
877k
    }
10887
2.89M
}
10888
10889
/**
10890
 * xmlXPathCompAndExpr:
10891
 * @ctxt:  the XPath Parser context
10892
 *
10893
 *  [22]   AndExpr ::=   EqualityExpr
10894
 *                 | AndExpr 'and' EqualityExpr
10895
 *
10896
 * Compile an AND expression.
10897
 *
10898
 */
10899
static void
10900
3.25M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10901
3.25M
    xmlXPathCompEqualityExpr(ctxt);
10902
3.25M
    CHECK_ERROR;
10903
2.68M
    SKIP_BLANKS;
10904
2.74M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10905
84.4k
  int op1 = ctxt->comp->last;
10906
84.4k
        SKIP(3);
10907
84.4k
  SKIP_BLANKS;
10908
84.4k
        xmlXPathCompEqualityExpr(ctxt);
10909
84.4k
  CHECK_ERROR;
10910
60.1k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10911
60.1k
  SKIP_BLANKS;
10912
60.1k
    }
10913
2.68M
}
10914
10915
/**
10916
 * xmlXPathCompileExpr:
10917
 * @ctxt:  the XPath Parser context
10918
 *
10919
 *  [14]   Expr ::=   OrExpr
10920
 *  [21]   OrExpr ::=   AndExpr
10921
 *                 | OrExpr 'or' AndExpr
10922
 *
10923
 * Parse and compile an expression
10924
 */
10925
static void
10926
3.42M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10927
3.42M
    xmlXPathContextPtr xpctxt = ctxt->context;
10928
10929
3.42M
    if (xpctxt != NULL) {
10930
3.42M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10931
3.23M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10932
        /*
10933
         * Parsing a single '(' pushes about 10 functions on the call stack
10934
         * before recursing!
10935
         */
10936
3.23M
        xpctxt->depth += 10;
10937
3.23M
    }
10938
10939
3.23M
    xmlXPathCompAndExpr(ctxt);
10940
3.23M
    CHECK_ERROR;
10941
2.64M
    SKIP_BLANKS;
10942
2.66M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10943
23.5k
  int op1 = ctxt->comp->last;
10944
23.5k
        SKIP(2);
10945
23.5k
  SKIP_BLANKS;
10946
23.5k
        xmlXPathCompAndExpr(ctxt);
10947
23.5k
  CHECK_ERROR;
10948
17.8k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10949
17.8k
  SKIP_BLANKS;
10950
17.8k
    }
10951
2.63M
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10952
  /* more ops could be optimized too */
10953
  /*
10954
  * This is the main place to eliminate sorting for
10955
  * operations which don't require a sorted node-set.
10956
  * E.g. count().
10957
  */
10958
2.32M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10959
2.32M
    }
10960
10961
2.63M
    if (xpctxt != NULL)
10962
2.63M
        xpctxt->depth -= 10;
10963
2.63M
}
10964
10965
/**
10966
 * xmlXPathCompPredicate:
10967
 * @ctxt:  the XPath Parser context
10968
 * @filter:  act as a filter
10969
 *
10970
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10971
 *  [9]   PredicateExpr ::=   Expr
10972
 *
10973
 * Compile a predicate expression
10974
 */
10975
static void
10976
553k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10977
553k
    int op1 = ctxt->comp->last;
10978
10979
553k
    SKIP_BLANKS;
10980
553k
    if (CUR != '[') {
10981
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10982
0
    }
10983
553k
    NEXT;
10984
553k
    SKIP_BLANKS;
10985
10986
553k
    ctxt->comp->last = -1;
10987
    /*
10988
    * This call to xmlXPathCompileExpr() will deactivate sorting
10989
    * of the predicate result.
10990
    * TODO: Sorting is still activated for filters, since I'm not
10991
    *  sure if needed. Normally sorting should not be needed, since
10992
    *  a filter can only diminish the number of items in a sequence,
10993
    *  but won't change its order; so if the initial sequence is sorted,
10994
    *  subsequent sorting is not needed.
10995
    */
10996
553k
    if (! filter)
10997
214k
  xmlXPathCompileExpr(ctxt, 0);
10998
339k
    else
10999
339k
  xmlXPathCompileExpr(ctxt, 1);
11000
553k
    CHECK_ERROR;
11001
11002
397k
    if (CUR != ']') {
11003
3.98k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11004
0
    }
11005
11006
393k
    if (filter)
11007
288k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11008
105k
    else
11009
105k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11010
11011
393k
    NEXT;
11012
393k
    SKIP_BLANKS;
11013
393k
}
11014
11015
/**
11016
 * xmlXPathCompNodeTest:
11017
 * @ctxt:  the XPath Parser context
11018
 * @test:  pointer to a xmlXPathTestVal
11019
 * @type:  pointer to a xmlXPathTypeVal
11020
 * @prefix:  placeholder for a possible name prefix
11021
 *
11022
 * [7] NodeTest ::=   NameTest
11023
 *        | NodeType '(' ')'
11024
 *        | 'processing-instruction' '(' Literal ')'
11025
 *
11026
 * [37] NameTest ::=  '*'
11027
 *        | NCName ':' '*'
11028
 *        | QName
11029
 * [38] NodeType ::= 'comment'
11030
 *       | 'text'
11031
 *       | 'processing-instruction'
11032
 *       | 'node'
11033
 *
11034
 * Returns the name found and updates @test, @type and @prefix appropriately
11035
 */
11036
static xmlChar *
11037
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11038
               xmlXPathTypeVal *type, xmlChar **prefix,
11039
38.3M
         xmlChar *name) {
11040
38.3M
    int blanks;
11041
11042
38.3M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11043
0
  STRANGE;
11044
0
  return(NULL);
11045
0
    }
11046
38.3M
    *type = (xmlXPathTypeVal) 0;
11047
38.3M
    *test = (xmlXPathTestVal) 0;
11048
38.3M
    *prefix = NULL;
11049
38.3M
    SKIP_BLANKS;
11050
11051
38.3M
    if ((name == NULL) && (CUR == '*')) {
11052
  /*
11053
   * All elements
11054
   */
11055
36.1M
  NEXT;
11056
36.1M
  *test = NODE_TEST_ALL;
11057
36.1M
  return(NULL);
11058
36.1M
    }
11059
11060
2.16M
    if (name == NULL)
11061
122k
  name = xmlXPathParseNCName(ctxt);
11062
2.16M
    if (name == NULL) {
11063
36.9k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11064
0
    }
11065
11066
2.13M
    blanks = IS_BLANK_CH(CUR);
11067
2.13M
    SKIP_BLANKS;
11068
2.13M
    if (CUR == '(') {
11069
322k
  NEXT;
11070
  /*
11071
   * NodeType or PI search
11072
   */
11073
322k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11074
25.0k
      *type = NODE_TYPE_COMMENT;
11075
297k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11076
170k
      *type = NODE_TYPE_NODE;
11077
127k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11078
13.4k
      *type = NODE_TYPE_PI;
11079
114k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11080
103k
      *type = NODE_TYPE_TEXT;
11081
10.5k
  else {
11082
10.5k
      if (name != NULL)
11083
10.5k
    xmlFree(name);
11084
10.5k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11085
0
  }
11086
11087
312k
  *test = NODE_TEST_TYPE;
11088
11089
312k
  SKIP_BLANKS;
11090
312k
  if (*type == NODE_TYPE_PI) {
11091
      /*
11092
       * Specific case: search a PI by name.
11093
       */
11094
13.4k
      if (name != NULL)
11095
13.4k
    xmlFree(name);
11096
13.4k
      name = NULL;
11097
13.4k
      if (CUR != ')') {
11098
2.26k
    name = xmlXPathParseLiteral(ctxt);
11099
2.26k
                if (name == NULL) {
11100
1.08k
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11101
0
                }
11102
1.18k
    *test = NODE_TEST_PI;
11103
1.18k
    SKIP_BLANKS;
11104
1.18k
      }
11105
13.4k
  }
11106
311k
  if (CUR != ')') {
11107
3.07k
      if (name != NULL)
11108
3.07k
    xmlFree(name);
11109
3.07k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11110
0
  }
11111
308k
  NEXT;
11112
308k
  return(name);
11113
311k
    }
11114
1.80M
    *test = NODE_TEST_NAME;
11115
1.80M
    if ((!blanks) && (CUR == ':')) {
11116
151k
  NEXT;
11117
11118
  /*
11119
   * Since currently the parser context don't have a
11120
   * namespace list associated:
11121
   * The namespace name for this prefix can be computed
11122
   * only at evaluation time. The compilation is done
11123
   * outside of any context.
11124
   */
11125
#if 0
11126
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11127
  if (name != NULL)
11128
      xmlFree(name);
11129
  if (*prefix == NULL) {
11130
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11131
  }
11132
#else
11133
151k
  *prefix = name;
11134
151k
#endif
11135
11136
151k
  if (CUR == '*') {
11137
      /*
11138
       * All elements
11139
       */
11140
19.0k
      NEXT;
11141
19.0k
      *test = NODE_TEST_ALL;
11142
19.0k
      return(NULL);
11143
19.0k
  }
11144
11145
132k
  name = xmlXPathParseNCName(ctxt);
11146
132k
  if (name == NULL) {
11147
19.3k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11148
0
  }
11149
132k
    }
11150
1.76M
    return(name);
11151
1.80M
}
11152
11153
/**
11154
 * xmlXPathIsAxisName:
11155
 * @name:  a preparsed name token
11156
 *
11157
 * [6] AxisName ::=   'ancestor'
11158
 *                  | 'ancestor-or-self'
11159
 *                  | 'attribute'
11160
 *                  | 'child'
11161
 *                  | 'descendant'
11162
 *                  | 'descendant-or-self'
11163
 *                  | 'following'
11164
 *                  | 'following-sibling'
11165
 *                  | 'namespace'
11166
 *                  | 'parent'
11167
 *                  | 'preceding'
11168
 *                  | 'preceding-sibling'
11169
 *                  | 'self'
11170
 *
11171
 * Returns the axis or 0
11172
 */
11173
static xmlXPathAxisVal
11174
2.12M
xmlXPathIsAxisName(const xmlChar *name) {
11175
2.12M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11176
2.12M
    switch (name[0]) {
11177
112k
  case 'a':
11178
112k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11179
456
    ret = AXIS_ANCESTOR;
11180
112k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11181
791
    ret = AXIS_ANCESTOR_OR_SELF;
11182
112k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11183
8.90k
    ret = AXIS_ATTRIBUTE;
11184
112k
      break;
11185
165k
  case 'c':
11186
165k
      if (xmlStrEqual(name, BAD_CAST "child"))
11187
2.62k
    ret = AXIS_CHILD;
11188
165k
      break;
11189
102k
  case 'd':
11190
102k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11191
237
    ret = AXIS_DESCENDANT;
11192
102k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11193
231
    ret = AXIS_DESCENDANT_OR_SELF;
11194
102k
      break;
11195
12.5k
  case 'f':
11196
12.5k
      if (xmlStrEqual(name, BAD_CAST "following"))
11197
1.16k
    ret = AXIS_FOLLOWING;
11198
12.5k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11199
212
    ret = AXIS_FOLLOWING_SIBLING;
11200
12.5k
      break;
11201
603k
  case 'n':
11202
603k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11203
110k
    ret = AXIS_NAMESPACE;
11204
603k
      break;
11205
94.0k
  case 'p':
11206
94.0k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11207
1.13k
    ret = AXIS_PARENT;
11208
94.0k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11209
734
    ret = AXIS_PRECEDING;
11210
94.0k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11211
562
    ret = AXIS_PRECEDING_SIBLING;
11212
94.0k
      break;
11213
52.9k
  case 's':
11214
52.9k
      if (xmlStrEqual(name, BAD_CAST "self"))
11215
3.21k
    ret = AXIS_SELF;
11216
52.9k
      break;
11217
2.12M
    }
11218
2.12M
    return(ret);
11219
2.12M
}
11220
11221
/**
11222
 * xmlXPathCompStep:
11223
 * @ctxt:  the XPath Parser context
11224
 *
11225
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11226
 *                  | AbbreviatedStep
11227
 *
11228
 * [12] AbbreviatedStep ::=   '.' | '..'
11229
 *
11230
 * [5] AxisSpecifier ::= AxisName '::'
11231
 *                  | AbbreviatedAxisSpecifier
11232
 *
11233
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11234
 *
11235
 * Modified for XPtr range support as:
11236
 *
11237
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11238
 *                     | AbbreviatedStep
11239
 *                     | 'range-to' '(' Expr ')' Predicate*
11240
 *
11241
 * Compile one step in a Location Path
11242
 * A location step of . is short for self::node(). This is
11243
 * particularly useful in conjunction with //. For example, the
11244
 * location path .//para is short for
11245
 * self::node()/descendant-or-self::node()/child::para
11246
 * and so will select all para descendant elements of the context
11247
 * node.
11248
 * Similarly, a location step of .. is short for parent::node().
11249
 * For example, ../title is short for parent::node()/child::title
11250
 * and so will select the title children of the parent of the context
11251
 * node.
11252
 */
11253
static void
11254
39.8M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11255
#ifdef LIBXML_XPTR_LOCS_ENABLED
11256
    int rangeto = 0;
11257
    int op2 = -1;
11258
#endif
11259
11260
39.8M
    SKIP_BLANKS;
11261
39.8M
    if ((CUR == '.') && (NXT(1) == '.')) {
11262
100k
  SKIP(2);
11263
100k
  SKIP_BLANKS;
11264
100k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11265
100k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11266
39.7M
    } else if (CUR == '.') {
11267
1.37M
  NEXT;
11268
1.37M
  SKIP_BLANKS;
11269
38.3M
    } else {
11270
38.3M
  xmlChar *name = NULL;
11271
38.3M
  xmlChar *prefix = NULL;
11272
38.3M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11273
38.3M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11274
38.3M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11275
38.3M
  int op1;
11276
11277
  /*
11278
   * The modification needed for XPointer change to the production
11279
   */
11280
#ifdef LIBXML_XPTR_LOCS_ENABLED
11281
  if (ctxt->xptr) {
11282
      name = xmlXPathParseNCName(ctxt);
11283
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11284
                op2 = ctxt->comp->last;
11285
    xmlFree(name);
11286
    SKIP_BLANKS;
11287
    if (CUR != '(') {
11288
        XP_ERROR(XPATH_EXPR_ERROR);
11289
    }
11290
    NEXT;
11291
    SKIP_BLANKS;
11292
11293
    xmlXPathCompileExpr(ctxt, 1);
11294
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11295
    CHECK_ERROR;
11296
11297
    SKIP_BLANKS;
11298
    if (CUR != ')') {
11299
        XP_ERROR(XPATH_EXPR_ERROR);
11300
    }
11301
    NEXT;
11302
    rangeto = 1;
11303
    goto eval_predicates;
11304
      }
11305
  }
11306
#endif
11307
38.3M
  if (CUR == '*') {
11308
36.1M
      axis = AXIS_CHILD;
11309
36.1M
  } else {
11310
2.24M
      if (name == NULL)
11311
2.24M
    name = xmlXPathParseNCName(ctxt);
11312
2.24M
      if (name != NULL) {
11313
2.12M
    axis = xmlXPathIsAxisName(name);
11314
2.12M
    if (axis != 0) {
11315
130k
        SKIP_BLANKS;
11316
130k
        if ((CUR == ':') && (NXT(1) == ':')) {
11317
77.7k
      SKIP(2);
11318
77.7k
      xmlFree(name);
11319
77.7k
      name = NULL;
11320
77.7k
        } else {
11321
      /* an element name can conflict with an axis one :-\ */
11322
52.5k
      axis = AXIS_CHILD;
11323
52.5k
        }
11324
1.99M
    } else {
11325
1.99M
        axis = AXIS_CHILD;
11326
1.99M
    }
11327
2.12M
      } else if (CUR == '@') {
11328
77.0k
    NEXT;
11329
77.0k
    axis = AXIS_ATTRIBUTE;
11330
77.0k
      } else {
11331
40.7k
    axis = AXIS_CHILD;
11332
40.7k
      }
11333
2.24M
  }
11334
11335
38.3M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11336
14.9k
            xmlFree(name);
11337
14.9k
            return;
11338
14.9k
        }
11339
11340
38.3M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11341
38.3M
  if (test == 0)
11342
47.5k
      return;
11343
11344
38.3M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11345
38.3M
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11346
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11347
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11348
0
      }
11349
0
  }
11350
#ifdef DEBUG_STEP
11351
  xmlGenericError(xmlGenericErrorContext,
11352
    "Basis : computing new set\n");
11353
#endif
11354
11355
#ifdef DEBUG_STEP
11356
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11357
  if (ctxt->value == NULL)
11358
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11359
  else if (ctxt->value->nodesetval == NULL)
11360
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11361
  else
11362
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11363
#endif
11364
11365
#ifdef LIBXML_XPTR_LOCS_ENABLED
11366
eval_predicates:
11367
#endif
11368
38.3M
  op1 = ctxt->comp->last;
11369
38.3M
  ctxt->comp->last = -1;
11370
11371
38.3M
  SKIP_BLANKS;
11372
38.5M
  while (CUR == '[') {
11373
214k
      xmlXPathCompPredicate(ctxt, 0);
11374
214k
  }
11375
11376
#ifdef LIBXML_XPTR_LOCS_ENABLED
11377
  if (rangeto) {
11378
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11379
  } else
11380
#endif
11381
38.3M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11382
38.3M
                           test, type, (void *)prefix, (void *)name) == -1) {
11383
73
            xmlFree(prefix);
11384
73
            xmlFree(name);
11385
73
        }
11386
38.3M
    }
11387
#ifdef DEBUG_STEP
11388
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11389
    if (ctxt->value == NULL)
11390
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11391
    else if (ctxt->value->nodesetval == NULL)
11392
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11393
    else
11394
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11395
    ctxt->value->nodesetval);
11396
#endif
11397
39.8M
}
11398
11399
/**
11400
 * xmlXPathCompRelativeLocationPath:
11401
 * @ctxt:  the XPath Parser context
11402
 *
11403
 *  [3]   RelativeLocationPath ::=   Step
11404
 *                     | RelativeLocationPath '/' Step
11405
 *                     | AbbreviatedRelativeLocationPath
11406
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11407
 *
11408
 * Compile a relative location path.
11409
 */
11410
static void
11411
xmlXPathCompRelativeLocationPath
11412
39.2M
(xmlXPathParserContextPtr ctxt) {
11413
39.2M
    SKIP_BLANKS;
11414
39.2M
    if ((CUR == '/') && (NXT(1) == '/')) {
11415
3.00k
  SKIP(2);
11416
3.00k
  SKIP_BLANKS;
11417
3.00k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11418
3.00k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11419
39.2M
    } else if (CUR == '/') {
11420
304k
      NEXT;
11421
304k
  SKIP_BLANKS;
11422
304k
    }
11423
39.2M
    xmlXPathCompStep(ctxt);
11424
39.2M
    CHECK_ERROR;
11425
39.2M
    SKIP_BLANKS;
11426
39.7M
    while (CUR == '/') {
11427
553k
  if ((CUR == '/') && (NXT(1) == '/')) {
11428
64.6k
      SKIP(2);
11429
64.6k
      SKIP_BLANKS;
11430
64.6k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11431
64.6k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11432
64.6k
      xmlXPathCompStep(ctxt);
11433
488k
  } else if (CUR == '/') {
11434
488k
      NEXT;
11435
488k
      SKIP_BLANKS;
11436
488k
      xmlXPathCompStep(ctxt);
11437
488k
  }
11438
553k
  SKIP_BLANKS;
11439
553k
    }
11440
39.2M
}
11441
11442
/**
11443
 * xmlXPathCompLocationPath:
11444
 * @ctxt:  the XPath Parser context
11445
 *
11446
 *  [1]   LocationPath ::=   RelativeLocationPath
11447
 *                     | AbsoluteLocationPath
11448
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11449
 *                     | AbbreviatedAbsoluteLocationPath
11450
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11451
 *                           '//' RelativeLocationPath
11452
 *
11453
 * Compile a location path
11454
 *
11455
 * // is short for /descendant-or-self::node()/. For example,
11456
 * //para is short for /descendant-or-self::node()/child::para and
11457
 * so will select any para element in the document (even a para element
11458
 * that is a document element will be selected by //para since the
11459
 * document element node is a child of the root node); div//para is
11460
 * short for div/descendant-or-self::node()/child::para and so will
11461
 * select all para descendants of div children.
11462
 */
11463
static void
11464
39.7M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11465
39.7M
    SKIP_BLANKS;
11466
39.7M
    if (CUR != '/') {
11467
38.4M
        xmlXPathCompRelativeLocationPath(ctxt);
11468
38.4M
    } else {
11469
2.68M
  while (CUR == '/') {
11470
1.35M
      if ((CUR == '/') && (NXT(1) == '/')) {
11471
277k
    SKIP(2);
11472
277k
    SKIP_BLANKS;
11473
277k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11474
277k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11475
277k
    xmlXPathCompRelativeLocationPath(ctxt);
11476
1.08M
      } else if (CUR == '/') {
11477
1.08M
    NEXT;
11478
1.08M
    SKIP_BLANKS;
11479
1.08M
    if ((CUR != 0 ) &&
11480
1.08M
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11481
1.07M
         (CUR == '@') || (CUR == '*')))
11482
262k
        xmlXPathCompRelativeLocationPath(ctxt);
11483
1.08M
      }
11484
1.35M
      CHECK_ERROR;
11485
1.35M
  }
11486
1.34M
    }
11487
39.7M
}
11488
11489
/************************************************************************
11490
 *                  *
11491
 *    XPath precompiled expression evaluation     *
11492
 *                  *
11493
 ************************************************************************/
11494
11495
static int
11496
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11497
11498
#ifdef DEBUG_STEP
11499
static void
11500
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11501
        int nbNodes)
11502
{
11503
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11504
    switch (op->value) {
11505
        case AXIS_ANCESTOR:
11506
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11507
            break;
11508
        case AXIS_ANCESTOR_OR_SELF:
11509
            xmlGenericError(xmlGenericErrorContext,
11510
                            "axis 'ancestors-or-self' ");
11511
            break;
11512
        case AXIS_ATTRIBUTE:
11513
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11514
            break;
11515
        case AXIS_CHILD:
11516
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11517
            break;
11518
        case AXIS_DESCENDANT:
11519
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11520
            break;
11521
        case AXIS_DESCENDANT_OR_SELF:
11522
            xmlGenericError(xmlGenericErrorContext,
11523
                            "axis 'descendant-or-self' ");
11524
            break;
11525
        case AXIS_FOLLOWING:
11526
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11527
            break;
11528
        case AXIS_FOLLOWING_SIBLING:
11529
            xmlGenericError(xmlGenericErrorContext,
11530
                            "axis 'following-siblings' ");
11531
            break;
11532
        case AXIS_NAMESPACE:
11533
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11534
            break;
11535
        case AXIS_PARENT:
11536
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11537
            break;
11538
        case AXIS_PRECEDING:
11539
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11540
            break;
11541
        case AXIS_PRECEDING_SIBLING:
11542
            xmlGenericError(xmlGenericErrorContext,
11543
                            "axis 'preceding-sibling' ");
11544
            break;
11545
        case AXIS_SELF:
11546
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11547
            break;
11548
    }
11549
    xmlGenericError(xmlGenericErrorContext,
11550
  " context contains %d nodes\n", nbNodes);
11551
    switch (op->value2) {
11552
        case NODE_TEST_NONE:
11553
            xmlGenericError(xmlGenericErrorContext,
11554
                            "           searching for none !!!\n");
11555
            break;
11556
        case NODE_TEST_TYPE:
11557
            xmlGenericError(xmlGenericErrorContext,
11558
                            "           searching for type %d\n", op->value3);
11559
            break;
11560
        case NODE_TEST_PI:
11561
            xmlGenericError(xmlGenericErrorContext,
11562
                            "           searching for PI !!!\n");
11563
            break;
11564
        case NODE_TEST_ALL:
11565
            xmlGenericError(xmlGenericErrorContext,
11566
                            "           searching for *\n");
11567
            break;
11568
        case NODE_TEST_NS:
11569
            xmlGenericError(xmlGenericErrorContext,
11570
                            "           searching for namespace %s\n",
11571
                            op->value5);
11572
            break;
11573
        case NODE_TEST_NAME:
11574
            xmlGenericError(xmlGenericErrorContext,
11575
                            "           searching for name %s\n", op->value5);
11576
            if (op->value4)
11577
                xmlGenericError(xmlGenericErrorContext,
11578
                                "           with namespace %s\n", op->value4);
11579
            break;
11580
    }
11581
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11582
}
11583
#endif /* DEBUG_STEP */
11584
11585
/**
11586
 * xmlXPathNodeSetFilter:
11587
 * @ctxt:  the XPath Parser context
11588
 * @set: the node set to filter
11589
 * @filterOpIndex: the index of the predicate/filter op
11590
 * @minPos: minimum position in the filtered set (1-based)
11591
 * @maxPos: maximum position in the filtered set (1-based)
11592
 * @hasNsNodes: true if the node set may contain namespace nodes
11593
 *
11594
 * Filter a node set, keeping only nodes for which the predicate expression
11595
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11596
 * filtered result.
11597
 */
11598
static void
11599
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11600
          xmlNodeSetPtr set,
11601
          int filterOpIndex,
11602
                      int minPos, int maxPos,
11603
          int hasNsNodes)
11604
312k
{
11605
312k
    xmlXPathContextPtr xpctxt;
11606
312k
    xmlNodePtr oldnode;
11607
312k
    xmlDocPtr olddoc;
11608
312k
    xmlXPathStepOpPtr filterOp;
11609
312k
    int oldcs, oldpp;
11610
312k
    int i, j, pos;
11611
11612
312k
    if ((set == NULL) || (set->nodeNr == 0))
11613
111k
        return;
11614
11615
    /*
11616
    * Check if the node set contains a sufficient number of nodes for
11617
    * the requested range.
11618
    */
11619
201k
    if (set->nodeNr < minPos) {
11620
6.78k
        xmlXPathNodeSetClear(set, hasNsNodes);
11621
6.78k
        return;
11622
6.78k
    }
11623
11624
194k
    xpctxt = ctxt->context;
11625
194k
    oldnode = xpctxt->node;
11626
194k
    olddoc = xpctxt->doc;
11627
194k
    oldcs = xpctxt->contextSize;
11628
194k
    oldpp = xpctxt->proximityPosition;
11629
194k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11630
11631
194k
    xpctxt->contextSize = set->nodeNr;
11632
11633
586k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11634
521k
        xmlNodePtr node = set->nodeTab[i];
11635
521k
        int res;
11636
11637
521k
        xpctxt->node = node;
11638
521k
        xpctxt->proximityPosition = i + 1;
11639
11640
        /*
11641
        * Also set the xpath document in case things like
11642
        * key() are evaluated in the predicate.
11643
        *
11644
        * TODO: Get real doc for namespace nodes.
11645
        */
11646
521k
        if ((node->type != XML_NAMESPACE_DECL) &&
11647
521k
            (node->doc != NULL))
11648
504k
            xpctxt->doc = node->doc;
11649
11650
521k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11651
11652
521k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11653
11.8k
            break;
11654
509k
        if (res < 0) {
11655
            /* Shouldn't happen */
11656
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11657
0
            break;
11658
0
        }
11659
11660
509k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11661
336k
            if (i != j) {
11662
15.5k
                set->nodeTab[j] = node;
11663
15.5k
                set->nodeTab[i] = NULL;
11664
15.5k
            }
11665
11666
336k
            j += 1;
11667
336k
        } else {
11668
            /* Remove the entry from the initial node set. */
11669
172k
            set->nodeTab[i] = NULL;
11670
172k
            if (node->type == XML_NAMESPACE_DECL)
11671
7.59k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11672
172k
        }
11673
11674
509k
        if (res != 0) {
11675
342k
            if (pos == maxPos) {
11676
117k
                i += 1;
11677
117k
                break;
11678
117k
            }
11679
11680
225k
            pos += 1;
11681
225k
        }
11682
509k
    }
11683
11684
    /* Free remaining nodes. */
11685
194k
    if (hasNsNodes) {
11686
67.8k
        for (; i < set->nodeNr; i++) {
11687
10.8k
            xmlNodePtr node = set->nodeTab[i];
11688
10.8k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11689
3.93k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11690
10.8k
        }
11691
57.0k
    }
11692
11693
194k
    set->nodeNr = j;
11694
11695
    /* If too many elements were removed, shrink table to preserve memory. */
11696
194k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11697
194k
        (set->nodeNr < set->nodeMax / 2)) {
11698
2.62k
        xmlNodePtr *tmp;
11699
2.62k
        int nodeMax = set->nodeNr;
11700
11701
2.62k
        if (nodeMax < XML_NODESET_DEFAULT)
11702
2.45k
            nodeMax = XML_NODESET_DEFAULT;
11703
2.62k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11704
2.62k
                nodeMax * sizeof(xmlNodePtr));
11705
2.62k
        if (tmp == NULL) {
11706
127
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11707
2.50k
        } else {
11708
2.50k
            set->nodeTab = tmp;
11709
2.50k
            set->nodeMax = nodeMax;
11710
2.50k
        }
11711
2.62k
    }
11712
11713
194k
    xpctxt->node = oldnode;
11714
194k
    xpctxt->doc = olddoc;
11715
194k
    xpctxt->contextSize = oldcs;
11716
194k
    xpctxt->proximityPosition = oldpp;
11717
194k
}
11718
11719
#ifdef LIBXML_XPTR_LOCS_ENABLED
11720
/**
11721
 * xmlXPathLocationSetFilter:
11722
 * @ctxt:  the XPath Parser context
11723
 * @locset: the location set to filter
11724
 * @filterOpIndex: the index of the predicate/filter op
11725
 * @minPos: minimum position in the filtered set (1-based)
11726
 * @maxPos: maximum position in the filtered set (1-based)
11727
 *
11728
 * Filter a location set, keeping only nodes for which the predicate
11729
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11730
 * in the filtered result.
11731
 */
11732
static void
11733
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11734
              xmlLocationSetPtr locset,
11735
              int filterOpIndex,
11736
                          int minPos, int maxPos)
11737
{
11738
    xmlXPathContextPtr xpctxt;
11739
    xmlNodePtr oldnode;
11740
    xmlDocPtr olddoc;
11741
    xmlXPathStepOpPtr filterOp;
11742
    int oldcs, oldpp;
11743
    int i, j, pos;
11744
11745
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11746
        return;
11747
11748
    xpctxt = ctxt->context;
11749
    oldnode = xpctxt->node;
11750
    olddoc = xpctxt->doc;
11751
    oldcs = xpctxt->contextSize;
11752
    oldpp = xpctxt->proximityPosition;
11753
    filterOp = &ctxt->comp->steps[filterOpIndex];
11754
11755
    xpctxt->contextSize = locset->locNr;
11756
11757
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11758
        xmlNodePtr contextNode = locset->locTab[i]->user;
11759
        int res;
11760
11761
        xpctxt->node = contextNode;
11762
        xpctxt->proximityPosition = i + 1;
11763
11764
        /*
11765
        * Also set the xpath document in case things like
11766
        * key() are evaluated in the predicate.
11767
        *
11768
        * TODO: Get real doc for namespace nodes.
11769
        */
11770
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11771
            (contextNode->doc != NULL))
11772
            xpctxt->doc = contextNode->doc;
11773
11774
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11775
11776
        if (ctxt->error != XPATH_EXPRESSION_OK)
11777
            break;
11778
        if (res < 0) {
11779
            /* Shouldn't happen */
11780
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11781
            break;
11782
        }
11783
11784
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11785
            if (i != j) {
11786
                locset->locTab[j] = locset->locTab[i];
11787
                locset->locTab[i] = NULL;
11788
            }
11789
11790
            j += 1;
11791
        } else {
11792
            /* Remove the entry from the initial location set. */
11793
            xmlXPathFreeObject(locset->locTab[i]);
11794
            locset->locTab[i] = NULL;
11795
        }
11796
11797
        if (res != 0) {
11798
            if (pos == maxPos) {
11799
                i += 1;
11800
                break;
11801
            }
11802
11803
            pos += 1;
11804
        }
11805
    }
11806
11807
    /* Free remaining nodes. */
11808
    for (; i < locset->locNr; i++)
11809
        xmlXPathFreeObject(locset->locTab[i]);
11810
11811
    locset->locNr = j;
11812
11813
    /* If too many elements were removed, shrink table to preserve memory. */
11814
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11815
        (locset->locNr < locset->locMax / 2)) {
11816
        xmlXPathObjectPtr *tmp;
11817
        int locMax = locset->locNr;
11818
11819
        if (locMax < XML_NODESET_DEFAULT)
11820
            locMax = XML_NODESET_DEFAULT;
11821
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11822
                locMax * sizeof(xmlXPathObjectPtr));
11823
        if (tmp == NULL) {
11824
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11825
        } else {
11826
            locset->locTab = tmp;
11827
            locset->locMax = locMax;
11828
        }
11829
    }
11830
11831
    xpctxt->node = oldnode;
11832
    xpctxt->doc = olddoc;
11833
    xpctxt->contextSize = oldcs;
11834
    xpctxt->proximityPosition = oldpp;
11835
}
11836
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11837
11838
/**
11839
 * xmlXPathCompOpEvalPredicate:
11840
 * @ctxt:  the XPath Parser context
11841
 * @op: the predicate op
11842
 * @set: the node set to filter
11843
 * @minPos: minimum position in the filtered set (1-based)
11844
 * @maxPos: maximum position in the filtered set (1-based)
11845
 * @hasNsNodes: true if the node set may contain namespace nodes
11846
 *
11847
 * Filter a node set, keeping only nodes for which the sequence of predicate
11848
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11849
 * in the filtered result.
11850
 */
11851
static void
11852
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11853
          xmlXPathStepOpPtr op,
11854
          xmlNodeSetPtr set,
11855
                            int minPos, int maxPos,
11856
          int hasNsNodes)
11857
158k
{
11858
158k
    if (op->ch1 != -1) {
11859
42.5k
  xmlXPathCompExprPtr comp = ctxt->comp;
11860
  /*
11861
  * Process inner predicates first.
11862
  */
11863
42.5k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11864
0
            xmlGenericError(xmlGenericErrorContext,
11865
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11866
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11867
0
  }
11868
42.5k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11869
42.5k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11870
42.5k
        ctxt->context->depth += 1;
11871
42.5k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11872
42.5k
                                    1, set->nodeNr, hasNsNodes);
11873
42.5k
        ctxt->context->depth -= 1;
11874
42.5k
  CHECK_ERROR;
11875
42.5k
    }
11876
11877
155k
    if (op->ch2 != -1)
11878
155k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11879
155k
}
11880
11881
static int
11882
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11883
          xmlXPathStepOpPtr op,
11884
          int *maxPos)
11885
99.4k
{
11886
11887
99.4k
    xmlXPathStepOpPtr exprOp;
11888
11889
    /*
11890
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11891
    */
11892
11893
    /*
11894
    * If not -1, then ch1 will point to:
11895
    * 1) For predicates (XPATH_OP_PREDICATE):
11896
    *    - an inner predicate operator
11897
    * 2) For filters (XPATH_OP_FILTER):
11898
    *    - an inner filter operator OR
11899
    *    - an expression selecting the node set.
11900
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11901
    */
11902
99.4k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11903
0
  return(0);
11904
11905
99.4k
    if (op->ch2 != -1) {
11906
99.4k
  exprOp = &ctxt->comp->steps[op->ch2];
11907
99.4k
    } else
11908
0
  return(0);
11909
11910
99.4k
    if ((exprOp != NULL) &&
11911
99.4k
  (exprOp->op == XPATH_OP_VALUE) &&
11912
99.4k
  (exprOp->value4 != NULL) &&
11913
99.4k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11914
30.2k
    {
11915
30.2k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11916
11917
  /*
11918
  * We have a "[n]" predicate here.
11919
  * TODO: Unfortunately this simplistic test here is not
11920
  * able to detect a position() predicate in compound
11921
  * expressions like "[@attr = 'a" and position() = 1],
11922
  * and even not the usage of position() in
11923
  * "[position() = 1]"; thus - obviously - a position-range,
11924
  * like it "[position() < 5]", is also not detected.
11925
  * Maybe we could rewrite the AST to ease the optimization.
11926
  */
11927
11928
30.2k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11929
29.8k
      *maxPos = (int) floatval;
11930
29.8k
            if (floatval == (double) *maxPos)
11931
28.2k
                return(1);
11932
29.8k
        }
11933
30.2k
    }
11934
71.1k
    return(0);
11935
99.4k
}
11936
11937
static int
11938
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11939
                           xmlXPathStepOpPtr op,
11940
         xmlNodePtr * first, xmlNodePtr * last,
11941
         int toBool)
11942
4.57M
{
11943
11944
4.57M
#define XP_TEST_HIT \
11945
16.1M
    if (hasAxisRange != 0) { \
11946
82.6k
  if (++pos == maxPos) { \
11947
45.6k
      if (addNode(seq, cur) < 0) \
11948
45.6k
          ctxt->error = XPATH_MEMORY_ERROR; \
11949
45.6k
      goto axis_range_end; } \
11950
16.0M
    } else { \
11951
16.0M
  if (addNode(seq, cur) < 0) \
11952
16.0M
      ctxt->error = XPATH_MEMORY_ERROR; \
11953
16.0M
  if (breakOnFirstHit) goto first_hit; }
11954
11955
4.57M
#define XP_TEST_HIT_NS \
11956
4.57M
    if (hasAxisRange != 0) { \
11957
6.35k
  if (++pos == maxPos) { \
11958
3.48k
      hasNsNodes = 1; \
11959
3.48k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11960
3.48k
          ctxt->error = XPATH_MEMORY_ERROR; \
11961
3.48k
  goto axis_range_end; } \
11962
307k
    } else { \
11963
307k
  hasNsNodes = 1; \
11964
307k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11965
307k
      ctxt->error = XPATH_MEMORY_ERROR; \
11966
307k
  if (breakOnFirstHit) goto first_hit; }
11967
11968
4.57M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11969
4.57M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11970
4.57M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11971
4.57M
    const xmlChar *prefix = op->value4;
11972
4.57M
    const xmlChar *name = op->value5;
11973
4.57M
    const xmlChar *URI = NULL;
11974
11975
#ifdef DEBUG_STEP
11976
    int nbMatches = 0, prevMatches = 0;
11977
#endif
11978
4.57M
    int total = 0, hasNsNodes = 0;
11979
    /* The popped object holding the context nodes */
11980
4.57M
    xmlXPathObjectPtr obj;
11981
    /* The set of context nodes for the node tests */
11982
4.57M
    xmlNodeSetPtr contextSeq;
11983
4.57M
    int contextIdx;
11984
4.57M
    xmlNodePtr contextNode;
11985
    /* The final resulting node set wrt to all context nodes */
11986
4.57M
    xmlNodeSetPtr outSeq;
11987
    /*
11988
    * The temporary resulting node set wrt 1 context node.
11989
    * Used to feed predicate evaluation.
11990
    */
11991
4.57M
    xmlNodeSetPtr seq;
11992
4.57M
    xmlNodePtr cur;
11993
    /* First predicate operator */
11994
4.57M
    xmlXPathStepOpPtr predOp;
11995
4.57M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11996
4.57M
    int hasPredicateRange, hasAxisRange, pos;
11997
4.57M
    int breakOnFirstHit;
11998
11999
4.57M
    xmlXPathTraversalFunction next = NULL;
12000
4.57M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12001
4.57M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12002
4.57M
    xmlNodePtr oldContextNode;
12003
4.57M
    xmlXPathContextPtr xpctxt = ctxt->context;
12004
12005
12006
4.57M
    CHECK_TYPE0(XPATH_NODESET);
12007
4.57M
    obj = valuePop(ctxt);
12008
    /*
12009
    * Setup namespaces.
12010
    */
12011
4.57M
    if (prefix != NULL) {
12012
177k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12013
177k
        if (URI == NULL) {
12014
82.4k
      xmlXPathReleaseObject(xpctxt, obj);
12015
82.4k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12016
0
  }
12017
177k
    }
12018
    /*
12019
    * Setup axis.
12020
    *
12021
    * MAYBE FUTURE TODO: merging optimizations:
12022
    * - If the nodes to be traversed wrt to the initial nodes and
12023
    *   the current axis cannot overlap, then we could avoid searching
12024
    *   for duplicates during the merge.
12025
    *   But the question is how/when to evaluate if they cannot overlap.
12026
    *   Example: if we know that for two initial nodes, the one is
12027
    *   not in the ancestor-or-self axis of the other, then we could safely
12028
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12029
    *   the descendant-or-self axis.
12030
    */
12031
4.48M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12032
4.48M
    switch (axis) {
12033
980
        case AXIS_ANCESTOR:
12034
980
            first = NULL;
12035
980
            next = xmlXPathNextAncestor;
12036
980
            break;
12037
578
        case AXIS_ANCESTOR_OR_SELF:
12038
578
            first = NULL;
12039
578
            next = xmlXPathNextAncestorOrSelf;
12040
578
            break;
12041
501k
        case AXIS_ATTRIBUTE:
12042
501k
            first = NULL;
12043
501k
      last = NULL;
12044
501k
            next = xmlXPathNextAttribute;
12045
501k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12046
501k
            break;
12047
2.85M
        case AXIS_CHILD:
12048
2.85M
      last = NULL;
12049
2.85M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12050
2.85M
    (type == NODE_TYPE_NODE))
12051
2.68M
      {
12052
    /*
12053
    * Optimization if an element node type is 'element'.
12054
    */
12055
2.68M
    next = xmlXPathNextChildElement;
12056
2.68M
      } else
12057
169k
    next = xmlXPathNextChild;
12058
2.85M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12059
2.85M
            break;
12060
844k
        case AXIS_DESCENDANT:
12061
844k
      last = NULL;
12062
844k
            next = xmlXPathNextDescendant;
12063
844k
            break;
12064
72.3k
        case AXIS_DESCENDANT_OR_SELF:
12065
72.3k
      last = NULL;
12066
72.3k
            next = xmlXPathNextDescendantOrSelf;
12067
72.3k
            break;
12068
1.16k
        case AXIS_FOLLOWING:
12069
1.16k
      last = NULL;
12070
1.16k
            next = xmlXPathNextFollowing;
12071
1.16k
            break;
12072
0
        case AXIS_FOLLOWING_SIBLING:
12073
0
      last = NULL;
12074
0
            next = xmlXPathNextFollowingSibling;
12075
0
            break;
12076
62.7k
        case AXIS_NAMESPACE:
12077
62.7k
            first = NULL;
12078
62.7k
      last = NULL;
12079
62.7k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12080
62.7k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081
62.7k
            break;
12082
152k
        case AXIS_PARENT:
12083
152k
            first = NULL;
12084
152k
            next = xmlXPathNextParent;
12085
152k
            break;
12086
1.52k
        case AXIS_PRECEDING:
12087
1.52k
            first = NULL;
12088
1.52k
            next = xmlXPathNextPrecedingInternal;
12089
1.52k
            break;
12090
0
        case AXIS_PRECEDING_SIBLING:
12091
0
            first = NULL;
12092
0
            next = xmlXPathNextPrecedingSibling;
12093
0
            break;
12094
511
        case AXIS_SELF:
12095
511
            first = NULL;
12096
511
      last = NULL;
12097
511
            next = xmlXPathNextSelf;
12098
511
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12099
511
            break;
12100
4.48M
    }
12101
12102
#ifdef DEBUG_STEP
12103
    xmlXPathDebugDumpStepAxis(op,
12104
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12105
#endif
12106
12107
4.48M
    if (next == NULL) {
12108
0
  xmlXPathReleaseObject(xpctxt, obj);
12109
0
        return(0);
12110
0
    }
12111
4.48M
    contextSeq = obj->nodesetval;
12112
4.48M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12113
613k
  xmlXPathReleaseObject(xpctxt, obj);
12114
613k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12115
613k
        return(0);
12116
613k
    }
12117
    /*
12118
    * Predicate optimization ---------------------------------------------
12119
    * If this step has a last predicate, which contains a position(),
12120
    * then we'll optimize (although not exactly "position()", but only
12121
    * the  short-hand form, i.e., "[n]".
12122
    *
12123
    * Example - expression "/foo[parent::bar][1]":
12124
    *
12125
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12126
    *   ROOT                               -- op->ch1
12127
    *   PREDICATE                          -- op->ch2 (predOp)
12128
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12129
    *       SORT
12130
    *         COLLECT  'parent' 'name' 'node' bar
12131
    *           NODE
12132
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12133
    *
12134
    */
12135
3.87M
    maxPos = 0;
12136
3.87M
    predOp = NULL;
12137
3.87M
    hasPredicateRange = 0;
12138
3.87M
    hasAxisRange = 0;
12139
3.87M
    if (op->ch2 != -1) {
12140
  /*
12141
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12142
  */
12143
99.4k
  predOp = &ctxt->comp->steps[op->ch2];
12144
99.4k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12145
28.2k
      if (predOp->ch1 != -1) {
12146
    /*
12147
    * Use the next inner predicate operator.
12148
    */
12149
5.31k
    predOp = &ctxt->comp->steps[predOp->ch1];
12150
5.31k
    hasPredicateRange = 1;
12151
22.9k
      } else {
12152
    /*
12153
    * There's no other predicate than the [n] predicate.
12154
    */
12155
22.9k
    predOp = NULL;
12156
22.9k
    hasAxisRange = 1;
12157
22.9k
      }
12158
28.2k
  }
12159
99.4k
    }
12160
3.87M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12161
    /*
12162
    * Axis traversal -----------------------------------------------------
12163
    */
12164
    /*
12165
     * 2.3 Node Tests
12166
     *  - For the attribute axis, the principal node type is attribute.
12167
     *  - For the namespace axis, the principal node type is namespace.
12168
     *  - For other axes, the principal node type is element.
12169
     *
12170
     * A node test * is true for any node of the
12171
     * principal node type. For example, child::* will
12172
     * select all element children of the context node
12173
     */
12174
3.87M
    oldContextNode = xpctxt->node;
12175
3.87M
    addNode = xmlXPathNodeSetAddUnique;
12176
3.87M
    outSeq = NULL;
12177
3.87M
    seq = NULL;
12178
3.87M
    contextNode = NULL;
12179
3.87M
    contextIdx = 0;
12180
12181
12182
8.98M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12183
8.98M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12184
5.14M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12185
12186
5.14M
  if (seq == NULL) {
12187
3.92M
      seq = xmlXPathNodeSetCreate(NULL);
12188
3.92M
      if (seq == NULL) {
12189
                /* TODO: Propagate memory error. */
12190
5.45k
    total = 0;
12191
5.45k
    goto error;
12192
5.45k
      }
12193
3.92M
  }
12194
  /*
12195
  * Traverse the axis and test the nodes.
12196
  */
12197
5.14M
  pos = 0;
12198
5.14M
  cur = NULL;
12199
5.14M
  hasNsNodes = 0;
12200
26.0M
        do {
12201
26.0M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12202
433
                goto error;
12203
12204
26.0M
            cur = next(ctxt, cur);
12205
26.0M
            if (cur == NULL)
12206
5.05M
                break;
12207
12208
      /*
12209
      * QUESTION TODO: What does the "first" and "last" stuff do?
12210
      */
12211
20.9M
            if ((first != NULL) && (*first != NULL)) {
12212
20.2k
    if (*first == cur)
12213
3.61k
        break;
12214
16.5k
    if (((total % 256) == 0) &&
12215
16.5k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12216
16.5k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12217
#else
12218
        (xmlXPathCmpNodes(*first, cur) >= 0))
12219
#endif
12220
8.49k
    {
12221
8.49k
        break;
12222
8.49k
    }
12223
16.5k
      }
12224
20.9M
      if ((last != NULL) && (*last != NULL)) {
12225
8.08k
    if (*last == cur)
12226
311
        break;
12227
7.77k
    if (((total % 256) == 0) &&
12228
7.77k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12229
7.77k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12230
#else
12231
        (xmlXPathCmpNodes(cur, *last) >= 0))
12232
#endif
12233
1.34k
    {
12234
1.34k
        break;
12235
1.34k
    }
12236
7.77k
      }
12237
12238
20.9M
            total++;
12239
12240
#ifdef DEBUG_STEP
12241
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12242
#endif
12243
12244
20.9M
      switch (test) {
12245
0
                case NODE_TEST_NONE:
12246
0
        total = 0;
12247
0
                    STRANGE
12248
0
        goto error;
12249
15.0M
                case NODE_TEST_TYPE:
12250
15.0M
        if (type == NODE_TYPE_NODE) {
12251
13.9M
      switch (cur->type) {
12252
93.1k
          case XML_DOCUMENT_NODE:
12253
93.1k
          case XML_HTML_DOCUMENT_NODE:
12254
6.93M
          case XML_ELEMENT_NODE:
12255
6.99M
          case XML_ATTRIBUTE_NODE:
12256
7.09M
          case XML_PI_NODE:
12257
7.23M
          case XML_COMMENT_NODE:
12258
7.23M
          case XML_CDATA_SECTION_NODE:
12259
13.8M
          case XML_TEXT_NODE:
12260
13.8M
        XP_TEST_HIT
12261
13.8M
        break;
12262
13.8M
          case XML_NAMESPACE_DECL: {
12263
91.6k
        if (axis == AXIS_NAMESPACE) {
12264
49.3k
            XP_TEST_HIT_NS
12265
49.3k
        } else {
12266
42.2k
                              hasNsNodes = 1;
12267
42.2k
            XP_TEST_HIT
12268
42.2k
        }
12269
91.0k
        break;
12270
91.6k
                            }
12271
91.0k
          default:
12272
0
        break;
12273
13.9M
      }
12274
13.9M
        } else if (cur->type == (xmlElementType) type) {
12275
369k
      if (cur->type == XML_NAMESPACE_DECL)
12276
0
          XP_TEST_HIT_NS
12277
369k
      else
12278
369k
          XP_TEST_HIT
12279
758k
        } else if ((type == NODE_TYPE_TEXT) &&
12280
758k
       (cur->type == XML_CDATA_SECTION_NODE))
12281
0
        {
12282
0
      XP_TEST_HIT
12283
0
        }
12284
14.9M
        break;
12285
14.9M
                case NODE_TEST_PI:
12286
4.87k
                    if ((cur->type == XML_PI_NODE) &&
12287
4.87k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12288
536
        {
12289
536
      XP_TEST_HIT
12290
536
                    }
12291
4.87k
                    break;
12292
2.18M
                case NODE_TEST_ALL:
12293
2.18M
                    if (axis == AXIS_ATTRIBUTE) {
12294
36.1k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12295
36.1k
      {
12296
36.1k
                            if (prefix == NULL)
12297
32.3k
          {
12298
32.3k
        XP_TEST_HIT
12299
32.3k
                            } else if ((cur->ns != NULL) &&
12300
3.75k
        (xmlStrEqual(URI, cur->ns->href)))
12301
38
          {
12302
38
        XP_TEST_HIT
12303
38
                            }
12304
36.1k
                        }
12305
2.14M
                    } else if (axis == AXIS_NAMESPACE) {
12306
262k
                        if (cur->type == XML_NAMESPACE_DECL)
12307
262k
      {
12308
262k
          XP_TEST_HIT_NS
12309
262k
                        }
12310
1.88M
                    } else {
12311
1.88M
                        if (cur->type == XML_ELEMENT_NODE) {
12312
1.33M
                            if (prefix == NULL)
12313
1.32M
          {
12314
1.32M
        XP_TEST_HIT
12315
12316
1.32M
                            } else if ((cur->ns != NULL) &&
12317
3.36k
        (xmlStrEqual(URI, cur->ns->href)))
12318
239
          {
12319
239
        XP_TEST_HIT
12320
239
                            }
12321
1.33M
                        }
12322
1.88M
                    }
12323
2.17M
                    break;
12324
2.17M
                case NODE_TEST_NS:{
12325
0
                        TODO;
12326
0
                        break;
12327
2.18M
                    }
12328
3.74M
                case NODE_TEST_NAME:
12329
3.74M
                    if (axis == AXIS_ATTRIBUTE) {
12330
502k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12331
0
          break;
12332
3.23M
        } else if (axis == AXIS_NAMESPACE) {
12333
27.4k
                        if (cur->type != XML_NAMESPACE_DECL)
12334
0
          break;
12335
3.21M
        } else {
12336
3.21M
            if (cur->type != XML_ELEMENT_NODE)
12337
677k
          break;
12338
3.21M
        }
12339
3.06M
                    switch (cur->type) {
12340
2.53M
                        case XML_ELEMENT_NODE:
12341
2.53M
                            if (xmlStrEqual(name, cur->name)) {
12342
163k
                                if (prefix == NULL) {
12343
95.0k
                                    if (cur->ns == NULL)
12344
92.4k
            {
12345
92.4k
          XP_TEST_HIT
12346
92.4k
                                    }
12347
95.0k
                                } else {
12348
68.6k
                                    if ((cur->ns != NULL) &&
12349
68.6k
                                        (xmlStrEqual(URI, cur->ns->href)))
12350
62.2k
            {
12351
62.2k
          XP_TEST_HIT
12352
62.2k
                                    }
12353
68.6k
                                }
12354
163k
                            }
12355
2.53M
                            break;
12356
2.53M
                        case XML_ATTRIBUTE_NODE:{
12357
502k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12358
12359
502k
                                if (xmlStrEqual(name, attr->name)) {
12360
353k
                                    if (prefix == NULL) {
12361
353k
                                        if ((attr->ns == NULL) ||
12362
353k
                                            (attr->ns->prefix == NULL))
12363
353k
          {
12364
353k
              XP_TEST_HIT
12365
353k
                                        }
12366
353k
                                    } else {
12367
29
                                        if ((attr->ns != NULL) &&
12368
29
                                            (xmlStrEqual(URI,
12369
0
                attr->ns->href)))
12370
0
          {
12371
0
              XP_TEST_HIT
12372
0
                                        }
12373
29
                                    }
12374
353k
                                }
12375
499k
                                break;
12376
502k
                            }
12377
499k
                        case XML_NAMESPACE_DECL:
12378
27.4k
                            if (cur->type == XML_NAMESPACE_DECL) {
12379
27.4k
                                xmlNsPtr ns = (xmlNsPtr) cur;
12380
12381
27.4k
                                if ((ns->prefix != NULL) && (name != NULL)
12382
27.4k
                                    && (xmlStrEqual(ns->prefix, name)))
12383
2.68k
        {
12384
2.68k
            XP_TEST_HIT_NS
12385
2.68k
                                }
12386
27.4k
                            }
12387
26.7k
                            break;
12388
26.7k
                        default:
12389
0
                            break;
12390
3.06M
                    }
12391
3.05M
                    break;
12392
20.9M
      } /* switch(test) */
12393
20.9M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12394
12395
5.06M
  goto apply_predicates;
12396
12397
5.06M
axis_range_end: /* ----------------------------------------------------- */
12398
  /*
12399
  * We have a "/foo[n]", and position() = n was reached.
12400
  * Note that we can have as well "/foo/::parent::foo[1]", so
12401
  * a duplicate-aware merge is still needed.
12402
  * Merge with the result.
12403
  */
12404
49.1k
  if (outSeq == NULL) {
12405
12.6k
      outSeq = seq;
12406
12.6k
      seq = NULL;
12407
12.6k
  } else
12408
            /* TODO: Check memory error. */
12409
36.4k
      outSeq = mergeAndClear(outSeq, seq);
12410
  /*
12411
  * Break if only a true/false result was requested.
12412
  */
12413
49.1k
  if (toBool)
12414
4.14k
      break;
12415
45.0k
  continue;
12416
12417
45.0k
first_hit: /* ---------------------------------------------------------- */
12418
  /*
12419
  * Break if only a true/false result was requested and
12420
  * no predicates existed and a node test succeeded.
12421
  */
12422
23.1k
  if (outSeq == NULL) {
12423
23.1k
      outSeq = seq;
12424
23.1k
      seq = NULL;
12425
23.1k
  } else
12426
            /* TODO: Check memory error. */
12427
0
      outSeq = mergeAndClear(outSeq, seq);
12428
23.1k
  break;
12429
12430
#ifdef DEBUG_STEP
12431
  if (seq != NULL)
12432
      nbMatches += seq->nodeNr;
12433
#endif
12434
12435
5.06M
apply_predicates: /* --------------------------------------------------- */
12436
5.06M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12437
386
      goto error;
12438
12439
        /*
12440
  * Apply predicates.
12441
  */
12442
5.06M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12443
      /*
12444
      * E.g. when we have a "/foo[some expression][n]".
12445
      */
12446
      /*
12447
      * QUESTION TODO: The old predicate evaluation took into
12448
      *  account location-sets.
12449
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12450
      *  Do we expect such a set here?
12451
      *  All what I learned now from the evaluation semantics
12452
      *  does not indicate that a location-set will be processed
12453
      *  here, so this looks OK.
12454
      */
12455
      /*
12456
      * Iterate over all predicates, starting with the outermost
12457
      * predicate.
12458
      * TODO: Problem: we cannot execute the inner predicates first
12459
      *  since we cannot go back *up* the operator tree!
12460
      *  Options we have:
12461
      *  1) Use of recursive functions (like is it currently done
12462
      *     via xmlXPathCompOpEval())
12463
      *  2) Add a predicate evaluation information stack to the
12464
      *     context struct
12465
      *  3) Change the way the operators are linked; we need a
12466
      *     "parent" field on xmlXPathStepOp
12467
      *
12468
      * For the moment, I'll try to solve this with a recursive
12469
      * function: xmlXPathCompOpEvalPredicate().
12470
      */
12471
116k
      if (hasPredicateRange != 0)
12472
10.7k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12473
10.7k
              hasNsNodes);
12474
105k
      else
12475
105k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12476
105k
              hasNsNodes);
12477
12478
116k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12479
6.72k
    total = 0;
12480
6.72k
    goto error;
12481
6.72k
      }
12482
116k
        }
12483
12484
5.06M
        if (seq->nodeNr > 0) {
12485
      /*
12486
      * Add to result set.
12487
      */
12488
1.91M
      if (outSeq == NULL) {
12489
1.59M
    outSeq = seq;
12490
1.59M
    seq = NULL;
12491
1.59M
      } else {
12492
                /* TODO: Check memory error. */
12493
325k
    outSeq = mergeAndClear(outSeq, seq);
12494
325k
      }
12495
12496
1.91M
            if (toBool)
12497
455
                break;
12498
1.91M
  }
12499
5.06M
    }
12500
12501
3.87M
error:
12502
3.87M
    if ((obj->boolval) && (obj->user != NULL)) {
12503
  /*
12504
  * QUESTION TODO: What does this do and why?
12505
  * TODO: Do we have to do this also for the "error"
12506
  * cleanup further down?
12507
  */
12508
0
  ctxt->value->boolval = 1;
12509
0
  ctxt->value->user = obj->user;
12510
0
  obj->user = NULL;
12511
0
  obj->boolval = 0;
12512
0
    }
12513
3.87M
    xmlXPathReleaseObject(xpctxt, obj);
12514
12515
    /*
12516
    * Ensure we return at least an empty set.
12517
    */
12518
3.87M
    if (outSeq == NULL) {
12519
2.24M
  if ((seq != NULL) && (seq->nodeNr == 0))
12520
2.24M
      outSeq = seq;
12521
5.73k
  else
12522
            /* TODO: Check memory error. */
12523
5.73k
      outSeq = xmlXPathNodeSetCreate(NULL);
12524
2.24M
    }
12525
3.87M
    if ((seq != NULL) && (seq != outSeq)) {
12526
44.8k
   xmlXPathFreeNodeSet(seq);
12527
44.8k
    }
12528
    /*
12529
    * Hand over the result. Better to push the set also in
12530
    * case of errors.
12531
    */
12532
3.87M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12533
    /*
12534
    * Reset the context node.
12535
    */
12536
3.87M
    xpctxt->node = oldContextNode;
12537
    /*
12538
    * When traversing the namespace axis in "toBool" mode, it's
12539
    * possible that tmpNsList wasn't freed.
12540
    */
12541
3.87M
    if (xpctxt->tmpNsList != NULL) {
12542
1.85k
        xmlFree(xpctxt->tmpNsList);
12543
1.85k
        xpctxt->tmpNsList = NULL;
12544
1.85k
    }
12545
12546
#ifdef DEBUG_STEP
12547
    xmlGenericError(xmlGenericErrorContext,
12548
  "\nExamined %d nodes, found %d nodes at that step\n",
12549
  total, nbMatches);
12550
#endif
12551
12552
3.87M
    return(total);
12553
3.87M
}
12554
12555
static int
12556
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12557
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12558
12559
/**
12560
 * xmlXPathCompOpEvalFirst:
12561
 * @ctxt:  the XPath parser context with the compiled expression
12562
 * @op:  an XPath compiled operation
12563
 * @first:  the first elem found so far
12564
 *
12565
 * Evaluate the Precompiled XPath operation searching only the first
12566
 * element in document order
12567
 *
12568
 * Returns the number of examined objects.
12569
 */
12570
static int
12571
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12572
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12573
198k
{
12574
198k
    int total = 0, cur;
12575
198k
    xmlXPathCompExprPtr comp;
12576
198k
    xmlXPathObjectPtr arg1, arg2;
12577
12578
198k
    CHECK_ERROR0;
12579
198k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12580
2
        return(0);
12581
198k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12582
197k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12583
197k
    ctxt->context->depth += 1;
12584
197k
    comp = ctxt->comp;
12585
197k
    switch (op->op) {
12586
0
        case XPATH_OP_END:
12587
0
            break;
12588
50.0k
        case XPATH_OP_UNION:
12589
50.0k
            total =
12590
50.0k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12591
50.0k
                                        first);
12592
50.0k
      CHECK_ERROR0;
12593
42.6k
            if ((ctxt->value != NULL)
12594
42.6k
                && (ctxt->value->type == XPATH_NODESET)
12595
42.6k
                && (ctxt->value->nodesetval != NULL)
12596
42.6k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12597
                /*
12598
                 * limit tree traversing to first node in the result
12599
                 */
12600
    /*
12601
    * OPTIMIZE TODO: This implicitly sorts
12602
    *  the result, even if not needed. E.g. if the argument
12603
    *  of the count() function, no sorting is needed.
12604
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12605
    *  already sorted?
12606
    */
12607
34.4k
    if (ctxt->value->nodesetval->nodeNr > 1)
12608
9.65k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12609
34.4k
                *first = ctxt->value->nodesetval->nodeTab[0];
12610
34.4k
            }
12611
42.6k
            cur =
12612
42.6k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12613
42.6k
                                        first);
12614
42.6k
      CHECK_ERROR0;
12615
12616
39.9k
            arg2 = valuePop(ctxt);
12617
39.9k
            arg1 = valuePop(ctxt);
12618
39.9k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12619
39.9k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12620
321
          xmlXPathReleaseObject(ctxt->context, arg1);
12621
321
          xmlXPathReleaseObject(ctxt->context, arg2);
12622
321
                XP_ERROR0(XPATH_INVALID_TYPE);
12623
0
            }
12624
39.6k
            if ((ctxt->context->opLimit != 0) &&
12625
39.6k
                (((arg1->nodesetval != NULL) &&
12626
39.6k
                  (xmlXPathCheckOpLimit(ctxt,
12627
36.4k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12628
39.6k
                 ((arg2->nodesetval != NULL) &&
12629
39.6k
                  (xmlXPathCheckOpLimit(ctxt,
12630
30.6k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12631
2
          xmlXPathReleaseObject(ctxt->context, arg1);
12632
2
          xmlXPathReleaseObject(ctxt->context, arg2);
12633
2
                break;
12634
2
            }
12635
12636
            /* TODO: Check memory error. */
12637
39.6k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12638
39.6k
                                                    arg2->nodesetval);
12639
39.6k
            valuePush(ctxt, arg1);
12640
39.6k
      xmlXPathReleaseObject(ctxt->context, arg2);
12641
            /* optimizer */
12642
39.6k
      if (total > cur)
12643
24.4k
    xmlXPathCompSwap(op);
12644
39.6k
            total += cur;
12645
39.6k
            break;
12646
641
        case XPATH_OP_ROOT:
12647
641
            xmlXPathRoot(ctxt);
12648
641
            break;
12649
9.45k
        case XPATH_OP_NODE:
12650
9.45k
            if (op->ch1 != -1)
12651
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12652
9.45k
      CHECK_ERROR0;
12653
9.45k
            if (op->ch2 != -1)
12654
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12655
9.45k
      CHECK_ERROR0;
12656
9.45k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12657
9.45k
    ctxt->context->node));
12658
9.45k
            break;
12659
49.6k
        case XPATH_OP_COLLECT:{
12660
49.6k
                if (op->ch1 == -1)
12661
0
                    break;
12662
12663
49.6k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12664
49.6k
    CHECK_ERROR0;
12665
12666
47.0k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12667
47.0k
                break;
12668
49.6k
            }
12669
401
        case XPATH_OP_VALUE:
12670
401
            valuePush(ctxt,
12671
401
                      xmlXPathCacheObjectCopy(ctxt->context,
12672
401
      (xmlXPathObjectPtr) op->value4));
12673
401
            break;
12674
19.2k
        case XPATH_OP_SORT:
12675
19.2k
            if (op->ch1 != -1)
12676
19.2k
                total +=
12677
19.2k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12678
19.2k
                                            first);
12679
19.2k
      CHECK_ERROR0;
12680
14.7k
            if ((ctxt->value != NULL)
12681
14.7k
                && (ctxt->value->type == XPATH_NODESET)
12682
14.7k
                && (ctxt->value->nodesetval != NULL)
12683
14.7k
    && (ctxt->value->nodesetval->nodeNr > 1))
12684
6.34k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12685
14.7k
            break;
12686
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12687
67.3k
  case XPATH_OP_FILTER:
12688
67.3k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12689
67.3k
            break;
12690
0
#endif
12691
638
        default:
12692
638
            total += xmlXPathCompOpEval(ctxt, op);
12693
638
            break;
12694
197k
    }
12695
12696
179k
    ctxt->context->depth -= 1;
12697
179k
    return(total);
12698
197k
}
12699
12700
/**
12701
 * xmlXPathCompOpEvalLast:
12702
 * @ctxt:  the XPath parser context with the compiled expression
12703
 * @op:  an XPath compiled operation
12704
 * @last:  the last elem found so far
12705
 *
12706
 * Evaluate the Precompiled XPath operation searching only the last
12707
 * element in document order
12708
 *
12709
 * Returns the number of nodes traversed
12710
 */
12711
static int
12712
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12713
                       xmlNodePtr * last)
12714
237k
{
12715
237k
    int total = 0, cur;
12716
237k
    xmlXPathCompExprPtr comp;
12717
237k
    xmlXPathObjectPtr arg1, arg2;
12718
12719
237k
    CHECK_ERROR0;
12720
237k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12721
3
        return(0);
12722
237k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12723
236k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12724
236k
    ctxt->context->depth += 1;
12725
236k
    comp = ctxt->comp;
12726
236k
    switch (op->op) {
12727
0
        case XPATH_OP_END:
12728
0
            break;
12729
76.1k
        case XPATH_OP_UNION:
12730
76.1k
            total =
12731
76.1k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12732
76.1k
      CHECK_ERROR0;
12733
72.6k
            if ((ctxt->value != NULL)
12734
72.6k
                && (ctxt->value->type == XPATH_NODESET)
12735
72.6k
                && (ctxt->value->nodesetval != NULL)
12736
72.6k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12737
                /*
12738
                 * limit tree traversing to first node in the result
12739
                 */
12740
49.3k
    if (ctxt->value->nodesetval->nodeNr > 1)
12741
7.91k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12742
49.3k
                *last =
12743
49.3k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12744
49.3k
                                                     nodesetval->nodeNr -
12745
49.3k
                                                     1];
12746
49.3k
            }
12747
72.6k
            cur =
12748
72.6k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12749
72.6k
      CHECK_ERROR0;
12750
71.5k
            if ((ctxt->value != NULL)
12751
71.5k
                && (ctxt->value->type == XPATH_NODESET)
12752
71.5k
                && (ctxt->value->nodesetval != NULL)
12753
71.5k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12754
24.3k
            }
12755
12756
71.5k
            arg2 = valuePop(ctxt);
12757
71.5k
            arg1 = valuePop(ctxt);
12758
71.5k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12759
71.5k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12760
405
          xmlXPathReleaseObject(ctxt->context, arg1);
12761
405
          xmlXPathReleaseObject(ctxt->context, arg2);
12762
405
                XP_ERROR0(XPATH_INVALID_TYPE);
12763
0
            }
12764
71.1k
            if ((ctxt->context->opLimit != 0) &&
12765
71.1k
                (((arg1->nodesetval != NULL) &&
12766
71.1k
                  (xmlXPathCheckOpLimit(ctxt,
12767
65.4k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12768
71.1k
                 ((arg2->nodesetval != NULL) &&
12769
71.1k
                  (xmlXPathCheckOpLimit(ctxt,
12770
53.1k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12771
2
          xmlXPathReleaseObject(ctxt->context, arg1);
12772
2
          xmlXPathReleaseObject(ctxt->context, arg2);
12773
2
                break;
12774
2
            }
12775
12776
            /* TODO: Check memory error. */
12777
71.1k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12778
71.1k
                                                    arg2->nodesetval);
12779
71.1k
            valuePush(ctxt, arg1);
12780
71.1k
      xmlXPathReleaseObject(ctxt->context, arg2);
12781
            /* optimizer */
12782
71.1k
      if (total > cur)
12783
21.1k
    xmlXPathCompSwap(op);
12784
71.1k
            total += cur;
12785
71.1k
            break;
12786
17.1k
        case XPATH_OP_ROOT:
12787
17.1k
            xmlXPathRoot(ctxt);
12788
17.1k
            break;
12789
7.14k
        case XPATH_OP_NODE:
12790
7.14k
            if (op->ch1 != -1)
12791
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12792
7.14k
      CHECK_ERROR0;
12793
7.14k
            if (op->ch2 != -1)
12794
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12795
7.14k
      CHECK_ERROR0;
12796
7.14k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12797
7.14k
    ctxt->context->node));
12798
7.14k
            break;
12799
89.4k
        case XPATH_OP_COLLECT:{
12800
89.4k
                if (op->ch1 == -1)
12801
0
                    break;
12802
12803
89.4k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12804
89.4k
    CHECK_ERROR0;
12805
12806
88.3k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12807
88.3k
                break;
12808
89.4k
            }
12809
408
        case XPATH_OP_VALUE:
12810
408
            valuePush(ctxt,
12811
408
                      xmlXPathCacheObjectCopy(ctxt->context,
12812
408
      (xmlXPathObjectPtr) op->value4));
12813
408
            break;
12814
44.5k
        case XPATH_OP_SORT:
12815
44.5k
            if (op->ch1 != -1)
12816
44.5k
                total +=
12817
44.5k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12818
44.5k
                                           last);
12819
44.5k
      CHECK_ERROR0;
12820
40.5k
            if ((ctxt->value != NULL)
12821
40.5k
                && (ctxt->value->type == XPATH_NODESET)
12822
40.5k
                && (ctxt->value->nodesetval != NULL)
12823
40.5k
    && (ctxt->value->nodesetval->nodeNr > 1))
12824
12.4k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12825
40.5k
            break;
12826
1.90k
        default:
12827
1.90k
            total += xmlXPathCompOpEval(ctxt, op);
12828
1.90k
            break;
12829
236k
    }
12830
12831
226k
    ctxt->context->depth -= 1;
12832
226k
    return (total);
12833
236k
}
12834
12835
#ifdef XP_OPTIMIZED_FILTER_FIRST
12836
static int
12837
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12838
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12839
67.3k
{
12840
67.3k
    int total = 0;
12841
67.3k
    xmlXPathCompExprPtr comp;
12842
67.3k
    xmlXPathObjectPtr obj;
12843
67.3k
    xmlNodeSetPtr set;
12844
12845
67.3k
    CHECK_ERROR0;
12846
67.3k
    comp = ctxt->comp;
12847
    /*
12848
    * Optimization for ()[last()] selection i.e. the last elem
12849
    */
12850
67.3k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12851
67.3k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12852
67.3k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12853
23.2k
  int f = comp->steps[op->ch2].ch1;
12854
12855
23.2k
  if ((f != -1) &&
12856
23.2k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12857
23.2k
      (comp->steps[f].value5 == NULL) &&
12858
23.2k
      (comp->steps[f].value == 0) &&
12859
23.2k
      (comp->steps[f].value4 != NULL) &&
12860
23.2k
      (xmlStrEqual
12861
20.0k
      (comp->steps[f].value4, BAD_CAST "last"))) {
12862
19.3k
      xmlNodePtr last = NULL;
12863
12864
19.3k
      total +=
12865
19.3k
    xmlXPathCompOpEvalLast(ctxt,
12866
19.3k
        &comp->steps[op->ch1],
12867
19.3k
        &last);
12868
19.3k
      CHECK_ERROR0;
12869
      /*
12870
      * The nodeset should be in document order,
12871
      * Keep only the last value
12872
      */
12873
17.9k
      if ((ctxt->value != NULL) &&
12874
17.9k
    (ctxt->value->type == XPATH_NODESET) &&
12875
17.9k
    (ctxt->value->nodesetval != NULL) &&
12876
17.9k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12877
17.9k
    (ctxt->value->nodesetval->nodeNr > 1)) {
12878
3.89k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12879
3.89k
    *first = *(ctxt->value->nodesetval->nodeTab);
12880
3.89k
      }
12881
17.9k
      return (total);
12882
19.3k
  }
12883
23.2k
    }
12884
12885
48.0k
    if (op->ch1 != -1)
12886
48.0k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12887
48.0k
    CHECK_ERROR0;
12888
35.7k
    if (op->ch2 == -1)
12889
0
  return (total);
12890
35.7k
    if (ctxt->value == NULL)
12891
0
  return (total);
12892
12893
#ifdef LIBXML_XPTR_LOCS_ENABLED
12894
    /*
12895
    * Hum are we filtering the result of an XPointer expression
12896
    */
12897
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12898
        xmlLocationSetPtr locset = ctxt->value->user;
12899
12900
        if (locset != NULL) {
12901
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12902
            if (locset->locNr > 0)
12903
                *first = (xmlNodePtr) locset->locTab[0]->user;
12904
        }
12905
12906
  return (total);
12907
    }
12908
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12909
12910
    /*
12911
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12912
     * the stack. We have to temporarily remove the nodeset object from the
12913
     * stack to avoid freeing it prematurely.
12914
     */
12915
35.7k
    CHECK_TYPE0(XPATH_NODESET);
12916
34.7k
    obj = valuePop(ctxt);
12917
34.7k
    set = obj->nodesetval;
12918
34.7k
    if (set != NULL) {
12919
34.4k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12920
34.4k
        if (set->nodeNr > 0)
12921
11.9k
            *first = set->nodeTab[0];
12922
34.4k
    }
12923
34.7k
    valuePush(ctxt, obj);
12924
12925
34.7k
    return (total);
12926
35.7k
}
12927
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12928
12929
/**
12930
 * xmlXPathCompOpEval:
12931
 * @ctxt:  the XPath parser context with the compiled expression
12932
 * @op:  an XPath compiled operation
12933
 *
12934
 * Evaluate the Precompiled XPath operation
12935
 * Returns the number of nodes traversed
12936
 */
12937
static int
12938
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12939
28.3M
{
12940
28.3M
    int total = 0;
12941
28.3M
    int equal, ret;
12942
28.3M
    xmlXPathCompExprPtr comp;
12943
28.3M
    xmlXPathObjectPtr arg1, arg2;
12944
12945
28.3M
    CHECK_ERROR0;
12946
28.3M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12947
429k
        return(0);
12948
27.9M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12949
27.8M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12950
27.8M
    ctxt->context->depth += 1;
12951
27.8M
    comp = ctxt->comp;
12952
27.8M
    switch (op->op) {
12953
0
        case XPATH_OP_END:
12954
0
            break;
12955
67.0k
        case XPATH_OP_AND:
12956
67.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12957
67.0k
      CHECK_ERROR0;
12958
35.1k
            xmlXPathBooleanFunction(ctxt, 1);
12959
35.1k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12960
20.2k
                break;
12961
14.9k
            arg2 = valuePop(ctxt);
12962
14.9k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12963
14.9k
      if (ctxt->error) {
12964
3.12k
    xmlXPathFreeObject(arg2);
12965
3.12k
    break;
12966
3.12k
      }
12967
11.7k
            xmlXPathBooleanFunction(ctxt, 1);
12968
11.7k
            if (ctxt->value != NULL)
12969
11.7k
                ctxt->value->boolval &= arg2->boolval;
12970
11.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
12971
11.7k
            break;
12972
75.1k
        case XPATH_OP_OR:
12973
75.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974
75.1k
      CHECK_ERROR0;
12975
62.6k
            xmlXPathBooleanFunction(ctxt, 1);
12976
62.6k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12977
4.06k
                break;
12978
58.6k
            arg2 = valuePop(ctxt);
12979
58.6k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12980
58.6k
      if (ctxt->error) {
12981
3.60k
    xmlXPathFreeObject(arg2);
12982
3.60k
    break;
12983
3.60k
      }
12984
55.0k
            xmlXPathBooleanFunction(ctxt, 1);
12985
55.0k
            if (ctxt->value != NULL)
12986
54.9k
                ctxt->value->boolval |= arg2->boolval;
12987
55.0k
      xmlXPathReleaseObject(ctxt->context, arg2);
12988
55.0k
            break;
12989
997k
        case XPATH_OP_EQUAL:
12990
997k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12991
997k
      CHECK_ERROR0;
12992
815k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12993
815k
      CHECK_ERROR0;
12994
685k
      if (op->value)
12995
403k
    equal = xmlXPathEqualValues(ctxt);
12996
282k
      else
12997
282k
    equal = xmlXPathNotEqualValues(ctxt);
12998
685k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12999
685k
            break;
13000
841k
        case XPATH_OP_CMP:
13001
841k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13002
841k
      CHECK_ERROR0;
13003
694k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13004
694k
      CHECK_ERROR0;
13005
639k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13006
639k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13007
639k
            break;
13008
1.94M
        case XPATH_OP_PLUS:
13009
1.94M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13010
1.94M
      CHECK_ERROR0;
13011
1.61M
            if (op->ch2 != -1) {
13012
776k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13013
776k
      }
13014
1.61M
      CHECK_ERROR0;
13015
1.52M
            if (op->value == 0)
13016
545k
                xmlXPathSubValues(ctxt);
13017
978k
            else if (op->value == 1)
13018
135k
                xmlXPathAddValues(ctxt);
13019
842k
            else if (op->value == 2)
13020
595k
                xmlXPathValueFlipSign(ctxt);
13021
247k
            else if (op->value == 3) {
13022
247k
                CAST_TO_NUMBER;
13023
247k
                CHECK_TYPE0(XPATH_NUMBER);
13024
247k
            }
13025
1.52M
            break;
13026
1.52M
        case XPATH_OP_MULT:
13027
763k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13028
763k
      CHECK_ERROR0;
13029
328k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13030
328k
      CHECK_ERROR0;
13031
320k
            if (op->value == 0)
13032
162k
                xmlXPathMultValues(ctxt);
13033
157k
            else if (op->value == 1)
13034
1.25k
                xmlXPathDivValues(ctxt);
13035
156k
            else if (op->value == 2)
13036
156k
                xmlXPathModValues(ctxt);
13037
320k
            break;
13038
1.12M
        case XPATH_OP_UNION:
13039
1.12M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13040
1.12M
      CHECK_ERROR0;
13041
1.10M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13042
1.10M
      CHECK_ERROR0;
13043
13044
1.06M
            arg2 = valuePop(ctxt);
13045
1.06M
            arg1 = valuePop(ctxt);
13046
1.06M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13047
1.06M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13048
22.4k
          xmlXPathReleaseObject(ctxt->context, arg1);
13049
22.4k
          xmlXPathReleaseObject(ctxt->context, arg2);
13050
22.4k
                XP_ERROR0(XPATH_INVALID_TYPE);
13051
0
            }
13052
1.03M
            if ((ctxt->context->opLimit != 0) &&
13053
1.03M
                (((arg1->nodesetval != NULL) &&
13054
1.03M
                  (xmlXPathCheckOpLimit(ctxt,
13055
984k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13056
1.03M
                 ((arg2->nodesetval != NULL) &&
13057
1.03M
                  (xmlXPathCheckOpLimit(ctxt,
13058
982k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13059
112
          xmlXPathReleaseObject(ctxt->context, arg1);
13060
112
          xmlXPathReleaseObject(ctxt->context, arg2);
13061
112
                break;
13062
112
            }
13063
13064
1.03M
      if ((arg1->nodesetval == NULL) ||
13065
1.03M
    ((arg2->nodesetval != NULL) &&
13066
983k
     (arg2->nodesetval->nodeNr != 0)))
13067
822k
      {
13068
                /* TODO: Check memory error. */
13069
822k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13070
822k
              arg2->nodesetval);
13071
822k
      }
13072
13073
1.03M
            valuePush(ctxt, arg1);
13074
1.03M
      xmlXPathReleaseObject(ctxt->context, arg2);
13075
1.03M
            break;
13076
1.87M
        case XPATH_OP_ROOT:
13077
1.87M
            xmlXPathRoot(ctxt);
13078
1.87M
            break;
13079
4.67M
        case XPATH_OP_NODE:
13080
4.67M
            if (op->ch1 != -1)
13081
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13082
4.67M
      CHECK_ERROR0;
13083
4.67M
            if (op->ch2 != -1)
13084
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13085
4.67M
      CHECK_ERROR0;
13086
4.67M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13087
4.67M
    ctxt->context->node));
13088
4.67M
            break;
13089
4.48M
        case XPATH_OP_COLLECT:{
13090
4.48M
                if (op->ch1 == -1)
13091
0
                    break;
13092
13093
4.48M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13094
4.48M
    CHECK_ERROR0;
13095
13096
4.39M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13097
4.39M
                break;
13098
4.48M
            }
13099
827k
        case XPATH_OP_VALUE:
13100
827k
            valuePush(ctxt,
13101
827k
                      xmlXPathCacheObjectCopy(ctxt->context,
13102
827k
      (xmlXPathObjectPtr) op->value4));
13103
827k
            break;
13104
86.4k
        case XPATH_OP_VARIABLE:{
13105
86.4k
    xmlXPathObjectPtr val;
13106
13107
86.4k
                if (op->ch1 != -1)
13108
0
                    total +=
13109
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13110
86.4k
                if (op->value5 == NULL) {
13111
84.7k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13112
84.7k
        if (val == NULL)
13113
57.1k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13114
57.1k
                    valuePush(ctxt, val);
13115
57.1k
    } else {
13116
1.71k
                    const xmlChar *URI;
13117
13118
1.71k
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13119
1.71k
                    if (URI == NULL) {
13120
1.36k
                        xmlGenericError(xmlGenericErrorContext,
13121
1.36k
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13122
1.36k
                                    (char *) op->value4, (char *)op->value5);
13123
1.36k
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13124
1.36k
                        break;
13125
1.36k
                    }
13126
356
        val = xmlXPathVariableLookupNS(ctxt->context,
13127
356
                                                       op->value4, URI);
13128
356
        if (val == NULL)
13129
356
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13130
0
                    valuePush(ctxt, val);
13131
0
                }
13132
57.1k
                break;
13133
86.4k
            }
13134
1.86M
        case XPATH_OP_FUNCTION:{
13135
1.86M
                xmlXPathFunction func;
13136
1.86M
                const xmlChar *oldFunc, *oldFuncURI;
13137
1.86M
    int i;
13138
1.86M
                int frame;
13139
13140
1.86M
                frame = ctxt->valueNr;
13141
1.86M
                if (op->ch1 != -1) {
13142
1.64M
                    total +=
13143
1.64M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13144
1.64M
                    if (ctxt->error != XPATH_EXPRESSION_OK)
13145
68.5k
                        break;
13146
1.64M
                }
13147
1.79M
    if (ctxt->valueNr < frame + op->value) {
13148
0
        xmlGenericError(xmlGenericErrorContext,
13149
0
          "xmlXPathCompOpEval: parameter error\n");
13150
0
        ctxt->error = XPATH_INVALID_OPERAND;
13151
0
        break;
13152
0
    }
13153
4.57M
    for (i = 0; i < op->value; i++) {
13154
2.78M
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13155
0
      xmlGenericError(xmlGenericErrorContext,
13156
0
        "xmlXPathCompOpEval: parameter error\n");
13157
0
      ctxt->error = XPATH_INVALID_OPERAND;
13158
0
      break;
13159
0
        }
13160
2.78M
                }
13161
1.79M
                if (op->cache != NULL)
13162
1.23M
                    func = op->cache;
13163
558k
                else {
13164
558k
                    const xmlChar *URI = NULL;
13165
13166
558k
                    if (op->value5 == NULL)
13167
56.5k
                        func =
13168
56.5k
                            xmlXPathFunctionLookup(ctxt->context,
13169
56.5k
                                                   op->value4);
13170
501k
                    else {
13171
501k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13172
501k
                        if (URI == NULL) {
13173
35.8k
                            xmlGenericError(xmlGenericErrorContext,
13174
35.8k
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13175
35.8k
                                    (char *)op->value4, (char *)op->value5);
13176
35.8k
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13177
35.8k
                            break;
13178
35.8k
                        }
13179
465k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13180
465k
                                                        op->value4, URI);
13181
465k
                    }
13182
522k
                    if (func == NULL) {
13183
46.0k
                        xmlGenericError(xmlGenericErrorContext,
13184
46.0k
                                "xmlXPathCompOpEval: function %s not found\n",
13185
46.0k
                                        (char *)op->value4);
13186
46.0k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13187
0
                    }
13188
476k
                    op->cache = func;
13189
476k
                    op->cacheURI = (void *) URI;
13190
476k
                }
13191
1.71M
                oldFunc = ctxt->context->function;
13192
1.71M
                oldFuncURI = ctxt->context->functionURI;
13193
1.71M
                ctxt->context->function = op->value4;
13194
1.71M
                ctxt->context->functionURI = op->cacheURI;
13195
1.71M
                func(ctxt, op->value);
13196
1.71M
                ctxt->context->function = oldFunc;
13197
1.71M
                ctxt->context->functionURI = oldFuncURI;
13198
1.71M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13199
1.71M
                    (ctxt->valueNr != frame + 1))
13200
1.70M
                    XP_ERROR0(XPATH_STACK_ERROR);
13201
1.70M
                break;
13202
1.71M
            }
13203
2.91M
        case XPATH_OP_ARG:
13204
2.91M
            if (op->ch1 != -1) {
13205
1.27M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206
1.27M
          CHECK_ERROR0;
13207
1.27M
            }
13208
2.87M
            if (op->ch2 != -1) {
13209
2.87M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13210
2.87M
          CHECK_ERROR0;
13211
2.87M
      }
13212
2.80M
            break;
13213
2.80M
        case XPATH_OP_PREDICATE:
13214
262k
        case XPATH_OP_FILTER:{
13215
262k
                xmlXPathObjectPtr obj;
13216
262k
                xmlNodeSetPtr set;
13217
13218
                /*
13219
                 * Optimization for ()[1] selection i.e. the first elem
13220
                 */
13221
262k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13222
262k
#ifdef XP_OPTIMIZED_FILTER_FIRST
13223
        /*
13224
        * FILTER TODO: Can we assume that the inner processing
13225
        *  will result in an ordered list if we have an
13226
        *  XPATH_OP_FILTER?
13227
        *  What about an additional field or flag on
13228
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13229
        *  to assume anything, so it would be more robust and
13230
        *  easier to optimize.
13231
        */
13232
262k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13233
262k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13234
#else
13235
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13236
#endif
13237
262k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13238
142k
                    xmlXPathObjectPtr val;
13239
13240
142k
                    val = comp->steps[op->ch2].value4;
13241
142k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13242
142k
                        (val->floatval == 1.0)) {
13243
86.6k
                        xmlNodePtr first = NULL;
13244
13245
86.6k
                        total +=
13246
86.6k
                            xmlXPathCompOpEvalFirst(ctxt,
13247
86.6k
                                                    &comp->steps[op->ch1],
13248
86.6k
                                                    &first);
13249
86.6k
      CHECK_ERROR0;
13250
                        /*
13251
                         * The nodeset should be in document order,
13252
                         * Keep only the first value
13253
                         */
13254
66.5k
                        if ((ctxt->value != NULL) &&
13255
66.5k
                            (ctxt->value->type == XPATH_NODESET) &&
13256
66.5k
                            (ctxt->value->nodesetval != NULL) &&
13257
66.5k
                            (ctxt->value->nodesetval->nodeNr > 1))
13258
6.34k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13259
6.34k
                                                        1, 1);
13260
66.5k
                        break;
13261
86.6k
                    }
13262
142k
                }
13263
                /*
13264
                 * Optimization for ()[last()] selection i.e. the last elem
13265
                 */
13266
175k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13267
175k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13268
175k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13269
30.5k
                    int f = comp->steps[op->ch2].ch1;
13270
13271
30.5k
                    if ((f != -1) &&
13272
30.5k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13273
30.5k
                        (comp->steps[f].value5 == NULL) &&
13274
30.5k
                        (comp->steps[f].value == 0) &&
13275
30.5k
                        (comp->steps[f].value4 != NULL) &&
13276
30.5k
                        (xmlStrEqual
13277
25.8k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13278
25.3k
                        xmlNodePtr last = NULL;
13279
13280
25.3k
                        total +=
13281
25.3k
                            xmlXPathCompOpEvalLast(ctxt,
13282
25.3k
                                                   &comp->steps[op->ch1],
13283
25.3k
                                                   &last);
13284
25.3k
      CHECK_ERROR0;
13285
                        /*
13286
                         * The nodeset should be in document order,
13287
                         * Keep only the last value
13288
                         */
13289
22.5k
                        if ((ctxt->value != NULL) &&
13290
22.5k
                            (ctxt->value->type == XPATH_NODESET) &&
13291
22.5k
                            (ctxt->value->nodesetval != NULL) &&
13292
22.5k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13293
22.5k
                            (ctxt->value->nodesetval->nodeNr > 1))
13294
8.53k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13295
22.5k
                        break;
13296
25.3k
                    }
13297
30.5k
                }
13298
    /*
13299
    * Process inner predicates first.
13300
    * Example "index[parent::book][1]":
13301
    * ...
13302
    *   PREDICATE   <-- we are here "[1]"
13303
    *     PREDICATE <-- process "[parent::book]" first
13304
    *       SORT
13305
    *         COLLECT  'parent' 'name' 'node' book
13306
    *           NODE
13307
    *     ELEM Object is a number : 1
13308
    */
13309
150k
                if (op->ch1 != -1)
13310
150k
                    total +=
13311
150k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13312
150k
    CHECK_ERROR0;
13313
136k
                if (op->ch2 == -1)
13314
0
                    break;
13315
136k
                if (ctxt->value == NULL)
13316
0
                    break;
13317
13318
#ifdef LIBXML_XPTR_LOCS_ENABLED
13319
                /*
13320
                 * Hum are we filtering the result of an XPointer expression
13321
                 */
13322
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13323
                    xmlLocationSetPtr locset = ctxt->value->user;
13324
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13325
                                              1, locset->locNr);
13326
                    break;
13327
                }
13328
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13329
13330
                /*
13331
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
13332
                 * nodes from the stack. We have to temporarily remove the
13333
                 * nodeset object from the stack to avoid freeing it
13334
                 * prematurely.
13335
                 */
13336
136k
                CHECK_TYPE0(XPATH_NODESET);
13337
126k
                obj = valuePop(ctxt);
13338
126k
                set = obj->nodesetval;
13339
126k
                if (set != NULL)
13340
122k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13341
122k
                                          1, set->nodeNr, 1);
13342
126k
                valuePush(ctxt, obj);
13343
126k
                break;
13344
136k
            }
13345
5.09M
        case XPATH_OP_SORT:
13346
5.09M
            if (op->ch1 != -1)
13347
5.09M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13348
5.09M
      CHECK_ERROR0;
13349
4.67M
            if ((ctxt->value != NULL) &&
13350
4.67M
                (ctxt->value->type == XPATH_NODESET) &&
13351
4.67M
                (ctxt->value->nodesetval != NULL) &&
13352
4.67M
    (ctxt->value->nodesetval->nodeNr > 1))
13353
807k
      {
13354
807k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13355
807k
      }
13356
4.67M
            break;
13357
#ifdef LIBXML_XPTR_LOCS_ENABLED
13358
        case XPATH_OP_RANGETO:{
13359
                xmlXPathObjectPtr range;
13360
                xmlXPathObjectPtr res, obj;
13361
                xmlXPathObjectPtr tmp;
13362
                xmlLocationSetPtr newlocset = NULL;
13363
        xmlLocationSetPtr oldlocset;
13364
                xmlNodeSetPtr oldset;
13365
                xmlNodePtr oldnode = ctxt->context->node;
13366
                int oldcs = ctxt->context->contextSize;
13367
                int oldpp = ctxt->context->proximityPosition;
13368
                int i, j;
13369
13370
                if (op->ch1 != -1) {
13371
                    total +=
13372
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13373
                    CHECK_ERROR0;
13374
                }
13375
                if (ctxt->value == NULL) {
13376
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13377
                }
13378
                if (op->ch2 == -1)
13379
                    break;
13380
13381
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13382
                    /*
13383
                     * Extract the old locset, and then evaluate the result of the
13384
                     * expression for all the element in the locset. use it to grow
13385
                     * up a new locset.
13386
                     */
13387
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13388
13389
                    if ((ctxt->value->user == NULL) ||
13390
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13391
                        break;
13392
13393
                    obj = valuePop(ctxt);
13394
                    oldlocset = obj->user;
13395
13396
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13397
13398
                    for (i = 0; i < oldlocset->locNr; i++) {
13399
                        /*
13400
                         * Run the evaluation with a node list made of a
13401
                         * single item in the nodelocset.
13402
                         */
13403
                        ctxt->context->node = oldlocset->locTab[i]->user;
13404
                        ctxt->context->contextSize = oldlocset->locNr;
13405
                        ctxt->context->proximityPosition = i + 1;
13406
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13407
          ctxt->context->node);
13408
                        valuePush(ctxt, tmp);
13409
13410
                        if (op->ch2 != -1)
13411
                            total +=
13412
                                xmlXPathCompOpEval(ctxt,
13413
                                                   &comp->steps[op->ch2]);
13414
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13415
                            xmlXPtrFreeLocationSet(newlocset);
13416
                            goto rangeto_error;
13417
      }
13418
13419
                        res = valuePop(ctxt);
13420
      if (res->type == XPATH_LOCATIONSET) {
13421
          xmlLocationSetPtr rloc =
13422
              (xmlLocationSetPtr)res->user;
13423
          for (j=0; j<rloc->locNr; j++) {
13424
              range = xmlXPtrNewRange(
13425
          oldlocset->locTab[i]->user,
13426
          oldlocset->locTab[i]->index,
13427
          rloc->locTab[j]->user2,
13428
          rloc->locTab[j]->index2);
13429
        if (range != NULL) {
13430
            xmlXPtrLocationSetAdd(newlocset, range);
13431
        }
13432
          }
13433
      } else {
13434
          range = xmlXPtrNewRangeNodeObject(
13435
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13436
                            if (range != NULL) {
13437
                                xmlXPtrLocationSetAdd(newlocset,range);
13438
          }
13439
                        }
13440
13441
                        /*
13442
                         * Cleanup
13443
                         */
13444
                        if (res != NULL) {
13445
          xmlXPathReleaseObject(ctxt->context, res);
13446
      }
13447
                        if (ctxt->value == tmp) {
13448
                            res = valuePop(ctxt);
13449
          xmlXPathReleaseObject(ctxt->context, res);
13450
                        }
13451
                    }
13452
    } else {  /* Not a location set */
13453
                    CHECK_TYPE0(XPATH_NODESET);
13454
                    obj = valuePop(ctxt);
13455
                    oldset = obj->nodesetval;
13456
13457
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13458
13459
                    if (oldset != NULL) {
13460
                        for (i = 0; i < oldset->nodeNr; i++) {
13461
                            /*
13462
                             * Run the evaluation with a node list made of a single item
13463
                             * in the nodeset.
13464
                             */
13465
                            ctxt->context->node = oldset->nodeTab[i];
13466
          /*
13467
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13468
          */
13469
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13470
        ctxt->context->node);
13471
                            valuePush(ctxt, tmp);
13472
13473
                            if (op->ch2 != -1)
13474
                                total +=
13475
                                    xmlXPathCompOpEval(ctxt,
13476
                                                   &comp->steps[op->ch2]);
13477
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13478
                                xmlXPtrFreeLocationSet(newlocset);
13479
                                goto rangeto_error;
13480
          }
13481
13482
                            res = valuePop(ctxt);
13483
                            range =
13484
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13485
                                                      res);
13486
                            if (range != NULL) {
13487
                                xmlXPtrLocationSetAdd(newlocset, range);
13488
                            }
13489
13490
                            /*
13491
                             * Cleanup
13492
                             */
13493
                            if (res != NULL) {
13494
        xmlXPathReleaseObject(ctxt->context, res);
13495
          }
13496
                            if (ctxt->value == tmp) {
13497
                                res = valuePop(ctxt);
13498
        xmlXPathReleaseObject(ctxt->context, res);
13499
                            }
13500
                        }
13501
                    }
13502
                }
13503
13504
                /*
13505
                 * The result is used as the new evaluation set.
13506
                 */
13507
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13508
rangeto_error:
13509
    xmlXPathReleaseObject(ctxt->context, obj);
13510
                ctxt->context->node = oldnode;
13511
                ctxt->context->contextSize = oldcs;
13512
                ctxt->context->proximityPosition = oldpp;
13513
                break;
13514
            }
13515
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13516
0
        default:
13517
0
            xmlGenericError(xmlGenericErrorContext,
13518
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13519
0
            ctxt->error = XPATH_INVALID_OPERAND;
13520
0
            break;
13521
27.8M
    }
13522
13523
25.6M
    ctxt->context->depth -= 1;
13524
25.6M
    return (total);
13525
27.8M
}
13526
13527
/**
13528
 * xmlXPathCompOpEvalToBoolean:
13529
 * @ctxt:  the XPath parser context
13530
 *
13531
 * Evaluates if the expression evaluates to true.
13532
 *
13533
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13534
 */
13535
static int
13536
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13537
          xmlXPathStepOpPtr op,
13538
          int isPredicate)
13539
542k
{
13540
542k
    xmlXPathObjectPtr resObj = NULL;
13541
13542
594k
start:
13543
594k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13544
398
        return(0);
13545
    /* comp = ctxt->comp; */
13546
594k
    switch (op->op) {
13547
0
        case XPATH_OP_END:
13548
0
            return (0);
13549
210k
  case XPATH_OP_VALUE:
13550
210k
      resObj = (xmlXPathObjectPtr) op->value4;
13551
210k
      if (isPredicate)
13552
210k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13553
43
      return(xmlXPathCastToBoolean(resObj));
13554
52.6k
  case XPATH_OP_SORT:
13555
      /*
13556
      * We don't need sorting for boolean results. Skip this one.
13557
      */
13558
52.6k
            if (op->ch1 != -1) {
13559
52.6k
    op = &ctxt->comp->steps[op->ch1];
13560
52.6k
    goto start;
13561
52.6k
      }
13562
0
      return(0);
13563
51.8k
  case XPATH_OP_COLLECT:
13564
51.8k
      if (op->ch1 == -1)
13565
0
    return(0);
13566
13567
51.8k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13568
51.8k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13569
2.02k
    return(-1);
13570
13571
49.8k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13572
49.8k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13573
930
    return(-1);
13574
13575
48.9k
      resObj = valuePop(ctxt);
13576
48.9k
      if (resObj == NULL)
13577
0
    return(-1);
13578
48.9k
      break;
13579
279k
  default:
13580
      /*
13581
      * Fallback to call xmlXPathCompOpEval().
13582
      */
13583
279k
      xmlXPathCompOpEval(ctxt, op);
13584
279k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13585
8.57k
    return(-1);
13586
13587
270k
      resObj = valuePop(ctxt);
13588
270k
      if (resObj == NULL)
13589
0
    return(-1);
13590
270k
      break;
13591
594k
    }
13592
13593
319k
    if (resObj) {
13594
319k
  int res;
13595
13596
319k
  if (resObj->type == XPATH_BOOLEAN) {
13597
108k
      res = resObj->boolval;
13598
211k
  } else if (isPredicate) {
13599
      /*
13600
      * For predicates a result of type "number" is handled
13601
      * differently:
13602
      * SPEC XPath 1.0:
13603
      * "If the result is a number, the result will be converted
13604
      *  to true if the number is equal to the context position
13605
      *  and will be converted to false otherwise;"
13606
      */
13607
210k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13608
210k
  } else {
13609
690
      res = xmlXPathCastToBoolean(resObj);
13610
690
  }
13611
319k
  xmlXPathReleaseObject(ctxt->context, resObj);
13612
319k
  return(res);
13613
319k
    }
13614
13615
0
    return(0);
13616
319k
}
13617
13618
#ifdef XPATH_STREAMING
13619
/**
13620
 * xmlXPathRunStreamEval:
13621
 * @ctxt:  the XPath parser context with the compiled expression
13622
 *
13623
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13624
 */
13625
static int
13626
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13627
          xmlXPathObjectPtr *resultSeq, int toBool)
13628
2.22M
{
13629
2.22M
    int max_depth, min_depth;
13630
2.22M
    int from_root;
13631
2.22M
    int ret, depth;
13632
2.22M
    int eval_all_nodes;
13633
2.22M
    xmlNodePtr cur = NULL, limit = NULL;
13634
2.22M
    xmlStreamCtxtPtr patstream = NULL;
13635
13636
2.22M
    if ((ctxt == NULL) || (comp == NULL))
13637
0
        return(-1);
13638
2.22M
    max_depth = xmlPatternMaxDepth(comp);
13639
2.22M
    if (max_depth == -1)
13640
0
        return(-1);
13641
2.22M
    if (max_depth == -2)
13642
10.1k
        max_depth = 10000;
13643
2.22M
    min_depth = xmlPatternMinDepth(comp);
13644
2.22M
    if (min_depth == -1)
13645
0
        return(-1);
13646
2.22M
    from_root = xmlPatternFromRoot(comp);
13647
2.22M
    if (from_root < 0)
13648
0
        return(-1);
13649
#if 0
13650
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13651
#endif
13652
13653
2.22M
    if (! toBool) {
13654
2.22M
  if (resultSeq == NULL)
13655
0
      return(-1);
13656
2.22M
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13657
2.22M
  if (*resultSeq == NULL)
13658
44
      return(-1);
13659
2.22M
    }
13660
13661
    /*
13662
     * handle the special cases of "/" amd "." being matched
13663
     */
13664
2.22M
    if (min_depth == 0) {
13665
561k
  if (from_root) {
13666
      /* Select "/" */
13667
0
      if (toBool)
13668
0
    return(1);
13669
            /* TODO: Check memory error. */
13670
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13671
0
                         (xmlNodePtr) ctxt->doc);
13672
561k
  } else {
13673
      /* Select "self::node()" */
13674
561k
      if (toBool)
13675
0
    return(1);
13676
            /* TODO: Check memory error. */
13677
561k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13678
561k
  }
13679
561k
    }
13680
2.22M
    if (max_depth == 0) {
13681
207k
  return(0);
13682
207k
    }
13683
13684
2.01M
    if (from_root) {
13685
31.6k
        cur = (xmlNodePtr)ctxt->doc;
13686
1.98M
    } else if (ctxt->node != NULL) {
13687
1.98M
        switch (ctxt->node->type) {
13688
1.01M
            case XML_ELEMENT_NODE:
13689
1.02M
            case XML_DOCUMENT_NODE:
13690
1.02M
            case XML_DOCUMENT_FRAG_NODE:
13691
1.02M
            case XML_HTML_DOCUMENT_NODE:
13692
1.02M
          cur = ctxt->node;
13693
1.02M
    break;
13694
31
            case XML_ATTRIBUTE_NODE:
13695
933k
            case XML_TEXT_NODE:
13696
933k
            case XML_CDATA_SECTION_NODE:
13697
933k
            case XML_ENTITY_REF_NODE:
13698
933k
            case XML_ENTITY_NODE:
13699
941k
            case XML_PI_NODE:
13700
960k
            case XML_COMMENT_NODE:
13701
960k
            case XML_NOTATION_NODE:
13702
960k
            case XML_DTD_NODE:
13703
960k
            case XML_DOCUMENT_TYPE_NODE:
13704
960k
            case XML_ELEMENT_DECL:
13705
960k
            case XML_ATTRIBUTE_DECL:
13706
960k
            case XML_ENTITY_DECL:
13707
961k
            case XML_NAMESPACE_DECL:
13708
961k
            case XML_XINCLUDE_START:
13709
961k
            case XML_XINCLUDE_END:
13710
961k
    break;
13711
1.98M
  }
13712
1.98M
  limit = cur;
13713
1.98M
    }
13714
2.01M
    if (cur == NULL) {
13715
961k
        return(0);
13716
961k
    }
13717
13718
1.05M
    patstream = xmlPatternGetStreamCtxt(comp);
13719
1.05M
    if (patstream == NULL) {
13720
  /*
13721
  * QUESTION TODO: Is this an error?
13722
  */
13723
105
  return(0);
13724
105
    }
13725
13726
1.05M
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13727
13728
1.05M
    if (from_root) {
13729
31.6k
  ret = xmlStreamPush(patstream, NULL, NULL);
13730
31.6k
  if (ret < 0) {
13731
31.6k
  } else if (ret == 1) {
13732
1.72k
      if (toBool)
13733
0
    goto return_1;
13734
            /* TODO: Check memory error. */
13735
1.72k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13736
1.72k
  }
13737
31.6k
    }
13738
1.05M
    depth = 0;
13739
1.05M
    goto scan_children;
13740
2.07M
next_node:
13741
3.30M
    do {
13742
3.30M
        if (ctxt->opLimit != 0) {
13743
3.30M
            if (ctxt->opCount >= ctxt->opLimit) {
13744
898
                xmlGenericError(xmlGenericErrorContext,
13745
898
                        "XPath operation limit exceeded\n");
13746
898
                xmlFreeStreamCtxt(patstream);
13747
898
                return(-1);
13748
898
            }
13749
3.30M
            ctxt->opCount++;
13750
3.30M
        }
13751
13752
3.30M
  switch (cur->type) {
13753
1.46M
      case XML_ELEMENT_NODE:
13754
3.25M
      case XML_TEXT_NODE:
13755
3.25M
      case XML_CDATA_SECTION_NODE:
13756
3.27M
      case XML_COMMENT_NODE:
13757
3.30M
      case XML_PI_NODE:
13758
3.30M
    if (cur->type == XML_ELEMENT_NODE) {
13759
1.46M
        ret = xmlStreamPush(patstream, cur->name,
13760
1.46M
        (cur->ns ? cur->ns->href : NULL));
13761
1.83M
    } else if (eval_all_nodes)
13762
214k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13763
1.62M
    else
13764
1.62M
        break;
13765
13766
1.68M
    if (ret < 0) {
13767
        /* NOP. */
13768
1.68M
    } else if (ret == 1) {
13769
350k
        if (toBool)
13770
73
      goto return_1;
13771
350k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13772
350k
            < 0) {
13773
829
      ctxt->lastError.domain = XML_FROM_XPATH;
13774
829
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13775
829
        }
13776
350k
    }
13777
1.68M
    if ((cur->children == NULL) || (depth >= max_depth)) {
13778
1.40M
        ret = xmlStreamPop(patstream);
13779
1.40M
        while (cur->next != NULL) {
13780
1.15M
      cur = cur->next;
13781
1.15M
      if ((cur->type != XML_ENTITY_DECL) &&
13782
1.15M
          (cur->type != XML_DTD_NODE))
13783
1.15M
          goto next_node;
13784
1.15M
        }
13785
1.40M
    }
13786
524k
      default:
13787
524k
    break;
13788
3.30M
  }
13789
13790
3.19M
scan_children:
13791
3.19M
  if (cur->type == XML_NAMESPACE_DECL) break;
13792
3.19M
  if ((cur->children != NULL) && (depth < max_depth)) {
13793
      /*
13794
       * Do not descend on entities declarations
13795
       */
13796
1.00M
      if (cur->children->type != XML_ENTITY_DECL) {
13797
1.00M
    cur = cur->children;
13798
1.00M
    depth++;
13799
    /*
13800
     * Skip DTDs
13801
     */
13802
1.00M
    if (cur->type != XML_DTD_NODE)
13803
1.00M
        continue;
13804
1.00M
      }
13805
1.00M
  }
13806
13807
2.19M
  if (cur == limit)
13808
323k
      break;
13809
13810
1.87M
  while (cur->next != NULL) {
13811
921k
      cur = cur->next;
13812
921k
      if ((cur->type != XML_ENTITY_DECL) &&
13813
921k
    (cur->type != XML_DTD_NODE))
13814
921k
    goto next_node;
13815
921k
  }
13816
13817
1.00M
  do {
13818
1.00M
      cur = cur->parent;
13819
1.00M
      depth--;
13820
1.00M
      if ((cur == NULL) || (cur == limit) ||
13821
1.00M
                (cur->type == XML_DOCUMENT_NODE))
13822
729k
          goto done;
13823
274k
      if (cur->type == XML_ELEMENT_NODE) {
13824
274k
    ret = xmlStreamPop(patstream);
13825
274k
      } else if ((eval_all_nodes) &&
13826
0
    ((cur->type == XML_TEXT_NODE) ||
13827
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13828
0
     (cur->type == XML_COMMENT_NODE) ||
13829
0
     (cur->type == XML_PI_NODE)))
13830
0
      {
13831
0
    ret = xmlStreamPop(patstream);
13832
0
      }
13833
274k
      if (cur->next != NULL) {
13834
220k
    cur = cur->next;
13835
220k
    break;
13836
220k
      }
13837
274k
  } while (cur != NULL);
13838
13839
1.22M
    } while ((cur != NULL) && (depth >= 0));
13840
13841
1.05M
done:
13842
13843
1.05M
    if (patstream)
13844
1.05M
  xmlFreeStreamCtxt(patstream);
13845
1.05M
    return(0);
13846
13847
73
return_1:
13848
73
    if (patstream)
13849
73
  xmlFreeStreamCtxt(patstream);
13850
73
    return(1);
13851
2.07M
}
13852
#endif /* XPATH_STREAMING */
13853
13854
/**
13855
 * xmlXPathRunEval:
13856
 * @ctxt:  the XPath parser context with the compiled expression
13857
 * @toBool:  evaluate to a boolean result
13858
 *
13859
 * Evaluate the Precompiled XPath expression in the given context.
13860
 */
13861
static int
13862
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13863
4.98M
{
13864
4.98M
    xmlXPathCompExprPtr comp;
13865
4.98M
    int oldDepth;
13866
13867
4.98M
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13868
0
  return(-1);
13869
13870
4.98M
    if (ctxt->valueTab == NULL) {
13871
  /* Allocate the value stack */
13872
20.2k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13873
20.2k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13874
20.2k
  if (ctxt->valueTab == NULL) {
13875
14
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13876
14
      return(-1);
13877
14
  }
13878
20.2k
  ctxt->valueNr = 0;
13879
20.2k
  ctxt->valueMax = 10;
13880
20.2k
  ctxt->value = NULL;
13881
20.2k
    }
13882
4.98M
#ifdef XPATH_STREAMING
13883
4.98M
    if (ctxt->comp->stream) {
13884
2.22M
  int res;
13885
13886
2.22M
  if (toBool) {
13887
      /*
13888
      * Evaluation to boolean result.
13889
      */
13890
83
      res = xmlXPathRunStreamEval(ctxt->context,
13891
83
    ctxt->comp->stream, NULL, 1);
13892
83
      if (res != -1)
13893
83
    return(res);
13894
2.22M
  } else {
13895
2.22M
      xmlXPathObjectPtr resObj = NULL;
13896
13897
      /*
13898
      * Evaluation to a sequence.
13899
      */
13900
2.22M
      res = xmlXPathRunStreamEval(ctxt->context,
13901
2.22M
    ctxt->comp->stream, &resObj, 0);
13902
13903
2.22M
      if ((res != -1) && (resObj != NULL)) {
13904
2.22M
    valuePush(ctxt, resObj);
13905
2.22M
    return(0);
13906
2.22M
      }
13907
942
      if (resObj != NULL)
13908
898
    xmlXPathReleaseObject(ctxt->context, resObj);
13909
942
  }
13910
  /*
13911
  * QUESTION TODO: This falls back to normal XPath evaluation
13912
  * if res == -1. Is this intended?
13913
  */
13914
2.22M
    }
13915
2.76M
#endif
13916
2.76M
    comp = ctxt->comp;
13917
2.76M
    if (comp->last < 0) {
13918
942
  xmlGenericError(xmlGenericErrorContext,
13919
942
      "xmlXPathRunEval: last is less than zero\n");
13920
942
  return(-1);
13921
942
    }
13922
2.76M
    oldDepth = ctxt->context->depth;
13923
2.76M
    if (toBool)
13924
21.1k
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13925
21.1k
      &comp->steps[comp->last], 0));
13926
2.74M
    else
13927
2.74M
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13928
2.74M
    ctxt->context->depth = oldDepth;
13929
13930
2.74M
    return(0);
13931
2.76M
}
13932
13933
/************************************************************************
13934
 *                  *
13935
 *      Public interfaces       *
13936
 *                  *
13937
 ************************************************************************/
13938
13939
/**
13940
 * xmlXPathEvalPredicate:
13941
 * @ctxt:  the XPath context
13942
 * @res:  the Predicate Expression evaluation result
13943
 *
13944
 * Evaluate a predicate result for the current node.
13945
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13946
 * the result to a boolean. If the result is a number, the result will
13947
 * be converted to true if the number is equal to the position of the
13948
 * context node in the context node list (as returned by the position
13949
 * function) and will be converted to false otherwise; if the result
13950
 * is not a number, then the result will be converted as if by a call
13951
 * to the boolean function.
13952
 *
13953
 * Returns 1 if predicate is true, 0 otherwise
13954
 */
13955
int
13956
25.5k
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13957
25.5k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13958
25.5k
    switch (res->type) {
13959
13.8k
        case XPATH_BOOLEAN:
13960
13.8k
      return(res->boolval);
13961
5.98k
        case XPATH_NUMBER:
13962
5.98k
      return(res->floatval == ctxt->proximityPosition);
13963
2.83k
        case XPATH_NODESET:
13964
2.83k
        case XPATH_XSLT_TREE:
13965
2.83k
      if (res->nodesetval == NULL)
13966
687
    return(0);
13967
2.14k
      return(res->nodesetval->nodeNr != 0);
13968
2.88k
        case XPATH_STRING:
13969
2.88k
      return((res->stringval != NULL) &&
13970
2.88k
             (xmlStrlen(res->stringval) != 0));
13971
0
        default:
13972
0
      STRANGE
13973
25.5k
    }
13974
0
    return(0);
13975
25.5k
}
13976
13977
/**
13978
 * xmlXPathEvaluatePredicateResult:
13979
 * @ctxt:  the XPath Parser context
13980
 * @res:  the Predicate Expression evaluation result
13981
 *
13982
 * Evaluate a predicate result for the current node.
13983
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13984
 * the result to a boolean. If the result is a number, the result will
13985
 * be converted to true if the number is equal to the position of the
13986
 * context node in the context node list (as returned by the position
13987
 * function) and will be converted to false otherwise; if the result
13988
 * is not a number, then the result will be converted as if by a call
13989
 * to the boolean function.
13990
 *
13991
 * Returns 1 if predicate is true, 0 otherwise
13992
 */
13993
int
13994
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13995
421k
                                xmlXPathObjectPtr res) {
13996
421k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13997
421k
    switch (res->type) {
13998
0
        case XPATH_BOOLEAN:
13999
0
      return(res->boolval);
14000
188k
        case XPATH_NUMBER:
14001
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14002
      return((res->floatval == ctxt->context->proximityPosition) &&
14003
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14004
#else
14005
188k
      return(res->floatval == ctxt->context->proximityPosition);
14006
0
#endif
14007
67.3k
        case XPATH_NODESET:
14008
67.3k
        case XPATH_XSLT_TREE:
14009
67.3k
      if (res->nodesetval == NULL)
14010
5.40k
    return(0);
14011
61.9k
      return(res->nodesetval->nodeNr != 0);
14012
165k
        case XPATH_STRING:
14013
165k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14014
#ifdef LIBXML_XPTR_LOCS_ENABLED
14015
  case XPATH_LOCATIONSET:{
14016
      xmlLocationSetPtr ptr = res->user;
14017
      if (ptr == NULL)
14018
          return(0);
14019
      return (ptr->locNr != 0);
14020
      }
14021
#endif
14022
0
        default:
14023
0
      STRANGE
14024
421k
    }
14025
0
    return(0);
14026
421k
}
14027
14028
#ifdef XPATH_STREAMING
14029
/**
14030
 * xmlXPathTryStreamCompile:
14031
 * @ctxt: an XPath context
14032
 * @str:  the XPath expression
14033
 *
14034
 * Try to compile the XPath expression as a streamable subset.
14035
 *
14036
 * Returns the compiled expression or NULL if failed to compile.
14037
 */
14038
static xmlXPathCompExprPtr
14039
1.15M
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14040
    /*
14041
     * Optimization: use streaming patterns when the XPath expression can
14042
     * be compiled to a stream lookup
14043
     */
14044
1.15M
    xmlPatternPtr stream;
14045
1.15M
    xmlXPathCompExprPtr comp;
14046
1.15M
    xmlDictPtr dict = NULL;
14047
1.15M
    const xmlChar **namespaces = NULL;
14048
1.15M
    xmlNsPtr ns;
14049
1.15M
    int i, j;
14050
14051
1.15M
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14052
1.15M
        (!xmlStrchr(str, '@'))) {
14053
493k
  const xmlChar *tmp;
14054
14055
  /*
14056
   * We don't try to handle expressions using the verbose axis
14057
   * specifiers ("::"), just the simplified form at this point.
14058
   * Additionally, if there is no list of namespaces available and
14059
   *  there's a ":" in the expression, indicating a prefixed QName,
14060
   *  then we won't try to compile either. xmlPatterncompile() needs
14061
   *  to have a list of namespaces at compilation time in order to
14062
   *  compile prefixed name tests.
14063
   */
14064
493k
  tmp = xmlStrchr(str, ':');
14065
493k
  if ((tmp != NULL) &&
14066
493k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14067
9.04k
      return(NULL);
14068
14069
484k
  if (ctxt != NULL) {
14070
484k
      dict = ctxt->dict;
14071
484k
      if (ctxt->nsNr > 0) {
14072
424k
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14073
424k
    if (namespaces == NULL) {
14074
37
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14075
37
        return(NULL);
14076
37
    }
14077
5.11M
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14078
4.68M
        ns = ctxt->namespaces[j];
14079
4.68M
        namespaces[i++] = ns->href;
14080
4.68M
        namespaces[i++] = ns->prefix;
14081
4.68M
    }
14082
424k
    namespaces[i++] = NULL;
14083
424k
    namespaces[i] = NULL;
14084
424k
      }
14085
484k
  }
14086
14087
484k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14088
484k
  if (namespaces != NULL) {
14089
424k
      xmlFree((xmlChar **)namespaces);
14090
424k
  }
14091
484k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14092
200k
      comp = xmlXPathNewCompExpr();
14093
200k
      if (comp == NULL) {
14094
19
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14095
19
          xmlFreePattern(stream);
14096
19
    return(NULL);
14097
19
      }
14098
200k
      comp->stream = stream;
14099
200k
      comp->dict = dict;
14100
200k
      if (comp->dict)
14101
22.5k
    xmlDictReference(comp->dict);
14102
200k
      return(comp);
14103
200k
  }
14104
284k
  xmlFreePattern(stream);
14105
284k
    }
14106
942k
    return(NULL);
14107
1.15M
}
14108
#endif /* XPATH_STREAMING */
14109
14110
static void
14111
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14112
                           xmlXPathStepOpPtr op)
14113
15.9M
{
14114
15.9M
    xmlXPathCompExprPtr comp = pctxt->comp;
14115
15.9M
    xmlXPathContextPtr ctxt;
14116
14117
    /*
14118
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14119
    * internal representation.
14120
    */
14121
14122
15.9M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14123
15.9M
        (op->ch1 != -1) &&
14124
15.9M
        (op->ch2 == -1 /* no predicate */))
14125
2.65M
    {
14126
2.65M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14127
14128
2.65M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14129
2.65M
            ((xmlXPathAxisVal) prevop->value ==
14130
342k
                AXIS_DESCENDANT_OR_SELF) &&
14131
2.65M
            (prevop->ch2 == -1) &&
14132
2.65M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14133
2.65M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14134
221k
        {
14135
            /*
14136
            * This is a "descendant-or-self::node()" without predicates.
14137
            * Try to eliminate it.
14138
            */
14139
14140
221k
            switch ((xmlXPathAxisVal) op->value) {
14141
216k
                case AXIS_CHILD:
14142
216k
                case AXIS_DESCENDANT:
14143
                    /*
14144
                    * Convert "descendant-or-self::node()/child::" or
14145
                    * "descendant-or-self::node()/descendant::" to
14146
                    * "descendant::"
14147
                    */
14148
216k
                    op->ch1   = prevop->ch1;
14149
216k
                    op->value = AXIS_DESCENDANT;
14150
216k
                    break;
14151
0
                case AXIS_SELF:
14152
1
                case AXIS_DESCENDANT_OR_SELF:
14153
                    /*
14154
                    * Convert "descendant-or-self::node()/self::" or
14155
                    * "descendant-or-self::node()/descendant-or-self::" to
14156
                    * to "descendant-or-self::"
14157
                    */
14158
1
                    op->ch1   = prevop->ch1;
14159
1
                    op->value = AXIS_DESCENDANT_OR_SELF;
14160
1
                    break;
14161
4.83k
                default:
14162
4.83k
                    break;
14163
221k
            }
14164
221k
  }
14165
2.65M
    }
14166
14167
    /* OP_VALUE has invalid ch1. */
14168
15.9M
    if (op->op == XPATH_OP_VALUE)
14169
861k
        return;
14170
14171
    /* Recurse */
14172
15.1M
    ctxt = pctxt->context;
14173
15.1M
    if (ctxt != NULL) {
14174
15.1M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14175
99.8k
            return;
14176
15.0M
        ctxt->depth += 1;
14177
15.0M
    }
14178
15.0M
    if (op->ch1 != -1)
14179
10.4M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14180
15.0M
    if (op->ch2 != -1)
14181
5.22M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14182
15.0M
    if (ctxt != NULL)
14183
15.0M
        ctxt->depth -= 1;
14184
15.0M
}
14185
14186
/**
14187
 * xmlXPathCtxtCompile:
14188
 * @ctxt: an XPath context
14189
 * @str:  the XPath expression
14190
 *
14191
 * Compile an XPath expression
14192
 *
14193
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14194
 *         the caller has to free the object.
14195
 */
14196
xmlXPathCompExprPtr
14197
1.11M
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14198
1.11M
    xmlXPathParserContextPtr pctxt;
14199
1.11M
    xmlXPathCompExprPtr comp;
14200
1.11M
    int oldDepth = 0;
14201
14202
1.11M
#ifdef XPATH_STREAMING
14203
1.11M
    comp = xmlXPathTryStreamCompile(ctxt, str);
14204
1.11M
    if (comp != NULL)
14205
196k
        return(comp);
14206
916k
#endif
14207
14208
916k
    xmlInitParser();
14209
14210
916k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14211
916k
    if (pctxt == NULL)
14212
1.05k
        return NULL;
14213
915k
    if (ctxt != NULL)
14214
915k
        oldDepth = ctxt->depth;
14215
915k
    xmlXPathCompileExpr(pctxt, 1);
14216
915k
    if (ctxt != NULL)
14217
915k
        ctxt->depth = oldDepth;
14218
14219
915k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14220
394k
    {
14221
394k
        xmlXPathFreeParserContext(pctxt);
14222
394k
        return(NULL);
14223
394k
    }
14224
14225
520k
    if (*pctxt->cur != 0) {
14226
  /*
14227
   * aleksey: in some cases this line prints *second* error message
14228
   * (see bug #78858) and probably this should be fixed.
14229
   * However, we are not sure that all error messages are printed
14230
   * out in other places. It's not critical so we leave it as-is for now
14231
   */
14232
151k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14233
151k
  comp = NULL;
14234
369k
    } else {
14235
369k
  comp = pctxt->comp;
14236
369k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14237
357k
            if (ctxt != NULL)
14238
357k
                oldDepth = ctxt->depth;
14239
357k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14240
357k
            if (ctxt != NULL)
14241
357k
                ctxt->depth = oldDepth;
14242
357k
  }
14243
369k
  pctxt->comp = NULL;
14244
369k
    }
14245
520k
    xmlXPathFreeParserContext(pctxt);
14246
14247
520k
    if (comp != NULL) {
14248
369k
  comp->expr = xmlStrdup(str);
14249
#ifdef DEBUG_EVAL_COUNTS
14250
  comp->string = xmlStrdup(str);
14251
  comp->nb = 0;
14252
#endif
14253
369k
    }
14254
520k
    return(comp);
14255
915k
}
14256
14257
/**
14258
 * xmlXPathCompile:
14259
 * @str:  the XPath expression
14260
 *
14261
 * Compile an XPath expression
14262
 *
14263
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14264
 *         the caller has to free the object.
14265
 */
14266
xmlXPathCompExprPtr
14267
0
xmlXPathCompile(const xmlChar *str) {
14268
0
    return(xmlXPathCtxtCompile(NULL, str));
14269
0
}
14270
14271
/**
14272
 * xmlXPathCompiledEvalInternal:
14273
 * @comp:  the compiled XPath expression
14274
 * @ctxt:  the XPath context
14275
 * @resObj: the resulting XPath object or NULL
14276
 * @toBool: 1 if only a boolean result is requested
14277
 *
14278
 * Evaluate the Precompiled XPath expression in the given context.
14279
 * The caller has to free @resObj.
14280
 *
14281
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14282
 *         the caller has to free the object.
14283
 */
14284
static int
14285
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14286
           xmlXPathContextPtr ctxt,
14287
           xmlXPathObjectPtr *resObjPtr,
14288
           int toBool)
14289
5.01M
{
14290
5.01M
    xmlXPathParserContextPtr pctxt;
14291
5.01M
    xmlXPathObjectPtr resObj;
14292
#ifndef LIBXML_THREAD_ENABLED
14293
    static int reentance = 0;
14294
#endif
14295
5.01M
    int res;
14296
14297
5.01M
    CHECK_CTXT_NEG(ctxt)
14298
14299
5.01M
    if (comp == NULL)
14300
5.30k
  return(-1);
14301
5.01M
    xmlInitParser();
14302
14303
#ifndef LIBXML_THREAD_ENABLED
14304
    reentance++;
14305
    if (reentance > 1)
14306
  xmlXPathDisableOptimizer = 1;
14307
#endif
14308
14309
#ifdef DEBUG_EVAL_COUNTS
14310
    comp->nb++;
14311
    if ((comp->string != NULL) && (comp->nb > 100)) {
14312
  fprintf(stderr, "100 x %s\n", comp->string);
14313
  comp->nb = 0;
14314
    }
14315
#endif
14316
5.01M
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14317
5.01M
    if (pctxt == NULL)
14318
44.5k
        return(-1);
14319
4.96M
    res = xmlXPathRunEval(pctxt, toBool);
14320
14321
4.96M
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14322
768k
        resObj = NULL;
14323
4.19M
    } else {
14324
4.19M
        resObj = valuePop(pctxt);
14325
4.19M
        if (resObj == NULL) {
14326
22.1k
            if (!toBool)
14327
942
                xmlGenericError(xmlGenericErrorContext,
14328
942
                    "xmlXPathCompiledEval: No result on the stack.\n");
14329
4.17M
        } else if (pctxt->valueNr > 0) {
14330
0
            xmlGenericError(xmlGenericErrorContext,
14331
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14332
0
                pctxt->valueNr);
14333
0
        }
14334
4.19M
    }
14335
14336
4.96M
    if (resObjPtr)
14337
4.94M
        *resObjPtr = resObj;
14338
21.2k
    else
14339
21.2k
        xmlXPathReleaseObject(ctxt, resObj);
14340
14341
4.96M
    pctxt->comp = NULL;
14342
4.96M
    xmlXPathFreeParserContext(pctxt);
14343
#ifndef LIBXML_THREAD_ENABLED
14344
    reentance--;
14345
#endif
14346
14347
4.96M
    return(res);
14348
5.01M
}
14349
14350
/**
14351
 * xmlXPathCompiledEval:
14352
 * @comp:  the compiled XPath expression
14353
 * @ctx:  the XPath context
14354
 *
14355
 * Evaluate the Precompiled XPath expression in the given context.
14356
 *
14357
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14358
 *         the caller has to free the object.
14359
 */
14360
xmlXPathObjectPtr
14361
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14362
4.99M
{
14363
4.99M
    xmlXPathObjectPtr res = NULL;
14364
14365
4.99M
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14366
4.99M
    return(res);
14367
4.99M
}
14368
14369
/**
14370
 * xmlXPathCompiledEvalToBoolean:
14371
 * @comp:  the compiled XPath expression
14372
 * @ctxt:  the XPath context
14373
 *
14374
 * Applies the XPath boolean() function on the result of the given
14375
 * compiled expression.
14376
 *
14377
 * Returns 1 if the expression evaluated to true, 0 if to false and
14378
 *         -1 in API and internal errors.
14379
 */
14380
int
14381
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14382
            xmlXPathContextPtr ctxt)
14383
21.2k
{
14384
21.2k
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14385
21.2k
}
14386
14387
/**
14388
 * xmlXPathEvalExpr:
14389
 * @ctxt:  the XPath Parser context
14390
 *
14391
 * Parse and evaluate an XPath expression in the given context,
14392
 * then push the result on the context stack
14393
 */
14394
void
14395
38.3k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14396
38.3k
#ifdef XPATH_STREAMING
14397
38.3k
    xmlXPathCompExprPtr comp;
14398
38.3k
#endif
14399
38.3k
    int oldDepth = 0;
14400
14401
38.3k
    if (ctxt == NULL) return;
14402
14403
38.3k
#ifdef XPATH_STREAMING
14404
38.3k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14405
38.3k
    if (comp != NULL) {
14406
3.59k
        if (ctxt->comp != NULL)
14407
3.59k
      xmlXPathFreeCompExpr(ctxt->comp);
14408
3.59k
        ctxt->comp = comp;
14409
3.59k
    } else
14410
34.7k
#endif
14411
34.7k
    {
14412
34.7k
        if (ctxt->context != NULL)
14413
34.7k
            oldDepth = ctxt->context->depth;
14414
34.7k
  xmlXPathCompileExpr(ctxt, 1);
14415
34.7k
        if (ctxt->context != NULL)
14416
34.7k
            ctxt->context->depth = oldDepth;
14417
34.7k
        CHECK_ERROR;
14418
14419
        /* Check for trailing characters. */
14420
23.3k
        if (*ctxt->cur != 0)
14421
16.7k
            XP_ERROR(XPATH_EXPR_ERROR);
14422
14423
16.7k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14424
14.8k
            if (ctxt->context != NULL)
14425
14.8k
                oldDepth = ctxt->context->depth;
14426
14.8k
      xmlXPathOptimizeExpression(ctxt,
14427
14.8k
    &ctxt->comp->steps[ctxt->comp->last]);
14428
14.8k
            if (ctxt->context != NULL)
14429
14.8k
                ctxt->context->depth = oldDepth;
14430
14.8k
        }
14431
16.7k
    }
14432
14433
20.3k
    xmlXPathRunEval(ctxt, 0);
14434
20.3k
}
14435
14436
/**
14437
 * xmlXPathEval:
14438
 * @str:  the XPath expression
14439
 * @ctx:  the XPath context
14440
 *
14441
 * Evaluate the XPath Location Path in the given context.
14442
 *
14443
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14444
 *         the caller has to free the object.
14445
 */
14446
xmlXPathObjectPtr
14447
40.4k
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14448
40.4k
    xmlXPathParserContextPtr ctxt;
14449
40.4k
    xmlXPathObjectPtr res;
14450
14451
40.4k
    CHECK_CTXT(ctx)
14452
14453
40.4k
    xmlInitParser();
14454
14455
40.4k
    ctxt = xmlXPathNewParserContext(str, ctx);
14456
40.4k
    if (ctxt == NULL)
14457
2.21k
        return NULL;
14458
38.2k
    xmlXPathEvalExpr(ctxt);
14459
14460
38.2k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14461
24.4k
  res = NULL;
14462
24.4k
    } else {
14463
13.8k
  res = valuePop(ctxt);
14464
13.8k
        if (res == NULL) {
14465
0
            xmlGenericError(xmlGenericErrorContext,
14466
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14467
13.8k
        } else if (ctxt->valueNr > 0) {
14468
0
            xmlGenericError(xmlGenericErrorContext,
14469
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14470
0
                ctxt->valueNr);
14471
0
        }
14472
13.8k
    }
14473
14474
38.2k
    xmlXPathFreeParserContext(ctxt);
14475
38.2k
    return(res);
14476
40.4k
}
14477
14478
/**
14479
 * xmlXPathSetContextNode:
14480
 * @node: the node to to use as the context node
14481
 * @ctx:  the XPath context
14482
 *
14483
 * Sets 'node' as the context node. The node must be in the same
14484
 * document as that associated with the context.
14485
 *
14486
 * Returns -1 in case of error or 0 if successful
14487
 */
14488
int
14489
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14490
0
    if ((node == NULL) || (ctx == NULL))
14491
0
        return(-1);
14492
14493
0
    if (node->doc == ctx->doc) {
14494
0
        ctx->node = node;
14495
0
  return(0);
14496
0
    }
14497
0
    return(-1);
14498
0
}
14499
14500
/**
14501
 * xmlXPathNodeEval:
14502
 * @node: the node to to use as the context node
14503
 * @str:  the XPath expression
14504
 * @ctx:  the XPath context
14505
 *
14506
 * Evaluate the XPath Location Path in the given context. The node 'node'
14507
 * is set as the context node. The context node is not restored.
14508
 *
14509
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14510
 *         the caller has to free the object.
14511
 */
14512
xmlXPathObjectPtr
14513
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14514
0
    if (str == NULL)
14515
0
        return(NULL);
14516
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14517
0
        return(NULL);
14518
0
    return(xmlXPathEval(str, ctx));
14519
0
}
14520
14521
/**
14522
 * xmlXPathEvalExpression:
14523
 * @str:  the XPath expression
14524
 * @ctxt:  the XPath context
14525
 *
14526
 * Alias for xmlXPathEval().
14527
 *
14528
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14529
 *         the caller has to free the object.
14530
 */
14531
xmlXPathObjectPtr
14532
4.27k
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14533
4.27k
    return(xmlXPathEval(str, ctxt));
14534
4.27k
}
14535
14536
/************************************************************************
14537
 *                  *
14538
 *  Extra functions not pertaining to the XPath spec    *
14539
 *                  *
14540
 ************************************************************************/
14541
/**
14542
 * xmlXPathEscapeUriFunction:
14543
 * @ctxt:  the XPath Parser context
14544
 * @nargs:  the number of arguments
14545
 *
14546
 * Implement the escape-uri() XPath function
14547
 *    string escape-uri(string $str, bool $escape-reserved)
14548
 *
14549
 * This function applies the URI escaping rules defined in section 2 of [RFC
14550
 * 2396] to the string supplied as $uri-part, which typically represents all
14551
 * or part of a URI. The effect of the function is to replace any special
14552
 * character in the string by an escape sequence of the form %xx%yy...,
14553
 * where xxyy... is the hexadecimal representation of the octets used to
14554
 * represent the character in UTF-8.
14555
 *
14556
 * The set of characters that are escaped depends on the setting of the
14557
 * boolean argument $escape-reserved.
14558
 *
14559
 * If $escape-reserved is true, all characters are escaped other than lower
14560
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14561
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14562
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14563
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14564
 * A-F).
14565
 *
14566
 * If $escape-reserved is false, the behavior differs in that characters
14567
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14568
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14569
 *
14570
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14571
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14572
 * compared using string comparison functions, this function must always use
14573
 * the upper-case letters A-F.
14574
 *
14575
 * Generally, $escape-reserved should be set to true when escaping a string
14576
 * that is to form a single part of a URI, and to false when escaping an
14577
 * entire URI or URI reference.
14578
 *
14579
 * In the case of non-ascii characters, the string is encoded according to
14580
 * utf-8 and then converted according to RFC 2396.
14581
 *
14582
 * Examples
14583
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14584
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14585
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14586
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14587
 *
14588
 */
14589
static void
14590
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14591
0
    xmlXPathObjectPtr str;
14592
0
    int escape_reserved;
14593
0
    xmlBufPtr target;
14594
0
    xmlChar *cptr;
14595
0
    xmlChar escape[4];
14596
14597
0
    CHECK_ARITY(2);
14598
14599
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14600
14601
0
    CAST_TO_STRING;
14602
0
    str = valuePop(ctxt);
14603
14604
0
    target = xmlBufCreate();
14605
14606
0
    escape[0] = '%';
14607
0
    escape[3] = 0;
14608
14609
0
    if (target) {
14610
0
  for (cptr = str->stringval; *cptr; cptr++) {
14611
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14612
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14613
0
    (*cptr >= '0' && *cptr <= '9') ||
14614
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14615
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14616
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14617
0
    (*cptr == '%' &&
14618
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14619
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14620
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14621
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14622
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14623
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14624
0
    (!escape_reserved &&
14625
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14626
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14627
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14628
0
      *cptr == ','))) {
14629
0
    xmlBufAdd(target, cptr, 1);
14630
0
      } else {
14631
0
    if ((*cptr >> 4) < 10)
14632
0
        escape[1] = '0' + (*cptr >> 4);
14633
0
    else
14634
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14635
0
    if ((*cptr & 0xF) < 10)
14636
0
        escape[2] = '0' + (*cptr & 0xF);
14637
0
    else
14638
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14639
14640
0
    xmlBufAdd(target, &escape[0], 3);
14641
0
      }
14642
0
  }
14643
0
    }
14644
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14645
0
  xmlBufContent(target)));
14646
0
    xmlBufFree(target);
14647
0
    xmlXPathReleaseObject(ctxt->context, str);
14648
0
}
14649
14650
/**
14651
 * xmlXPathRegisterAllFunctions:
14652
 * @ctxt:  the XPath context
14653
 *
14654
 * Registers all default XPath functions in this context
14655
 */
14656
void
14657
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14658
59.6k
{
14659
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14660
59.6k
                         xmlXPathBooleanFunction);
14661
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14662
59.6k
                         xmlXPathCeilingFunction);
14663
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14664
59.6k
                         xmlXPathCountFunction);
14665
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14666
59.6k
                         xmlXPathConcatFunction);
14667
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14668
59.6k
                         xmlXPathContainsFunction);
14669
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14670
59.6k
                         xmlXPathIdFunction);
14671
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14672
59.6k
                         xmlXPathFalseFunction);
14673
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14674
59.6k
                         xmlXPathFloorFunction);
14675
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14676
59.6k
                         xmlXPathLastFunction);
14677
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14678
59.6k
                         xmlXPathLangFunction);
14679
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14680
59.6k
                         xmlXPathLocalNameFunction);
14681
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14682
59.6k
                         xmlXPathNotFunction);
14683
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14684
59.6k
                         xmlXPathNameFunction);
14685
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14686
59.6k
                         xmlXPathNamespaceURIFunction);
14687
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14688
59.6k
                         xmlXPathNormalizeFunction);
14689
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14690
59.6k
                         xmlXPathNumberFunction);
14691
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14692
59.6k
                         xmlXPathPositionFunction);
14693
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14694
59.6k
                         xmlXPathRoundFunction);
14695
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14696
59.6k
                         xmlXPathStringFunction);
14697
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14698
59.6k
                         xmlXPathStringLengthFunction);
14699
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14700
59.6k
                         xmlXPathStartsWithFunction);
14701
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14702
59.6k
                         xmlXPathSubstringFunction);
14703
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14704
59.6k
                         xmlXPathSubstringBeforeFunction);
14705
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14706
59.6k
                         xmlXPathSubstringAfterFunction);
14707
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14708
59.6k
                         xmlXPathSumFunction);
14709
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14710
59.6k
                         xmlXPathTrueFunction);
14711
59.6k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14712
59.6k
                         xmlXPathTranslateFunction);
14713
14714
59.6k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14715
59.6k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14716
59.6k
                         xmlXPathEscapeUriFunction);
14717
59.6k
}
14718
14719
#endif /* LIBXML_XPATH_ENABLED */