Coverage Report

Created: 2023-12-13 20:03

/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
55
#ifdef LIBXML_PATTERN_ENABLED
56
#define XPATH_STREAMING
57
#endif
58
59
#define TODO                \
60
0
    xmlGenericError(xmlGenericErrorContext,       \
61
0
      "Unimplemented block at %s:%d\n",       \
62
0
            __FILE__, __LINE__);
63
64
/**
65
 * WITH_TIM_SORT:
66
 *
67
 * Use the Timsort algorithm provided in timsort.h to sort
68
 * nodeset as this is a great improvement over the old Shell sort
69
 * used in xmlXPathNodeSetSort()
70
 */
71
#define WITH_TIM_SORT
72
73
/*
74
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
75
* If defined, this will use xmlXPathCmpNodesExt() instead of
76
* xmlXPathCmpNodes(). The new function is optimized comparison of
77
* non-element nodes; actually it will speed up comparison only if
78
* xmlXPathOrderDocElems() was called in order to index the elements of
79
* a tree in document order; Libxslt does such an indexing, thus it will
80
* benefit from this optimization.
81
*/
82
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
83
84
/*
85
* XP_OPTIMIZED_FILTER_FIRST:
86
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
87
* in a way, that it stop evaluation at the first node.
88
*/
89
#define XP_OPTIMIZED_FILTER_FIRST
90
91
/*
92
* XP_DEBUG_OBJ_USAGE:
93
* Internal flag to enable tracking of how much XPath objects have been
94
* created.
95
*/
96
/* #define XP_DEBUG_OBJ_USAGE */
97
98
/*
99
 * XPATH_MAX_STEPS:
100
 * when compiling an XPath expression we arbitrary limit the maximum
101
 * number of step operation in the compiled expression. 1000000 is
102
 * an insanely large value which should never be reached under normal
103
 * circumstances
104
 */
105
82.6k
#define XPATH_MAX_STEPS 1000000
106
107
/*
108
 * XPATH_MAX_STACK_DEPTH:
109
 * when evaluating an XPath expression we arbitrary limit the maximum
110
 * number of object allowed to be pushed on the stack. 1000000 is
111
 * an insanely large value which should never be reached under normal
112
 * circumstances
113
 */
114
18
#define XPATH_MAX_STACK_DEPTH 1000000
115
116
/*
117
 * XPATH_MAX_NODESET_LENGTH:
118
 * when evaluating an XPath expression nodesets are created and we
119
 * arbitrary limit the maximum length of those node set. 10000000 is
120
 * an insanely large value which should never be reached under normal
121
 * circumstances, one would first need to construct an in memory tree
122
 * with more than 10 millions nodes.
123
 */
124
367k
#define XPATH_MAX_NODESET_LENGTH 10000000
125
126
/*
127
 * XPATH_MAX_RECRUSION_DEPTH:
128
 * Maximum amount of nested functions calls when parsing or evaluating
129
 * expressions
130
 */
131
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
132
5.12M
#define XPATH_MAX_RECURSION_DEPTH 500
133
#elif defined(_WIN32)
134
/* Windows typically limits stack size to 1MB. */
135
#define XPATH_MAX_RECURSION_DEPTH 1000
136
#else
137
#define XPATH_MAX_RECURSION_DEPTH 5000
138
#endif
139
140
/*
141
 * TODO:
142
 * There are a few spots where some tests are done which depend upon ascii
143
 * data.  These should be enhanced for full UTF8 support (see particularly
144
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
145
 */
146
147
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
148
/**
149
 * xmlXPathCmpNodesExt:
150
 * @node1:  the first node
151
 * @node2:  the second node
152
 *
153
 * Compare two nodes w.r.t document order.
154
 * This one is optimized for handling of non-element nodes.
155
 *
156
 * Returns -2 in case of error 1 if first point < second point, 0 if
157
 *         it's the same node, -1 otherwise
158
 */
159
static int
160
10.2M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
161
10.2M
    int depth1, depth2;
162
10.2M
    int misc = 0, precedence1 = 0, precedence2 = 0;
163
10.2M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
164
10.2M
    xmlNodePtr cur, root;
165
10.2M
    ptrdiff_t l1, l2;
166
167
10.2M
    if ((node1 == NULL) || (node2 == NULL))
168
0
  return(-2);
169
170
10.2M
    if (node1 == node2)
171
0
  return(0);
172
173
    /*
174
     * a couple of optimizations which will avoid computations in most cases
175
     */
176
10.2M
    switch (node1->type) {
177
6.09M
  case XML_ELEMENT_NODE:
178
6.09M
      if (node2->type == XML_ELEMENT_NODE) {
179
5.56M
    if ((0 > (ptrdiff_t) node1->content) &&
180
5.56M
        (0 > (ptrdiff_t) node2->content) &&
181
5.56M
        (node1->doc == node2->doc))
182
0
    {
183
0
        l1 = -((ptrdiff_t) node1->content);
184
0
        l2 = -((ptrdiff_t) node2->content);
185
0
        if (l1 < l2)
186
0
      return(1);
187
0
        if (l1 > l2)
188
0
      return(-1);
189
0
    } else
190
5.56M
        goto turtle_comparison;
191
5.56M
      }
192
526k
      break;
193
526k
  case XML_ATTRIBUTE_NODE:
194
244k
      precedence1 = 1; /* element is owner */
195
244k
      miscNode1 = node1;
196
244k
      node1 = node1->parent;
197
244k
      misc = 1;
198
244k
      break;
199
3.70M
  case XML_TEXT_NODE:
200
3.71M
  case XML_CDATA_SECTION_NODE:
201
3.86M
  case XML_COMMENT_NODE:
202
3.88M
  case XML_PI_NODE: {
203
3.88M
      miscNode1 = node1;
204
      /*
205
      * Find nearest element node.
206
      */
207
3.88M
      if (node1->prev != NULL) {
208
19.4M
    do {
209
19.4M
        node1 = node1->prev;
210
19.4M
        if (node1->type == XML_ELEMENT_NODE) {
211
2.10M
      precedence1 = 3; /* element in prev-sibl axis */
212
2.10M
      break;
213
2.10M
        }
214
17.3M
        if (node1->prev == NULL) {
215
199k
      precedence1 = 2; /* element is parent */
216
      /*
217
      * URGENT TODO: Are there any cases, where the
218
      * parent of such a node is not an element node?
219
      */
220
199k
      node1 = node1->parent;
221
199k
      break;
222
199k
        }
223
17.3M
    } while (1);
224
2.30M
      } else {
225
1.58M
    precedence1 = 2; /* element is parent */
226
1.58M
    node1 = node1->parent;
227
1.58M
      }
228
3.88M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
229
3.88M
    (0 <= (ptrdiff_t) node1->content)) {
230
    /*
231
    * Fallback for whatever case.
232
    */
233
3.88M
    node1 = miscNode1;
234
3.88M
    precedence1 = 0;
235
3.88M
      } else
236
0
    misc = 1;
237
3.88M
  }
238
0
      break;
239
0
  case XML_NAMESPACE_DECL:
240
      /*
241
      * TODO: why do we return 1 for namespace nodes?
242
      */
243
0
      return(1);
244
14.3k
  default:
245
14.3k
      break;
246
10.2M
    }
247
4.67M
    switch (node2->type) {
248
438k
  case XML_ELEMENT_NODE:
249
438k
      break;
250
489k
  case XML_ATTRIBUTE_NODE:
251
489k
      precedence2 = 1; /* element is owner */
252
489k
      miscNode2 = node2;
253
489k
      node2 = node2->parent;
254
489k
      misc = 1;
255
489k
      break;
256
3.57M
  case XML_TEXT_NODE:
257
3.58M
  case XML_CDATA_SECTION_NODE:
258
3.71M
  case XML_COMMENT_NODE:
259
3.73M
  case XML_PI_NODE: {
260
3.73M
      miscNode2 = node2;
261
3.73M
      if (node2->prev != NULL) {
262
19.9M
    do {
263
19.9M
        node2 = node2->prev;
264
19.9M
        if (node2->type == XML_ELEMENT_NODE) {
265
1.74M
      precedence2 = 3; /* element in prev-sibl axis */
266
1.74M
      break;
267
1.74M
        }
268
18.1M
        if (node2->prev == NULL) {
269
220k
      precedence2 = 2; /* element is parent */
270
220k
      node2 = node2->parent;
271
220k
      break;
272
220k
        }
273
18.1M
    } while (1);
274
1.96M
      } else {
275
1.77M
    precedence2 = 2; /* element is parent */
276
1.77M
    node2 = node2->parent;
277
1.77M
      }
278
3.73M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
279
3.73M
    (0 <= (ptrdiff_t) node2->content))
280
3.73M
      {
281
3.73M
    node2 = miscNode2;
282
3.73M
    precedence2 = 0;
283
3.73M
      } else
284
0
    misc = 1;
285
3.73M
  }
286
0
      break;
287
0
  case XML_NAMESPACE_DECL:
288
0
      return(1);
289
7.23k
  default:
290
7.23k
      break;
291
4.67M
    }
292
4.67M
    if (misc) {
293
539k
  if (node1 == node2) {
294
78.9k
      if (precedence1 == precedence2) {
295
    /*
296
    * The ugly case; but normally there aren't many
297
    * adjacent non-element nodes around.
298
    */
299
30.1k
    cur = miscNode2->prev;
300
30.3k
    while (cur != NULL) {
301
29.9k
        if (cur == miscNode1)
302
29.7k
      return(1);
303
223
        if (cur->type == XML_ELEMENT_NODE)
304
0
      return(-1);
305
223
        cur = cur->prev;
306
223
    }
307
360
    return (-1);
308
48.8k
      } else {
309
    /*
310
    * Evaluate based on higher precedence wrt to the element.
311
    * TODO: This assumes attributes are sorted before content.
312
    *   Is this 100% correct?
313
    */
314
48.8k
    if (precedence1 < precedence2)
315
45.8k
        return(1);
316
3.05k
    else
317
3.05k
        return(-1);
318
48.8k
      }
319
78.9k
  }
320
  /*
321
  * Special case: One of the helper-elements is contained by the other.
322
  * <foo>
323
  *   <node2>
324
  *     <node1>Text-1(precedence1 == 2)</node1>
325
  *   </node2>
326
  *   Text-6(precedence2 == 3)
327
  * </foo>
328
  */
329
460k
  if ((precedence2 == 3) && (precedence1 > 1)) {
330
0
      cur = node1->parent;
331
0
      while (cur) {
332
0
    if (cur == node2)
333
0
        return(1);
334
0
    cur = cur->parent;
335
0
      }
336
0
  }
337
460k
  if ((precedence1 == 3) && (precedence2 > 1)) {
338
0
      cur = node2->parent;
339
0
      while (cur) {
340
0
    if (cur == node1)
341
0
        return(-1);
342
0
    cur = cur->parent;
343
0
      }
344
0
  }
345
460k
    }
346
347
    /*
348
     * Speedup using document order if available.
349
     */
350
4.59M
    if ((node1->type == XML_ELEMENT_NODE) &&
351
4.59M
  (node2->type == XML_ELEMENT_NODE) &&
352
4.59M
  (0 > (ptrdiff_t) node1->content) &&
353
4.59M
  (0 > (ptrdiff_t) node2->content) &&
354
4.59M
  (node1->doc == node2->doc)) {
355
356
0
  l1 = -((ptrdiff_t) node1->content);
357
0
  l2 = -((ptrdiff_t) node2->content);
358
0
  if (l1 < l2)
359
0
      return(1);
360
0
  if (l1 > l2)
361
0
      return(-1);
362
0
    }
363
364
10.1M
turtle_comparison:
365
366
10.1M
    if (node1 == node2->prev)
367
1.54M
  return(1);
368
8.62M
    if (node1 == node2->next)
369
52.4k
  return(-1);
370
    /*
371
     * compute depth to root
372
     */
373
229M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
374
222M
  if (cur->parent == node1)
375
1.41M
      return(1);
376
220M
  depth2++;
377
220M
    }
378
7.15M
    root = cur;
379
186M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
380
179M
  if (cur->parent == node2)
381
318k
      return(-1);
382
179M
  depth1++;
383
179M
    }
384
    /*
385
     * Distinct document (or distinct entities :-( ) case.
386
     */
387
6.83M
    if (root != cur) {
388
0
  return(-2);
389
0
    }
390
    /*
391
     * get the nearest common ancestor.
392
     */
393
12.2M
    while (depth1 > depth2) {
394
5.45M
  depth1--;
395
5.45M
  node1 = node1->parent;
396
5.45M
    }
397
24.8M
    while (depth2 > depth1) {
398
18.0M
  depth2--;
399
18.0M
  node2 = node2->parent;
400
18.0M
    }
401
9.85M
    while (node1->parent != node2->parent) {
402
3.02M
  node1 = node1->parent;
403
3.02M
  node2 = node2->parent;
404
  /* should not happen but just in case ... */
405
3.02M
  if ((node1 == NULL) || (node2 == NULL))
406
0
      return(-2);
407
3.02M
    }
408
    /*
409
     * Find who's first.
410
     */
411
6.83M
    if (node1 == node2->prev)
412
1.04M
  return(1);
413
5.79M
    if (node1 == node2->next)
414
643k
  return(-1);
415
    /*
416
     * Speedup using document order if available.
417
     */
418
5.15M
    if ((node1->type == XML_ELEMENT_NODE) &&
419
5.15M
  (node2->type == XML_ELEMENT_NODE) &&
420
5.15M
  (0 > (ptrdiff_t) node1->content) &&
421
5.15M
  (0 > (ptrdiff_t) node2->content) &&
422
5.15M
  (node1->doc == node2->doc)) {
423
424
0
  l1 = -((ptrdiff_t) node1->content);
425
0
  l2 = -((ptrdiff_t) node2->content);
426
0
  if (l1 < l2)
427
0
      return(1);
428
0
  if (l1 > l2)
429
0
      return(-1);
430
0
    }
431
432
65.1M
    for (cur = node1->next;cur != NULL;cur = cur->next)
433
62.8M
  if (cur == node2)
434
2.85M
      return(1);
435
2.29M
    return(-1); /* assume there is no sibling list corruption */
436
5.15M
}
437
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
438
439
/*
440
 * Wrapper for the Timsort algorithm from timsort.h
441
 */
442
#ifdef WITH_TIM_SORT
443
#define SORT_NAME libxml_domnode
444
2.31M
#define SORT_TYPE xmlNodePtr
445
/**
446
 * wrap_cmp:
447
 * @x: a node
448
 * @y: another node
449
 *
450
 * Comparison function for the Timsort implementation
451
 *
452
 * Returns -2 in case of error -1 if first point < second point, 0 if
453
 *         it's the same node, +1 otherwise
454
 */
455
static
456
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
457
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
458
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
459
10.2M
    {
460
10.2M
        int res = xmlXPathCmpNodesExt(x, y);
461
10.2M
        return res == -2 ? res : -res;
462
10.2M
    }
463
#else
464
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
465
    {
466
        int res = xmlXPathCmpNodes(x, y);
467
        return res == -2 ? res : -res;
468
    }
469
#endif
470
10.2M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
471
#include "timsort.h"
472
#endif /* WITH_TIM_SORT */
473
474
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
475
476
/************************************************************************
477
 *                  *
478
 *      Floating point stuff        *
479
 *                  *
480
 ************************************************************************/
481
482
double xmlXPathNAN = 0.0;
483
double xmlXPathPINF = 0.0;
484
double xmlXPathNINF = 0.0;
485
486
/**
487
 * xmlXPathInit:
488
 *
489
 * DEPRECATED: This function will be made private. Call xmlInitParser to
490
 * initialize the library.
491
 *
492
 * Initialize the XPath environment
493
 */
494
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
495
void
496
9.77k
xmlXPathInit(void) {
497
9.77k
#if defined(NAN) && defined(INFINITY)
498
9.77k
    xmlXPathNAN = NAN;
499
9.77k
    xmlXPathPINF = INFINITY;
500
9.77k
    xmlXPathNINF = -INFINITY;
501
#else
502
    /* MSVC doesn't allow division by zero in constant expressions. */
503
    double zero = 0.0;
504
    xmlXPathNAN = 0.0 / zero;
505
    xmlXPathPINF = 1.0 / zero;
506
    xmlXPathNINF = -xmlXPathPINF;
507
#endif
508
9.77k
}
509
510
/**
511
 * xmlXPathIsNaN:
512
 * @val:  a double value
513
 *
514
 * Returns 1 if the value is a NaN, 0 otherwise
515
 */
516
int
517
1.04M
xmlXPathIsNaN(double val) {
518
1.04M
#ifdef isnan
519
1.04M
    return isnan(val);
520
#else
521
    return !(val == val);
522
#endif
523
1.04M
}
524
525
/**
526
 * xmlXPathIsInf:
527
 * @val:  a double value
528
 *
529
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
530
 */
531
int
532
41.1k
xmlXPathIsInf(double val) {
533
41.1k
#ifdef isinf
534
41.1k
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
535
#else
536
    if (val >= xmlXPathPINF)
537
        return 1;
538
    if (val <= -xmlXPathPINF)
539
        return -1;
540
    return 0;
541
#endif
542
41.1k
}
543
544
#endif /* SCHEMAS or XPATH */
545
546
#ifdef LIBXML_XPATH_ENABLED
547
548
/*
549
 * TODO: when compatibility allows remove all "fake node libxslt" strings
550
 *       the test should just be name[0] = ' '
551
 */
552
#ifdef DEBUG_XPATH_EXPRESSION
553
#define DEBUG_STEP
554
#define DEBUG_EXPR
555
#define DEBUG_EVAL_COUNTS
556
#endif
557
558
static xmlNs xmlXPathXMLNamespaceStruct = {
559
    NULL,
560
    XML_NAMESPACE_DECL,
561
    XML_XML_NAMESPACE,
562
    BAD_CAST "xml",
563
    NULL,
564
    NULL
565
};
566
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
567
#ifndef LIBXML_THREAD_ENABLED
568
/*
569
 * Optimizer is disabled only when threaded apps are detected while
570
 * the library ain't compiled for thread safety.
571
 */
572
static int xmlXPathDisableOptimizer = 0;
573
#endif
574
575
/************************************************************************
576
 *                  *
577
 *      Error handling routines       *
578
 *                  *
579
 ************************************************************************/
580
581
/**
582
 * XP_ERRORNULL:
583
 * @X:  the error code
584
 *
585
 * Macro to raise an XPath error and return NULL.
586
 */
587
#define XP_ERRORNULL(X)             \
588
8.04k
    { xmlXPathErr(ctxt, X); return(NULL); }
589
590
/*
591
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
592
 */
593
static const char* const xmlXPathErrorMessages[] = {
594
    "Ok\n",
595
    "Number encoding\n",
596
    "Unfinished literal\n",
597
    "Start of literal\n",
598
    "Expected $ for variable reference\n",
599
    "Undefined variable\n",
600
    "Invalid predicate\n",
601
    "Invalid expression\n",
602
    "Missing closing curly brace\n",
603
    "Unregistered function\n",
604
    "Invalid operand\n",
605
    "Invalid type\n",
606
    "Invalid number of arguments\n",
607
    "Invalid context size\n",
608
    "Invalid context position\n",
609
    "Memory allocation error\n",
610
    "Syntax error\n",
611
    "Resource error\n",
612
    "Sub resource error\n",
613
    "Undefined namespace prefix\n",
614
    "Encoding error\n",
615
    "Char out of XML range\n",
616
    "Invalid or incomplete context\n",
617
    "Stack usage error\n",
618
    "Forbidden variable\n",
619
    "Operation limit exceeded\n",
620
    "Recursion limit exceeded\n",
621
    "?? Unknown error ??\n" /* Must be last in the list! */
622
};
623
731k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
624
731k
       sizeof(xmlXPathErrorMessages[0])) - 1)
625
/**
626
 * xmlXPathErrMemory:
627
 * @ctxt:  an XPath context
628
 * @extra:  extra information
629
 *
630
 * Handle a redefinition of attribute error
631
 */
632
static void
633
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
634
0
{
635
0
    if (ctxt != NULL) {
636
0
        xmlResetError(&ctxt->lastError);
637
0
        if (extra) {
638
0
            xmlChar buf[200];
639
640
0
            xmlStrPrintf(buf, 200,
641
0
                         "Memory allocation failed : %s\n",
642
0
                         extra);
643
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
644
0
        } else {
645
0
            ctxt->lastError.message = (char *)
646
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
647
0
        }
648
0
        ctxt->lastError.domain = XML_FROM_XPATH;
649
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
650
0
  if (ctxt->error != NULL)
651
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
652
0
    } else {
653
0
        if (extra)
654
0
            __xmlRaiseError(NULL, NULL, NULL,
655
0
                            NULL, NULL, XML_FROM_XPATH,
656
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657
0
                            extra, NULL, NULL, 0, 0,
658
0
                            "Memory allocation failed : %s\n", extra);
659
0
        else
660
0
            __xmlRaiseError(NULL, NULL, NULL,
661
0
                            NULL, NULL, XML_FROM_XPATH,
662
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
663
0
                            NULL, NULL, NULL, 0, 0,
664
0
                            "Memory allocation failed\n");
665
0
    }
666
0
}
667
668
/**
669
 * xmlXPathPErrMemory:
670
 * @ctxt:  an XPath parser context
671
 * @extra:  extra information
672
 *
673
 * Handle a redefinition of attribute error
674
 */
675
static void
676
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
677
0
{
678
0
    if (ctxt == NULL)
679
0
  xmlXPathErrMemory(NULL, extra);
680
0
    else {
681
0
  ctxt->error = XPATH_MEMORY_ERROR;
682
0
  xmlXPathErrMemory(ctxt->context, extra);
683
0
    }
684
0
}
685
686
/**
687
 * xmlXPathErr:
688
 * @ctxt:  a XPath parser context
689
 * @error:  the error code
690
 *
691
 * Handle an XPath error
692
 */
693
void
694
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
695
731k
{
696
731k
    if ((error < 0) || (error > MAXERRNO))
697
0
  error = MAXERRNO;
698
731k
    if (ctxt == NULL) {
699
0
  __xmlRaiseError(NULL, NULL, NULL,
700
0
      NULL, NULL, XML_FROM_XPATH,
701
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702
0
      XML_ERR_ERROR, NULL, 0,
703
0
      NULL, NULL, NULL, 0, 0,
704
0
      "%s", xmlXPathErrorMessages[error]);
705
0
  return;
706
0
    }
707
731k
    ctxt->error = error;
708
731k
    if (ctxt->context == NULL) {
709
0
  __xmlRaiseError(NULL, NULL, NULL,
710
0
      NULL, NULL, XML_FROM_XPATH,
711
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712
0
      XML_ERR_ERROR, NULL, 0,
713
0
      (const char *) ctxt->base, NULL, NULL,
714
0
      ctxt->cur - ctxt->base, 0,
715
0
      "%s", xmlXPathErrorMessages[error]);
716
0
  return;
717
0
    }
718
719
    /* cleanup current last error */
720
731k
    xmlResetError(&ctxt->context->lastError);
721
722
731k
    ctxt->context->lastError.domain = XML_FROM_XPATH;
723
731k
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
724
731k
                           XPATH_EXPRESSION_OK;
725
731k
    ctxt->context->lastError.level = XML_ERR_ERROR;
726
731k
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
727
731k
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
728
731k
    ctxt->context->lastError.node = ctxt->context->debugNode;
729
731k
    if (ctxt->context->error != NULL) {
730
0
  ctxt->context->error(ctxt->context->userData,
731
0
                       &ctxt->context->lastError);
732
731k
    } else {
733
731k
  __xmlRaiseError(NULL, NULL, NULL,
734
731k
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
735
731k
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
736
731k
      XML_ERR_ERROR, NULL, 0,
737
731k
      (const char *) ctxt->base, NULL, NULL,
738
731k
      ctxt->cur - ctxt->base, 0,
739
731k
      "%s", xmlXPathErrorMessages[error]);
740
731k
    }
741
742
731k
}
743
744
/**
745
 * xmlXPatherror:
746
 * @ctxt:  the XPath Parser context
747
 * @file:  the file name
748
 * @line:  the line number
749
 * @no:  the error number
750
 *
751
 * Formats an error message.
752
 */
753
void
754
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
755
3.34k
              int line ATTRIBUTE_UNUSED, int no) {
756
3.34k
    xmlXPathErr(ctxt, no);
757
3.34k
}
758
759
/**
760
 * xmlXPathCheckOpLimit:
761
 * @ctxt:  the XPath Parser context
762
 * @opCount:  the number of operations to be added
763
 *
764
 * Adds opCount to the running total of operations and returns -1 if the
765
 * operation limit is exceeded. Returns 0 otherwise.
766
 */
767
static int
768
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
769
0
    xmlXPathContextPtr xpctxt = ctxt->context;
770
771
0
    if ((opCount > xpctxt->opLimit) ||
772
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
773
0
        xpctxt->opCount = xpctxt->opLimit;
774
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
775
0
        return(-1);
776
0
    }
777
778
0
    xpctxt->opCount += opCount;
779
0
    return(0);
780
0
}
781
782
#define OP_LIMIT_EXCEEDED(ctxt, n) \
783
38.9M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
784
785
/************************************************************************
786
 *                  *
787
 *      Utilities         *
788
 *                  *
789
 ************************************************************************/
790
791
/**
792
 * xsltPointerList:
793
 *
794
 * Pointer-list for various purposes.
795
 */
796
typedef struct _xmlPointerList xmlPointerList;
797
typedef xmlPointerList *xmlPointerListPtr;
798
struct _xmlPointerList {
799
    void **items;
800
    int number;
801
    int size;
802
};
803
/*
804
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
805
* and here, we should make the functions public.
806
*/
807
static int
808
xmlPointerListAddSize(xmlPointerListPtr list,
809
           void *item,
810
           int initialSize)
811
0
{
812
0
    if (list->items == NULL) {
813
0
  if (initialSize <= 0)
814
0
      initialSize = 1;
815
0
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
816
0
  if (list->items == NULL) {
817
0
      xmlXPathErrMemory(NULL,
818
0
    "xmlPointerListCreate: allocating item\n");
819
0
      return(-1);
820
0
  }
821
0
  list->number = 0;
822
0
  list->size = initialSize;
823
0
    } else if (list->size <= list->number) {
824
0
        if (list->size > 50000000) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListAddSize: re-allocating item\n");
827
0
            return(-1);
828
0
        }
829
0
  list->size *= 2;
830
0
  list->items = (void **) xmlRealloc(list->items,
831
0
      list->size * sizeof(void *));
832
0
  if (list->items == NULL) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
      list->size = 0;
836
0
      return(-1);
837
0
  }
838
0
    }
839
0
    list->items[list->number++] = item;
840
0
    return(0);
841
0
}
842
843
/**
844
 * xsltPointerListCreate:
845
 *
846
 * Creates an xsltPointerList structure.
847
 *
848
 * Returns a xsltPointerList structure or NULL in case of an error.
849
 */
850
static xmlPointerListPtr
851
xmlPointerListCreate(int initialSize)
852
0
{
853
0
    xmlPointerListPtr ret;
854
855
0
    ret = xmlMalloc(sizeof(xmlPointerList));
856
0
    if (ret == NULL) {
857
0
  xmlXPathErrMemory(NULL,
858
0
      "xmlPointerListCreate: allocating item\n");
859
0
  return (NULL);
860
0
    }
861
0
    memset(ret, 0, sizeof(xmlPointerList));
862
0
    if (initialSize > 0) {
863
0
  xmlPointerListAddSize(ret, NULL, initialSize);
864
0
  ret->number = 0;
865
0
    }
866
0
    return (ret);
867
0
}
868
869
/**
870
 * xsltPointerListFree:
871
 *
872
 * Frees the xsltPointerList structure. This does not free
873
 * the content of the list.
874
 */
875
static void
876
xmlPointerListFree(xmlPointerListPtr list)
877
0
{
878
0
    if (list == NULL)
879
0
  return;
880
0
    if (list->items != NULL)
881
0
  xmlFree(list->items);
882
0
    xmlFree(list);
883
0
}
884
885
/************************************************************************
886
 *                  *
887
 *      Parser Types          *
888
 *                  *
889
 ************************************************************************/
890
891
/*
892
 * Types are private:
893
 */
894
895
typedef enum {
896
    XPATH_OP_END=0,
897
    XPATH_OP_AND,
898
    XPATH_OP_OR,
899
    XPATH_OP_EQUAL,
900
    XPATH_OP_CMP,
901
    XPATH_OP_PLUS,
902
    XPATH_OP_MULT,
903
    XPATH_OP_UNION,
904
    XPATH_OP_ROOT,
905
    XPATH_OP_NODE,
906
    XPATH_OP_COLLECT,
907
    XPATH_OP_VALUE, /* 11 */
908
    XPATH_OP_VARIABLE,
909
    XPATH_OP_FUNCTION,
910
    XPATH_OP_ARG,
911
    XPATH_OP_PREDICATE,
912
    XPATH_OP_FILTER, /* 16 */
913
    XPATH_OP_SORT /* 17 */
914
#ifdef LIBXML_XPTR_LOCS_ENABLED
915
    ,XPATH_OP_RANGETO
916
#endif
917
} xmlXPathOp;
918
919
typedef enum {
920
    AXIS_ANCESTOR = 1,
921
    AXIS_ANCESTOR_OR_SELF,
922
    AXIS_ATTRIBUTE,
923
    AXIS_CHILD,
924
    AXIS_DESCENDANT,
925
    AXIS_DESCENDANT_OR_SELF,
926
    AXIS_FOLLOWING,
927
    AXIS_FOLLOWING_SIBLING,
928
    AXIS_NAMESPACE,
929
    AXIS_PARENT,
930
    AXIS_PRECEDING,
931
    AXIS_PRECEDING_SIBLING,
932
    AXIS_SELF
933
} xmlXPathAxisVal;
934
935
typedef enum {
936
    NODE_TEST_NONE = 0,
937
    NODE_TEST_TYPE = 1,
938
    NODE_TEST_PI = 2,
939
    NODE_TEST_ALL = 3,
940
    NODE_TEST_NS = 4,
941
    NODE_TEST_NAME = 5
942
} xmlXPathTestVal;
943
944
typedef enum {
945
    NODE_TYPE_NODE = 0,
946
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
947
    NODE_TYPE_TEXT = XML_TEXT_NODE,
948
    NODE_TYPE_PI = XML_PI_NODE
949
} xmlXPathTypeVal;
950
951
typedef struct _xmlXPathStepOp xmlXPathStepOp;
952
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
953
struct _xmlXPathStepOp {
954
    xmlXPathOp op;    /* The identifier of the operation */
955
    int ch1;      /* First child */
956
    int ch2;      /* Second child */
957
    int value;
958
    int value2;
959
    int value3;
960
    void *value4;
961
    void *value5;
962
    xmlXPathFunction cache;
963
    void *cacheURI;
964
};
965
966
struct _xmlXPathCompExpr {
967
    int nbStep;     /* Number of steps in this expression */
968
    int maxStep;    /* Maximum number of steps allocated */
969
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
970
    int last;     /* index of last step in expression */
971
    xmlChar *expr;    /* the expression being computed */
972
    xmlDictPtr dict;    /* the dictionary to use if any */
973
#ifdef DEBUG_EVAL_COUNTS
974
    int nb;
975
    xmlChar *string;
976
#endif
977
#ifdef XPATH_STREAMING
978
    xmlPatternPtr stream;
979
#endif
980
};
981
982
/************************************************************************
983
 *                  *
984
 *      Forward declarations        *
985
 *                  *
986
 ************************************************************************/
987
static void
988
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
989
static void
990
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
991
static int
992
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
993
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
994
static int
995
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
996
          xmlXPathStepOpPtr op,
997
          int isPredicate);
998
static void
999
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1000
1001
/************************************************************************
1002
 *                  *
1003
 *      Parser Type functions       *
1004
 *                  *
1005
 ************************************************************************/
1006
1007
/**
1008
 * xmlXPathNewCompExpr:
1009
 *
1010
 * Create a new Xpath component
1011
 *
1012
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1013
 */
1014
static xmlXPathCompExprPtr
1015
329k
xmlXPathNewCompExpr(void) {
1016
329k
    xmlXPathCompExprPtr cur;
1017
1018
329k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1019
329k
    if (cur == NULL) {
1020
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1021
0
  return(NULL);
1022
0
    }
1023
329k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1024
329k
    cur->maxStep = 10;
1025
329k
    cur->nbStep = 0;
1026
329k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1027
329k
                                     sizeof(xmlXPathStepOp));
1028
329k
    if (cur->steps == NULL) {
1029
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1030
0
  xmlFree(cur);
1031
0
  return(NULL);
1032
0
    }
1033
329k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1034
329k
    cur->last = -1;
1035
#ifdef DEBUG_EVAL_COUNTS
1036
    cur->nb = 0;
1037
#endif
1038
329k
    return(cur);
1039
329k
}
1040
1041
/**
1042
 * xmlXPathFreeCompExpr:
1043
 * @comp:  an XPATH comp
1044
 *
1045
 * Free up the memory allocated by @comp
1046
 */
1047
void
1048
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1049
329k
{
1050
329k
    xmlXPathStepOpPtr op;
1051
329k
    int i;
1052
1053
329k
    if (comp == NULL)
1054
0
        return;
1055
329k
    if (comp->dict == NULL) {
1056
3.79M
  for (i = 0; i < comp->nbStep; i++) {
1057
3.46M
      op = &comp->steps[i];
1058
3.46M
      if (op->value4 != NULL) {
1059
96.1k
    if (op->op == XPATH_OP_VALUE)
1060
74.6k
        xmlXPathFreeObject(op->value4);
1061
21.4k
    else
1062
21.4k
        xmlFree(op->value4);
1063
96.1k
      }
1064
3.46M
      if (op->value5 != NULL)
1065
338k
    xmlFree(op->value5);
1066
3.46M
  }
1067
329k
    } else {
1068
0
  for (i = 0; i < comp->nbStep; i++) {
1069
0
      op = &comp->steps[i];
1070
0
      if (op->value4 != NULL) {
1071
0
    if (op->op == XPATH_OP_VALUE)
1072
0
        xmlXPathFreeObject(op->value4);
1073
0
      }
1074
0
  }
1075
0
        xmlDictFree(comp->dict);
1076
0
    }
1077
329k
    if (comp->steps != NULL) {
1078
329k
        xmlFree(comp->steps);
1079
329k
    }
1080
#ifdef DEBUG_EVAL_COUNTS
1081
    if (comp->string != NULL) {
1082
        xmlFree(comp->string);
1083
    }
1084
#endif
1085
329k
#ifdef XPATH_STREAMING
1086
329k
    if (comp->stream != NULL) {
1087
626
        xmlFreePatternList(comp->stream);
1088
626
    }
1089
329k
#endif
1090
329k
    if (comp->expr != NULL) {
1091
0
        xmlFree(comp->expr);
1092
0
    }
1093
1094
329k
    xmlFree(comp);
1095
329k
}
1096
1097
/**
1098
 * xmlXPathCompExprAdd:
1099
 * @comp:  the compiled expression
1100
 * @ch1: first child index
1101
 * @ch2: second child index
1102
 * @op:  an op
1103
 * @value:  the first int value
1104
 * @value2:  the second int value
1105
 * @value3:  the third int value
1106
 * @value4:  the first string value
1107
 * @value5:  the second string value
1108
 *
1109
 * Add a step to an XPath Compiled Expression
1110
 *
1111
 * Returns -1 in case of failure, the index otherwise
1112
 */
1113
static int
1114
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1115
   xmlXPathOp op, int value,
1116
3.46M
   int value2, int value3, void *value4, void *value5) {
1117
3.46M
    xmlXPathCompExprPtr comp = ctxt->comp;
1118
3.46M
    if (comp->nbStep >= comp->maxStep) {
1119
82.6k
  xmlXPathStepOp *real;
1120
1121
82.6k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1122
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1123
0
      return(-1);
1124
0
        }
1125
82.6k
  comp->maxStep *= 2;
1126
82.6k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1127
82.6k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1128
82.6k
  if (real == NULL) {
1129
0
      comp->maxStep /= 2;
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
  }
1133
82.6k
  comp->steps = real;
1134
82.6k
    }
1135
3.46M
    comp->last = comp->nbStep;
1136
3.46M
    comp->steps[comp->nbStep].ch1 = ch1;
1137
3.46M
    comp->steps[comp->nbStep].ch2 = ch2;
1138
3.46M
    comp->steps[comp->nbStep].op = op;
1139
3.46M
    comp->steps[comp->nbStep].value = value;
1140
3.46M
    comp->steps[comp->nbStep].value2 = value2;
1141
3.46M
    comp->steps[comp->nbStep].value3 = value3;
1142
3.46M
    if ((comp->dict != NULL) &&
1143
3.46M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1144
0
   (op == XPATH_OP_COLLECT))) {
1145
0
        if (value4 != NULL) {
1146
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1147
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1148
0
      xmlFree(value4);
1149
0
  } else
1150
0
      comp->steps[comp->nbStep].value4 = NULL;
1151
0
        if (value5 != NULL) {
1152
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1153
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1154
0
      xmlFree(value5);
1155
0
  } else
1156
0
      comp->steps[comp->nbStep].value5 = NULL;
1157
3.46M
    } else {
1158
3.46M
  comp->steps[comp->nbStep].value4 = value4;
1159
3.46M
  comp->steps[comp->nbStep].value5 = value5;
1160
3.46M
    }
1161
3.46M
    comp->steps[comp->nbStep].cache = NULL;
1162
3.46M
    return(comp->nbStep++);
1163
3.46M
}
1164
1165
/**
1166
 * xmlXPathCompSwap:
1167
 * @comp:  the compiled expression
1168
 * @op: operation index
1169
 *
1170
 * Swaps 2 operations in the compiled expression
1171
 */
1172
static void
1173
895
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1174
895
    int tmp;
1175
1176
#ifndef LIBXML_THREAD_ENABLED
1177
    /*
1178
     * Since this manipulates possibly shared variables, this is
1179
     * disabled if one detects that the library is used in a multithreaded
1180
     * application
1181
     */
1182
    if (xmlXPathDisableOptimizer)
1183
  return;
1184
#endif
1185
1186
895
    tmp = op->ch1;
1187
895
    op->ch1 = op->ch2;
1188
895
    op->ch2 = tmp;
1189
895
}
1190
1191
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1192
821k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1193
821k
                  (op), (val), (val2), (val3), (val4), (val5))
1194
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1195
290k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1196
290k
                  (op), (val), (val2), (val3), (val4), (val5))
1197
1198
1.16M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1199
1.16M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1200
1201
199k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1202
199k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1203
1204
995k
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1205
995k
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1206
995k
      (val), (val2), 0 ,NULL ,NULL)
1207
1208
/************************************************************************
1209
 *                  *
1210
 *    XPath object cache structures       *
1211
 *                  *
1212
 ************************************************************************/
1213
1214
/* #define XP_DEFAULT_CACHE_ON */
1215
1216
539k
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1217
1218
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1219
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1220
struct _xmlXPathContextCache {
1221
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1222
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1223
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1224
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1225
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1226
    int maxNodeset;
1227
    int maxString;
1228
    int maxBoolean;
1229
    int maxNumber;
1230
    int maxMisc;
1231
#ifdef XP_DEBUG_OBJ_USAGE
1232
    int dbgCachedAll;
1233
    int dbgCachedNodeset;
1234
    int dbgCachedString;
1235
    int dbgCachedBool;
1236
    int dbgCachedNumber;
1237
    int dbgCachedPoint;
1238
    int dbgCachedRange;
1239
    int dbgCachedLocset;
1240
    int dbgCachedUsers;
1241
    int dbgCachedXSLTTree;
1242
    int dbgCachedUndefined;
1243
1244
1245
    int dbgReusedAll;
1246
    int dbgReusedNodeset;
1247
    int dbgReusedString;
1248
    int dbgReusedBool;
1249
    int dbgReusedNumber;
1250
    int dbgReusedPoint;
1251
    int dbgReusedRange;
1252
    int dbgReusedLocset;
1253
    int dbgReusedUsers;
1254
    int dbgReusedXSLTTree;
1255
    int dbgReusedUndefined;
1256
1257
#endif
1258
};
1259
1260
/************************************************************************
1261
 *                  *
1262
 *    Debugging related functions       *
1263
 *                  *
1264
 ************************************************************************/
1265
1266
#define STRANGE             \
1267
0
    xmlGenericError(xmlGenericErrorContext,       \
1268
0
      "Internal error at %s:%d\n",        \
1269
0
            __FILE__, __LINE__);
1270
1271
#ifdef LIBXML_DEBUG_ENABLED
1272
static void
1273
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1274
    int i;
1275
    char shift[100];
1276
1277
    for (i = 0;((i < depth) && (i < 25));i++)
1278
        shift[2 * i] = shift[2 * i + 1] = ' ';
1279
    shift[2 * i] = shift[2 * i + 1] = 0;
1280
    if (cur == NULL) {
1281
  fprintf(output, "%s", shift);
1282
  fprintf(output, "Node is NULL !\n");
1283
  return;
1284
1285
    }
1286
1287
    if ((cur->type == XML_DOCUMENT_NODE) ||
1288
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1289
  fprintf(output, "%s", shift);
1290
  fprintf(output, " /\n");
1291
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1292
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1293
    else
1294
  xmlDebugDumpOneNode(output, cur, depth);
1295
}
1296
static void
1297
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1298
    xmlNodePtr tmp;
1299
    int i;
1300
    char shift[100];
1301
1302
    for (i = 0;((i < depth) && (i < 25));i++)
1303
        shift[2 * i] = shift[2 * i + 1] = ' ';
1304
    shift[2 * i] = shift[2 * i + 1] = 0;
1305
    if (cur == NULL) {
1306
  fprintf(output, "%s", shift);
1307
  fprintf(output, "Node is NULL !\n");
1308
  return;
1309
1310
    }
1311
1312
    while (cur != NULL) {
1313
  tmp = cur;
1314
  cur = cur->next;
1315
  xmlDebugDumpOneNode(output, tmp, depth);
1316
    }
1317
}
1318
1319
static void
1320
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1321
    int i;
1322
    char shift[100];
1323
1324
    for (i = 0;((i < depth) && (i < 25));i++)
1325
        shift[2 * i] = shift[2 * i + 1] = ' ';
1326
    shift[2 * i] = shift[2 * i + 1] = 0;
1327
1328
    if (cur == NULL) {
1329
  fprintf(output, "%s", shift);
1330
  fprintf(output, "NodeSet is NULL !\n");
1331
  return;
1332
1333
    }
1334
1335
    if (cur != NULL) {
1336
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1337
  for (i = 0;i < cur->nodeNr;i++) {
1338
      fprintf(output, "%s", shift);
1339
      fprintf(output, "%d", i + 1);
1340
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1341
  }
1342
    }
1343
}
1344
1345
static void
1346
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1347
    int i;
1348
    char shift[100];
1349
1350
    for (i = 0;((i < depth) && (i < 25));i++)
1351
        shift[2 * i] = shift[2 * i + 1] = ' ';
1352
    shift[2 * i] = shift[2 * i + 1] = 0;
1353
1354
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1355
  fprintf(output, "%s", shift);
1356
  fprintf(output, "Value Tree is NULL !\n");
1357
  return;
1358
1359
    }
1360
1361
    fprintf(output, "%s", shift);
1362
    fprintf(output, "%d", i + 1);
1363
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1364
}
1365
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1366
static void
1367
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1368
    int i;
1369
    char shift[100];
1370
1371
    for (i = 0;((i < depth) && (i < 25));i++)
1372
        shift[2 * i] = shift[2 * i + 1] = ' ';
1373
    shift[2 * i] = shift[2 * i + 1] = 0;
1374
1375
    if (cur == NULL) {
1376
  fprintf(output, "%s", shift);
1377
  fprintf(output, "LocationSet is NULL !\n");
1378
  return;
1379
1380
    }
1381
1382
    for (i = 0;i < cur->locNr;i++) {
1383
  fprintf(output, "%s", shift);
1384
        fprintf(output, "%d : ", i + 1);
1385
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1386
    }
1387
}
1388
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1389
1390
/**
1391
 * xmlXPathDebugDumpObject:
1392
 * @output:  the FILE * to dump the output
1393
 * @cur:  the object to inspect
1394
 * @depth:  indentation level
1395
 *
1396
 * Dump the content of the object for debugging purposes
1397
 */
1398
void
1399
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1400
    int i;
1401
    char shift[100];
1402
1403
    if (output == NULL) return;
1404
1405
    for (i = 0;((i < depth) && (i < 25));i++)
1406
        shift[2 * i] = shift[2 * i + 1] = ' ';
1407
    shift[2 * i] = shift[2 * i + 1] = 0;
1408
1409
1410
    fprintf(output, "%s", shift);
1411
1412
    if (cur == NULL) {
1413
        fprintf(output, "Object is empty (NULL)\n");
1414
  return;
1415
    }
1416
    switch(cur->type) {
1417
        case XPATH_UNDEFINED:
1418
      fprintf(output, "Object is uninitialized\n");
1419
      break;
1420
        case XPATH_NODESET:
1421
      fprintf(output, "Object is a Node Set :\n");
1422
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1423
      break;
1424
  case XPATH_XSLT_TREE:
1425
      fprintf(output, "Object is an XSLT value tree :\n");
1426
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1427
      break;
1428
        case XPATH_BOOLEAN:
1429
      fprintf(output, "Object is a Boolean : ");
1430
      if (cur->boolval) fprintf(output, "true\n");
1431
      else fprintf(output, "false\n");
1432
      break;
1433
        case XPATH_NUMBER:
1434
      switch (xmlXPathIsInf(cur->floatval)) {
1435
      case 1:
1436
    fprintf(output, "Object is a number : Infinity\n");
1437
    break;
1438
      case -1:
1439
    fprintf(output, "Object is a number : -Infinity\n");
1440
    break;
1441
      default:
1442
    if (xmlXPathIsNaN(cur->floatval)) {
1443
        fprintf(output, "Object is a number : NaN\n");
1444
    } else if (cur->floatval == 0) {
1445
                    /* Omit sign for negative zero. */
1446
        fprintf(output, "Object is a number : 0\n");
1447
    } else {
1448
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1449
    }
1450
      }
1451
      break;
1452
        case XPATH_STRING:
1453
      fprintf(output, "Object is a string : ");
1454
      xmlDebugDumpString(output, cur->stringval);
1455
      fprintf(output, "\n");
1456
      break;
1457
#ifdef LIBXML_XPTR_LOCS_ENABLED
1458
  case XPATH_POINT:
1459
      fprintf(output, "Object is a point : index %d in node", cur->index);
1460
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1461
      fprintf(output, "\n");
1462
      break;
1463
  case XPATH_RANGE:
1464
      if ((cur->user2 == NULL) ||
1465
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1466
    fprintf(output, "Object is a collapsed range :\n");
1467
    fprintf(output, "%s", shift);
1468
    if (cur->index >= 0)
1469
        fprintf(output, "index %d in ", cur->index);
1470
    fprintf(output, "node\n");
1471
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1472
                    depth + 1);
1473
      } else  {
1474
    fprintf(output, "Object is a range :\n");
1475
    fprintf(output, "%s", shift);
1476
    fprintf(output, "From ");
1477
    if (cur->index >= 0)
1478
        fprintf(output, "index %d in ", cur->index);
1479
    fprintf(output, "node\n");
1480
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1481
                    depth + 1);
1482
    fprintf(output, "%s", shift);
1483
    fprintf(output, "To ");
1484
    if (cur->index2 >= 0)
1485
        fprintf(output, "index %d in ", cur->index2);
1486
    fprintf(output, "node\n");
1487
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1488
                    depth + 1);
1489
    fprintf(output, "\n");
1490
      }
1491
      break;
1492
  case XPATH_LOCATIONSET:
1493
      fprintf(output, "Object is a Location Set:\n");
1494
      xmlXPathDebugDumpLocationSet(output,
1495
        (xmlLocationSetPtr) cur->user, depth);
1496
      break;
1497
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1498
  case XPATH_USERS:
1499
      fprintf(output, "Object is user defined\n");
1500
      break;
1501
    }
1502
}
1503
1504
static void
1505
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1506
                       xmlXPathStepOpPtr op, int depth) {
1507
    int i;
1508
    char shift[100];
1509
1510
    for (i = 0;((i < depth) && (i < 25));i++)
1511
        shift[2 * i] = shift[2 * i + 1] = ' ';
1512
    shift[2 * i] = shift[2 * i + 1] = 0;
1513
1514
    fprintf(output, "%s", shift);
1515
    if (op == NULL) {
1516
  fprintf(output, "Step is NULL\n");
1517
  return;
1518
    }
1519
    switch (op->op) {
1520
        case XPATH_OP_END:
1521
      fprintf(output, "END"); break;
1522
        case XPATH_OP_AND:
1523
      fprintf(output, "AND"); break;
1524
        case XPATH_OP_OR:
1525
      fprintf(output, "OR"); break;
1526
        case XPATH_OP_EQUAL:
1527
       if (op->value)
1528
     fprintf(output, "EQUAL =");
1529
       else
1530
     fprintf(output, "EQUAL !=");
1531
       break;
1532
        case XPATH_OP_CMP:
1533
       if (op->value)
1534
     fprintf(output, "CMP <");
1535
       else
1536
     fprintf(output, "CMP >");
1537
       if (!op->value2)
1538
     fprintf(output, "=");
1539
       break;
1540
        case XPATH_OP_PLUS:
1541
       if (op->value == 0)
1542
     fprintf(output, "PLUS -");
1543
       else if (op->value == 1)
1544
     fprintf(output, "PLUS +");
1545
       else if (op->value == 2)
1546
     fprintf(output, "PLUS unary -");
1547
       else if (op->value == 3)
1548
     fprintf(output, "PLUS unary - -");
1549
       break;
1550
        case XPATH_OP_MULT:
1551
       if (op->value == 0)
1552
     fprintf(output, "MULT *");
1553
       else if (op->value == 1)
1554
     fprintf(output, "MULT div");
1555
       else
1556
     fprintf(output, "MULT mod");
1557
       break;
1558
        case XPATH_OP_UNION:
1559
       fprintf(output, "UNION"); break;
1560
        case XPATH_OP_ROOT:
1561
       fprintf(output, "ROOT"); break;
1562
        case XPATH_OP_NODE:
1563
       fprintf(output, "NODE"); break;
1564
        case XPATH_OP_SORT:
1565
       fprintf(output, "SORT"); break;
1566
        case XPATH_OP_COLLECT: {
1567
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1568
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1569
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1570
      const xmlChar *prefix = op->value4;
1571
      const xmlChar *name = op->value5;
1572
1573
      fprintf(output, "COLLECT ");
1574
      switch (axis) {
1575
    case AXIS_ANCESTOR:
1576
        fprintf(output, " 'ancestors' "); break;
1577
    case AXIS_ANCESTOR_OR_SELF:
1578
        fprintf(output, " 'ancestors-or-self' "); break;
1579
    case AXIS_ATTRIBUTE:
1580
        fprintf(output, " 'attributes' "); break;
1581
    case AXIS_CHILD:
1582
        fprintf(output, " 'child' "); break;
1583
    case AXIS_DESCENDANT:
1584
        fprintf(output, " 'descendant' "); break;
1585
    case AXIS_DESCENDANT_OR_SELF:
1586
        fprintf(output, " 'descendant-or-self' "); break;
1587
    case AXIS_FOLLOWING:
1588
        fprintf(output, " 'following' "); break;
1589
    case AXIS_FOLLOWING_SIBLING:
1590
        fprintf(output, " 'following-siblings' "); break;
1591
    case AXIS_NAMESPACE:
1592
        fprintf(output, " 'namespace' "); break;
1593
    case AXIS_PARENT:
1594
        fprintf(output, " 'parent' "); break;
1595
    case AXIS_PRECEDING:
1596
        fprintf(output, " 'preceding' "); break;
1597
    case AXIS_PRECEDING_SIBLING:
1598
        fprintf(output, " 'preceding-sibling' "); break;
1599
    case AXIS_SELF:
1600
        fprintf(output, " 'self' "); break;
1601
      }
1602
      switch (test) {
1603
                case NODE_TEST_NONE:
1604
        fprintf(output, "'none' "); break;
1605
                case NODE_TEST_TYPE:
1606
        fprintf(output, "'type' "); break;
1607
                case NODE_TEST_PI:
1608
        fprintf(output, "'PI' "); break;
1609
                case NODE_TEST_ALL:
1610
        fprintf(output, "'all' "); break;
1611
                case NODE_TEST_NS:
1612
        fprintf(output, "'namespace' "); break;
1613
                case NODE_TEST_NAME:
1614
        fprintf(output, "'name' "); break;
1615
      }
1616
      switch (type) {
1617
                case NODE_TYPE_NODE:
1618
        fprintf(output, "'node' "); break;
1619
                case NODE_TYPE_COMMENT:
1620
        fprintf(output, "'comment' "); break;
1621
                case NODE_TYPE_TEXT:
1622
        fprintf(output, "'text' "); break;
1623
                case NODE_TYPE_PI:
1624
        fprintf(output, "'PI' "); break;
1625
      }
1626
      if (prefix != NULL)
1627
    fprintf(output, "%s:", prefix);
1628
      if (name != NULL)
1629
    fprintf(output, "%s", (const char *) name);
1630
      break;
1631
1632
        }
1633
  case XPATH_OP_VALUE: {
1634
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1635
1636
      fprintf(output, "ELEM ");
1637
      xmlXPathDebugDumpObject(output, object, 0);
1638
      goto finish;
1639
  }
1640
  case XPATH_OP_VARIABLE: {
1641
      const xmlChar *prefix = op->value5;
1642
      const xmlChar *name = op->value4;
1643
1644
      if (prefix != NULL)
1645
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1646
      else
1647
    fprintf(output, "VARIABLE %s", name);
1648
      break;
1649
  }
1650
  case XPATH_OP_FUNCTION: {
1651
      int nbargs = op->value;
1652
      const xmlChar *prefix = op->value5;
1653
      const xmlChar *name = op->value4;
1654
1655
      if (prefix != NULL)
1656
    fprintf(output, "FUNCTION %s:%s(%d args)",
1657
      prefix, name, nbargs);
1658
      else
1659
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1660
      break;
1661
  }
1662
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1663
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1664
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1665
#ifdef LIBXML_XPTR_LOCS_ENABLED
1666
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1667
#endif
1668
  default:
1669
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1670
    }
1671
    fprintf(output, "\n");
1672
finish:
1673
    if (op->ch1 >= 0)
1674
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1675
    if (op->ch2 >= 0)
1676
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1677
}
1678
1679
/**
1680
 * xmlXPathDebugDumpCompExpr:
1681
 * @output:  the FILE * for the output
1682
 * @comp:  the precompiled XPath expression
1683
 * @depth:  the indentation level.
1684
 *
1685
 * Dumps the tree of the compiled XPath expression.
1686
 */
1687
void
1688
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1689
                    int depth) {
1690
    int i;
1691
    char shift[100];
1692
1693
    if ((output == NULL) || (comp == NULL)) return;
1694
1695
    for (i = 0;((i < depth) && (i < 25));i++)
1696
        shift[2 * i] = shift[2 * i + 1] = ' ';
1697
    shift[2 * i] = shift[2 * i + 1] = 0;
1698
1699
    fprintf(output, "%s", shift);
1700
1701
#ifdef XPATH_STREAMING
1702
    if (comp->stream) {
1703
        fprintf(output, "Streaming Expression\n");
1704
    } else
1705
#endif
1706
    {
1707
        fprintf(output, "Compiled Expression : %d elements\n",
1708
                comp->nbStep);
1709
        i = comp->last;
1710
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1711
    }
1712
}
1713
1714
#ifdef XP_DEBUG_OBJ_USAGE
1715
1716
/*
1717
* XPath object usage related debugging variables.
1718
*/
1719
static int xmlXPathDebugObjCounterUndefined = 0;
1720
static int xmlXPathDebugObjCounterNodeset = 0;
1721
static int xmlXPathDebugObjCounterBool = 0;
1722
static int xmlXPathDebugObjCounterNumber = 0;
1723
static int xmlXPathDebugObjCounterString = 0;
1724
static int xmlXPathDebugObjCounterPoint = 0;
1725
static int xmlXPathDebugObjCounterRange = 0;
1726
static int xmlXPathDebugObjCounterLocset = 0;
1727
static int xmlXPathDebugObjCounterUsers = 0;
1728
static int xmlXPathDebugObjCounterXSLTTree = 0;
1729
static int xmlXPathDebugObjCounterAll = 0;
1730
1731
static int xmlXPathDebugObjTotalUndefined = 0;
1732
static int xmlXPathDebugObjTotalNodeset = 0;
1733
static int xmlXPathDebugObjTotalBool = 0;
1734
static int xmlXPathDebugObjTotalNumber = 0;
1735
static int xmlXPathDebugObjTotalString = 0;
1736
static int xmlXPathDebugObjTotalPoint = 0;
1737
static int xmlXPathDebugObjTotalRange = 0;
1738
static int xmlXPathDebugObjTotalLocset = 0;
1739
static int xmlXPathDebugObjTotalUsers = 0;
1740
static int xmlXPathDebugObjTotalXSLTTree = 0;
1741
static int xmlXPathDebugObjTotalAll = 0;
1742
1743
static int xmlXPathDebugObjMaxUndefined = 0;
1744
static int xmlXPathDebugObjMaxNodeset = 0;
1745
static int xmlXPathDebugObjMaxBool = 0;
1746
static int xmlXPathDebugObjMaxNumber = 0;
1747
static int xmlXPathDebugObjMaxString = 0;
1748
static int xmlXPathDebugObjMaxPoint = 0;
1749
static int xmlXPathDebugObjMaxRange = 0;
1750
static int xmlXPathDebugObjMaxLocset = 0;
1751
static int xmlXPathDebugObjMaxUsers = 0;
1752
static int xmlXPathDebugObjMaxXSLTTree = 0;
1753
static int xmlXPathDebugObjMaxAll = 0;
1754
1755
static void
1756
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1757
{
1758
    if (ctxt != NULL) {
1759
  if (ctxt->cache != NULL) {
1760
      xmlXPathContextCachePtr cache =
1761
    (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
      cache->dbgCachedAll = 0;
1764
      cache->dbgCachedNodeset = 0;
1765
      cache->dbgCachedString = 0;
1766
      cache->dbgCachedBool = 0;
1767
      cache->dbgCachedNumber = 0;
1768
      cache->dbgCachedPoint = 0;
1769
      cache->dbgCachedRange = 0;
1770
      cache->dbgCachedLocset = 0;
1771
      cache->dbgCachedUsers = 0;
1772
      cache->dbgCachedXSLTTree = 0;
1773
      cache->dbgCachedUndefined = 0;
1774
1775
      cache->dbgReusedAll = 0;
1776
      cache->dbgReusedNodeset = 0;
1777
      cache->dbgReusedString = 0;
1778
      cache->dbgReusedBool = 0;
1779
      cache->dbgReusedNumber = 0;
1780
      cache->dbgReusedPoint = 0;
1781
      cache->dbgReusedRange = 0;
1782
      cache->dbgReusedLocset = 0;
1783
      cache->dbgReusedUsers = 0;
1784
      cache->dbgReusedXSLTTree = 0;
1785
      cache->dbgReusedUndefined = 0;
1786
  }
1787
    }
1788
1789
    xmlXPathDebugObjCounterUndefined = 0;
1790
    xmlXPathDebugObjCounterNodeset = 0;
1791
    xmlXPathDebugObjCounterBool = 0;
1792
    xmlXPathDebugObjCounterNumber = 0;
1793
    xmlXPathDebugObjCounterString = 0;
1794
    xmlXPathDebugObjCounterPoint = 0;
1795
    xmlXPathDebugObjCounterRange = 0;
1796
    xmlXPathDebugObjCounterLocset = 0;
1797
    xmlXPathDebugObjCounterUsers = 0;
1798
    xmlXPathDebugObjCounterXSLTTree = 0;
1799
    xmlXPathDebugObjCounterAll = 0;
1800
1801
    xmlXPathDebugObjTotalUndefined = 0;
1802
    xmlXPathDebugObjTotalNodeset = 0;
1803
    xmlXPathDebugObjTotalBool = 0;
1804
    xmlXPathDebugObjTotalNumber = 0;
1805
    xmlXPathDebugObjTotalString = 0;
1806
    xmlXPathDebugObjTotalPoint = 0;
1807
    xmlXPathDebugObjTotalRange = 0;
1808
    xmlXPathDebugObjTotalLocset = 0;
1809
    xmlXPathDebugObjTotalUsers = 0;
1810
    xmlXPathDebugObjTotalXSLTTree = 0;
1811
    xmlXPathDebugObjTotalAll = 0;
1812
1813
    xmlXPathDebugObjMaxUndefined = 0;
1814
    xmlXPathDebugObjMaxNodeset = 0;
1815
    xmlXPathDebugObjMaxBool = 0;
1816
    xmlXPathDebugObjMaxNumber = 0;
1817
    xmlXPathDebugObjMaxString = 0;
1818
    xmlXPathDebugObjMaxPoint = 0;
1819
    xmlXPathDebugObjMaxRange = 0;
1820
    xmlXPathDebugObjMaxLocset = 0;
1821
    xmlXPathDebugObjMaxUsers = 0;
1822
    xmlXPathDebugObjMaxXSLTTree = 0;
1823
    xmlXPathDebugObjMaxAll = 0;
1824
1825
}
1826
1827
static void
1828
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1829
            xmlXPathObjectType objType)
1830
{
1831
    int isCached = 0;
1832
1833
    if (ctxt != NULL) {
1834
  if (ctxt->cache != NULL) {
1835
      xmlXPathContextCachePtr cache =
1836
    (xmlXPathContextCachePtr) ctxt->cache;
1837
1838
      isCached = 1;
1839
1840
      cache->dbgReusedAll++;
1841
      switch (objType) {
1842
    case XPATH_UNDEFINED:
1843
        cache->dbgReusedUndefined++;
1844
        break;
1845
    case XPATH_NODESET:
1846
        cache->dbgReusedNodeset++;
1847
        break;
1848
    case XPATH_BOOLEAN:
1849
        cache->dbgReusedBool++;
1850
        break;
1851
    case XPATH_NUMBER:
1852
        cache->dbgReusedNumber++;
1853
        break;
1854
    case XPATH_STRING:
1855
        cache->dbgReusedString++;
1856
        break;
1857
#ifdef LIBXML_XPTR_LOCS_ENABLED
1858
    case XPATH_POINT:
1859
        cache->dbgReusedPoint++;
1860
        break;
1861
    case XPATH_RANGE:
1862
        cache->dbgReusedRange++;
1863
        break;
1864
    case XPATH_LOCATIONSET:
1865
        cache->dbgReusedLocset++;
1866
        break;
1867
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1868
    case XPATH_USERS:
1869
        cache->dbgReusedUsers++;
1870
        break;
1871
    case XPATH_XSLT_TREE:
1872
        cache->dbgReusedXSLTTree++;
1873
        break;
1874
    default:
1875
        break;
1876
      }
1877
  }
1878
    }
1879
1880
    switch (objType) {
1881
  case XPATH_UNDEFINED:
1882
      if (! isCached)
1883
    xmlXPathDebugObjTotalUndefined++;
1884
      xmlXPathDebugObjCounterUndefined++;
1885
      if (xmlXPathDebugObjCounterUndefined >
1886
    xmlXPathDebugObjMaxUndefined)
1887
    xmlXPathDebugObjMaxUndefined =
1888
        xmlXPathDebugObjCounterUndefined;
1889
      break;
1890
  case XPATH_NODESET:
1891
      if (! isCached)
1892
    xmlXPathDebugObjTotalNodeset++;
1893
      xmlXPathDebugObjCounterNodeset++;
1894
      if (xmlXPathDebugObjCounterNodeset >
1895
    xmlXPathDebugObjMaxNodeset)
1896
    xmlXPathDebugObjMaxNodeset =
1897
        xmlXPathDebugObjCounterNodeset;
1898
      break;
1899
  case XPATH_BOOLEAN:
1900
      if (! isCached)
1901
    xmlXPathDebugObjTotalBool++;
1902
      xmlXPathDebugObjCounterBool++;
1903
      if (xmlXPathDebugObjCounterBool >
1904
    xmlXPathDebugObjMaxBool)
1905
    xmlXPathDebugObjMaxBool =
1906
        xmlXPathDebugObjCounterBool;
1907
      break;
1908
  case XPATH_NUMBER:
1909
      if (! isCached)
1910
    xmlXPathDebugObjTotalNumber++;
1911
      xmlXPathDebugObjCounterNumber++;
1912
      if (xmlXPathDebugObjCounterNumber >
1913
    xmlXPathDebugObjMaxNumber)
1914
    xmlXPathDebugObjMaxNumber =
1915
        xmlXPathDebugObjCounterNumber;
1916
      break;
1917
  case XPATH_STRING:
1918
      if (! isCached)
1919
    xmlXPathDebugObjTotalString++;
1920
      xmlXPathDebugObjCounterString++;
1921
      if (xmlXPathDebugObjCounterString >
1922
    xmlXPathDebugObjMaxString)
1923
    xmlXPathDebugObjMaxString =
1924
        xmlXPathDebugObjCounterString;
1925
      break;
1926
#ifdef LIBXML_XPTR_LOCS_ENABLED
1927
  case XPATH_POINT:
1928
      if (! isCached)
1929
    xmlXPathDebugObjTotalPoint++;
1930
      xmlXPathDebugObjCounterPoint++;
1931
      if (xmlXPathDebugObjCounterPoint >
1932
    xmlXPathDebugObjMaxPoint)
1933
    xmlXPathDebugObjMaxPoint =
1934
        xmlXPathDebugObjCounterPoint;
1935
      break;
1936
  case XPATH_RANGE:
1937
      if (! isCached)
1938
    xmlXPathDebugObjTotalRange++;
1939
      xmlXPathDebugObjCounterRange++;
1940
      if (xmlXPathDebugObjCounterRange >
1941
    xmlXPathDebugObjMaxRange)
1942
    xmlXPathDebugObjMaxRange =
1943
        xmlXPathDebugObjCounterRange;
1944
      break;
1945
  case XPATH_LOCATIONSET:
1946
      if (! isCached)
1947
    xmlXPathDebugObjTotalLocset++;
1948
      xmlXPathDebugObjCounterLocset++;
1949
      if (xmlXPathDebugObjCounterLocset >
1950
    xmlXPathDebugObjMaxLocset)
1951
    xmlXPathDebugObjMaxLocset =
1952
        xmlXPathDebugObjCounterLocset;
1953
      break;
1954
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1955
  case XPATH_USERS:
1956
      if (! isCached)
1957
    xmlXPathDebugObjTotalUsers++;
1958
      xmlXPathDebugObjCounterUsers++;
1959
      if (xmlXPathDebugObjCounterUsers >
1960
    xmlXPathDebugObjMaxUsers)
1961
    xmlXPathDebugObjMaxUsers =
1962
        xmlXPathDebugObjCounterUsers;
1963
      break;
1964
  case XPATH_XSLT_TREE:
1965
      if (! isCached)
1966
    xmlXPathDebugObjTotalXSLTTree++;
1967
      xmlXPathDebugObjCounterXSLTTree++;
1968
      if (xmlXPathDebugObjCounterXSLTTree >
1969
    xmlXPathDebugObjMaxXSLTTree)
1970
    xmlXPathDebugObjMaxXSLTTree =
1971
        xmlXPathDebugObjCounterXSLTTree;
1972
      break;
1973
  default:
1974
      break;
1975
    }
1976
    if (! isCached)
1977
  xmlXPathDebugObjTotalAll++;
1978
    xmlXPathDebugObjCounterAll++;
1979
    if (xmlXPathDebugObjCounterAll >
1980
  xmlXPathDebugObjMaxAll)
1981
  xmlXPathDebugObjMaxAll =
1982
      xmlXPathDebugObjCounterAll;
1983
}
1984
1985
static void
1986
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1987
            xmlXPathObjectType objType)
1988
{
1989
    int isCached = 0;
1990
1991
    if (ctxt != NULL) {
1992
  if (ctxt->cache != NULL) {
1993
      xmlXPathContextCachePtr cache =
1994
    (xmlXPathContextCachePtr) ctxt->cache;
1995
1996
      isCached = 1;
1997
1998
      cache->dbgCachedAll++;
1999
      switch (objType) {
2000
    case XPATH_UNDEFINED:
2001
        cache->dbgCachedUndefined++;
2002
        break;
2003
    case XPATH_NODESET:
2004
        cache->dbgCachedNodeset++;
2005
        break;
2006
    case XPATH_BOOLEAN:
2007
        cache->dbgCachedBool++;
2008
        break;
2009
    case XPATH_NUMBER:
2010
        cache->dbgCachedNumber++;
2011
        break;
2012
    case XPATH_STRING:
2013
        cache->dbgCachedString++;
2014
        break;
2015
#ifdef LIBXML_XPTR_LOCS_ENABLED
2016
    case XPATH_POINT:
2017
        cache->dbgCachedPoint++;
2018
        break;
2019
    case XPATH_RANGE:
2020
        cache->dbgCachedRange++;
2021
        break;
2022
    case XPATH_LOCATIONSET:
2023
        cache->dbgCachedLocset++;
2024
        break;
2025
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2026
    case XPATH_USERS:
2027
        cache->dbgCachedUsers++;
2028
        break;
2029
    case XPATH_XSLT_TREE:
2030
        cache->dbgCachedXSLTTree++;
2031
        break;
2032
    default:
2033
        break;
2034
      }
2035
2036
  }
2037
    }
2038
    switch (objType) {
2039
  case XPATH_UNDEFINED:
2040
      xmlXPathDebugObjCounterUndefined--;
2041
      break;
2042
  case XPATH_NODESET:
2043
      xmlXPathDebugObjCounterNodeset--;
2044
      break;
2045
  case XPATH_BOOLEAN:
2046
      xmlXPathDebugObjCounterBool--;
2047
      break;
2048
  case XPATH_NUMBER:
2049
      xmlXPathDebugObjCounterNumber--;
2050
      break;
2051
  case XPATH_STRING:
2052
      xmlXPathDebugObjCounterString--;
2053
      break;
2054
#ifdef LIBXML_XPTR_LOCS_ENABLED
2055
  case XPATH_POINT:
2056
      xmlXPathDebugObjCounterPoint--;
2057
      break;
2058
  case XPATH_RANGE:
2059
      xmlXPathDebugObjCounterRange--;
2060
      break;
2061
  case XPATH_LOCATIONSET:
2062
      xmlXPathDebugObjCounterLocset--;
2063
      break;
2064
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2065
  case XPATH_USERS:
2066
      xmlXPathDebugObjCounterUsers--;
2067
      break;
2068
  case XPATH_XSLT_TREE:
2069
      xmlXPathDebugObjCounterXSLTTree--;
2070
      break;
2071
  default:
2072
      break;
2073
    }
2074
    xmlXPathDebugObjCounterAll--;
2075
}
2076
2077
static void
2078
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2079
{
2080
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2081
  reqXSLTTree, reqUndefined;
2082
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2083
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2084
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2085
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2086
    int leftObjs = xmlXPathDebugObjCounterAll;
2087
2088
    reqAll = xmlXPathDebugObjTotalAll;
2089
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2090
    reqString = xmlXPathDebugObjTotalString;
2091
    reqBool = xmlXPathDebugObjTotalBool;
2092
    reqNumber = xmlXPathDebugObjTotalNumber;
2093
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2094
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2095
2096
    printf("# XPath object usage:\n");
2097
2098
    if (ctxt != NULL) {
2099
  if (ctxt->cache != NULL) {
2100
      xmlXPathContextCachePtr cache =
2101
    (xmlXPathContextCachePtr) ctxt->cache;
2102
2103
      reAll = cache->dbgReusedAll;
2104
      reqAll += reAll;
2105
      reNodeset = cache->dbgReusedNodeset;
2106
      reqNodeset += reNodeset;
2107
      reString = cache->dbgReusedString;
2108
      reqString += reString;
2109
      reBool = cache->dbgReusedBool;
2110
      reqBool += reBool;
2111
      reNumber = cache->dbgReusedNumber;
2112
      reqNumber += reNumber;
2113
      reXSLTTree = cache->dbgReusedXSLTTree;
2114
      reqXSLTTree += reXSLTTree;
2115
      reUndefined = cache->dbgReusedUndefined;
2116
      reqUndefined += reUndefined;
2117
2118
      caAll = cache->dbgCachedAll;
2119
      caBool = cache->dbgCachedBool;
2120
      caNodeset = cache->dbgCachedNodeset;
2121
      caString = cache->dbgCachedString;
2122
      caNumber = cache->dbgCachedNumber;
2123
      caXSLTTree = cache->dbgCachedXSLTTree;
2124
      caUndefined = cache->dbgCachedUndefined;
2125
2126
      if (cache->nodesetObjs)
2127
    leftObjs -= cache->nodesetObjs->number;
2128
      if (cache->stringObjs)
2129
    leftObjs -= cache->stringObjs->number;
2130
      if (cache->booleanObjs)
2131
    leftObjs -= cache->booleanObjs->number;
2132
      if (cache->numberObjs)
2133
    leftObjs -= cache->numberObjs->number;
2134
      if (cache->miscObjs)
2135
    leftObjs -= cache->miscObjs->number;
2136
  }
2137
    }
2138
2139
    printf("# all\n");
2140
    printf("#   total  : %d\n", reqAll);
2141
    printf("#   left  : %d\n", leftObjs);
2142
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2143
    printf("#   reused : %d\n", reAll);
2144
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2145
2146
    printf("# node-sets\n");
2147
    printf("#   total  : %d\n", reqNodeset);
2148
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2149
    printf("#   reused : %d\n", reNodeset);
2150
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2151
2152
    printf("# strings\n");
2153
    printf("#   total  : %d\n", reqString);
2154
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2155
    printf("#   reused : %d\n", reString);
2156
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2157
2158
    printf("# booleans\n");
2159
    printf("#   total  : %d\n", reqBool);
2160
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2161
    printf("#   reused : %d\n", reBool);
2162
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2163
2164
    printf("# numbers\n");
2165
    printf("#   total  : %d\n", reqNumber);
2166
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2167
    printf("#   reused : %d\n", reNumber);
2168
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2169
2170
    printf("# XSLT result tree fragments\n");
2171
    printf("#   total  : %d\n", reqXSLTTree);
2172
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2173
    printf("#   reused : %d\n", reXSLTTree);
2174
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2175
2176
    printf("# undefined\n");
2177
    printf("#   total  : %d\n", reqUndefined);
2178
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2179
    printf("#   reused : %d\n", reUndefined);
2180
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2181
2182
}
2183
2184
#endif /* XP_DEBUG_OBJ_USAGE */
2185
2186
#endif /* LIBXML_DEBUG_ENABLED */
2187
2188
/************************************************************************
2189
 *                  *
2190
 *      XPath object caching        *
2191
 *                  *
2192
 ************************************************************************/
2193
2194
/**
2195
 * xmlXPathNewCache:
2196
 *
2197
 * Create a new object cache
2198
 *
2199
 * Returns the xmlXPathCache just allocated.
2200
 */
2201
static xmlXPathContextCachePtr
2202
xmlXPathNewCache(void)
2203
0
{
2204
0
    xmlXPathContextCachePtr ret;
2205
2206
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2207
0
    if (ret == NULL) {
2208
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2209
0
  return(NULL);
2210
0
    }
2211
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2212
0
    ret->maxNodeset = 100;
2213
0
    ret->maxString = 100;
2214
0
    ret->maxBoolean = 100;
2215
0
    ret->maxNumber = 100;
2216
0
    ret->maxMisc = 100;
2217
0
    return(ret);
2218
0
}
2219
2220
static void
2221
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2222
0
{
2223
0
    int i;
2224
0
    xmlXPathObjectPtr obj;
2225
2226
0
    if (list == NULL)
2227
0
  return;
2228
2229
0
    for (i = 0; i < list->number; i++) {
2230
0
  obj = list->items[i];
2231
  /*
2232
  * Note that it is already assured that we don't need to
2233
  * look out for namespace nodes in the node-set.
2234
  */
2235
0
  if (obj->nodesetval != NULL) {
2236
0
      if (obj->nodesetval->nodeTab != NULL)
2237
0
    xmlFree(obj->nodesetval->nodeTab);
2238
0
      xmlFree(obj->nodesetval);
2239
0
  }
2240
0
  xmlFree(obj);
2241
#ifdef XP_DEBUG_OBJ_USAGE
2242
  xmlXPathDebugObjCounterAll--;
2243
#endif
2244
0
    }
2245
0
    xmlPointerListFree(list);
2246
0
}
2247
2248
static void
2249
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2250
0
{
2251
0
    if (cache == NULL)
2252
0
  return;
2253
0
    if (cache->nodesetObjs)
2254
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2255
0
    if (cache->stringObjs)
2256
0
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2257
0
    if (cache->booleanObjs)
2258
0
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2259
0
    if (cache->numberObjs)
2260
0
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2261
0
    if (cache->miscObjs)
2262
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2263
0
    xmlFree(cache);
2264
0
}
2265
2266
/**
2267
 * xmlXPathContextSetCache:
2268
 *
2269
 * @ctxt:  the XPath context
2270
 * @active: enables/disables (creates/frees) the cache
2271
 * @value: a value with semantics dependent on @options
2272
 * @options: options (currently only the value 0 is used)
2273
 *
2274
 * Creates/frees an object cache on the XPath context.
2275
 * If activates XPath objects (xmlXPathObject) will be cached internally
2276
 * to be reused.
2277
 * @options:
2278
 *   0: This will set the XPath object caching:
2279
 *      @value:
2280
 *        This will set the maximum number of XPath objects
2281
 *        to be cached per slot
2282
 *        There are 5 slots for: node-set, string, number, boolean, and
2283
 *        misc objects. Use <0 for the default number (100).
2284
 *   Other values for @options have currently no effect.
2285
 *
2286
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2287
 */
2288
int
2289
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2290
      int active,
2291
      int value,
2292
      int options)
2293
0
{
2294
0
    if (ctxt == NULL)
2295
0
  return(-1);
2296
0
    if (active) {
2297
0
  xmlXPathContextCachePtr cache;
2298
2299
0
  if (ctxt->cache == NULL) {
2300
0
      ctxt->cache = xmlXPathNewCache();
2301
0
      if (ctxt->cache == NULL)
2302
0
    return(-1);
2303
0
  }
2304
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2305
0
  if (options == 0) {
2306
0
      if (value < 0)
2307
0
    value = 100;
2308
0
      cache->maxNodeset = value;
2309
0
      cache->maxString = value;
2310
0
      cache->maxNumber = value;
2311
0
      cache->maxBoolean = value;
2312
0
      cache->maxMisc = value;
2313
0
  }
2314
0
    } else if (ctxt->cache != NULL) {
2315
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2316
0
  ctxt->cache = NULL;
2317
0
    }
2318
0
    return(0);
2319
0
}
2320
2321
/**
2322
 * xmlXPathCacheWrapNodeSet:
2323
 * @ctxt: the XPath context
2324
 * @val:  the NodePtr value
2325
 *
2326
 * This is the cached version of xmlXPathWrapNodeSet().
2327
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2328
 *
2329
 * Returns the created or reused object.
2330
 */
2331
static xmlXPathObjectPtr
2332
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2333
787k
{
2334
787k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2335
0
  xmlXPathContextCachePtr cache =
2336
0
      (xmlXPathContextCachePtr) ctxt->cache;
2337
2338
0
  if ((cache->miscObjs != NULL) &&
2339
0
      (cache->miscObjs->number != 0))
2340
0
  {
2341
0
      xmlXPathObjectPtr ret;
2342
2343
0
      ret = (xmlXPathObjectPtr)
2344
0
    cache->miscObjs->items[--cache->miscObjs->number];
2345
0
      ret->type = XPATH_NODESET;
2346
0
      ret->nodesetval = val;
2347
#ifdef XP_DEBUG_OBJ_USAGE
2348
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2349
#endif
2350
0
      return(ret);
2351
0
  }
2352
0
    }
2353
2354
787k
    return(xmlXPathWrapNodeSet(val));
2355
2356
787k
}
2357
2358
/**
2359
 * xmlXPathCacheWrapString:
2360
 * @ctxt: the XPath context
2361
 * @val:  the xmlChar * value
2362
 *
2363
 * This is the cached version of xmlXPathWrapString().
2364
 * Wraps the @val string into an XPath object.
2365
 *
2366
 * Returns the created or reused object.
2367
 */
2368
static xmlXPathObjectPtr
2369
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2370
0
{
2371
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2372
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2373
2374
0
  if ((cache->stringObjs != NULL) &&
2375
0
      (cache->stringObjs->number != 0))
2376
0
  {
2377
2378
0
      xmlXPathObjectPtr ret;
2379
2380
0
      ret = (xmlXPathObjectPtr)
2381
0
    cache->stringObjs->items[--cache->stringObjs->number];
2382
0
      ret->type = XPATH_STRING;
2383
0
      ret->stringval = val;
2384
#ifdef XP_DEBUG_OBJ_USAGE
2385
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2386
#endif
2387
0
      return(ret);
2388
0
  } else if ((cache->miscObjs != NULL) &&
2389
0
      (cache->miscObjs->number != 0))
2390
0
  {
2391
0
      xmlXPathObjectPtr ret;
2392
      /*
2393
      * Fallback to misc-cache.
2394
      */
2395
0
      ret = (xmlXPathObjectPtr)
2396
0
    cache->miscObjs->items[--cache->miscObjs->number];
2397
2398
0
      ret->type = XPATH_STRING;
2399
0
      ret->stringval = val;
2400
#ifdef XP_DEBUG_OBJ_USAGE
2401
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2402
#endif
2403
0
      return(ret);
2404
0
  }
2405
0
    }
2406
0
    return(xmlXPathWrapString(val));
2407
0
}
2408
2409
/**
2410
 * xmlXPathCacheNewNodeSet:
2411
 * @ctxt: the XPath context
2412
 * @val:  the NodePtr value
2413
 *
2414
 * This is the cached version of xmlXPathNewNodeSet().
2415
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2416
 * it with the single Node @val
2417
 *
2418
 * Returns the created or reused object.
2419
 */
2420
static xmlXPathObjectPtr
2421
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2422
1.12M
{
2423
1.12M
    if ((ctxt != NULL) && (ctxt->cache)) {
2424
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2425
2426
0
  if ((cache->nodesetObjs != NULL) &&
2427
0
      (cache->nodesetObjs->number != 0))
2428
0
  {
2429
0
      xmlXPathObjectPtr ret;
2430
      /*
2431
      * Use the nodeset-cache.
2432
      */
2433
0
      ret = (xmlXPathObjectPtr)
2434
0
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2435
0
      ret->type = XPATH_NODESET;
2436
0
      ret->boolval = 0;
2437
0
      if (val) {
2438
0
    if ((ret->nodesetval->nodeMax == 0) ||
2439
0
        (val->type == XML_NAMESPACE_DECL))
2440
0
    {
2441
                    /* TODO: Check memory error. */
2442
0
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2443
0
    } else {
2444
0
        ret->nodesetval->nodeTab[0] = val;
2445
0
        ret->nodesetval->nodeNr = 1;
2446
0
    }
2447
0
      }
2448
#ifdef XP_DEBUG_OBJ_USAGE
2449
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2450
#endif
2451
0
      return(ret);
2452
0
  } else if ((cache->miscObjs != NULL) &&
2453
0
      (cache->miscObjs->number != 0))
2454
0
  {
2455
0
      xmlXPathObjectPtr ret;
2456
      /*
2457
      * Fallback to misc-cache.
2458
      */
2459
2460
0
      ret = (xmlXPathObjectPtr)
2461
0
    cache->miscObjs->items[--cache->miscObjs->number];
2462
2463
0
      ret->type = XPATH_NODESET;
2464
0
      ret->boolval = 0;
2465
0
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2466
0
      if (ret->nodesetval == NULL) {
2467
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2468
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2469
0
    return(NULL);
2470
0
      }
2471
#ifdef XP_DEBUG_OBJ_USAGE
2472
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2473
#endif
2474
0
      return(ret);
2475
0
  }
2476
0
    }
2477
1.12M
    return(xmlXPathNewNodeSet(val));
2478
1.12M
}
2479
2480
/**
2481
 * xmlXPathCacheNewCString:
2482
 * @ctxt: the XPath context
2483
 * @val:  the char * value
2484
 *
2485
 * This is the cached version of xmlXPathNewCString().
2486
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2487
 *
2488
 * Returns the created or reused object.
2489
 */
2490
static xmlXPathObjectPtr
2491
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2492
0
{
2493
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2494
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2495
2496
0
  if ((cache->stringObjs != NULL) &&
2497
0
      (cache->stringObjs->number != 0))
2498
0
  {
2499
0
      xmlXPathObjectPtr ret;
2500
2501
0
      ret = (xmlXPathObjectPtr)
2502
0
    cache->stringObjs->items[--cache->stringObjs->number];
2503
2504
0
      ret->type = XPATH_STRING;
2505
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2506
#ifdef XP_DEBUG_OBJ_USAGE
2507
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2508
#endif
2509
0
      return(ret);
2510
0
  } else if ((cache->miscObjs != NULL) &&
2511
0
      (cache->miscObjs->number != 0))
2512
0
  {
2513
0
      xmlXPathObjectPtr ret;
2514
2515
0
      ret = (xmlXPathObjectPtr)
2516
0
    cache->miscObjs->items[--cache->miscObjs->number];
2517
2518
0
      ret->type = XPATH_STRING;
2519
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2520
#ifdef XP_DEBUG_OBJ_USAGE
2521
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2522
#endif
2523
0
      return(ret);
2524
0
  }
2525
0
    }
2526
0
    return(xmlXPathNewCString(val));
2527
0
}
2528
2529
/**
2530
 * xmlXPathCacheNewString:
2531
 * @ctxt: the XPath context
2532
 * @val:  the xmlChar * value
2533
 *
2534
 * This is the cached version of xmlXPathNewString().
2535
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2536
 *
2537
 * Returns the created or reused object.
2538
 */
2539
static xmlXPathObjectPtr
2540
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2541
508k
{
2542
508k
    if ((ctxt != NULL) && (ctxt->cache)) {
2543
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2544
2545
0
  if ((cache->stringObjs != NULL) &&
2546
0
      (cache->stringObjs->number != 0))
2547
0
  {
2548
0
      xmlXPathObjectPtr ret;
2549
2550
0
      ret = (xmlXPathObjectPtr)
2551
0
    cache->stringObjs->items[--cache->stringObjs->number];
2552
0
      ret->type = XPATH_STRING;
2553
0
      if (val != NULL)
2554
0
    ret->stringval = xmlStrdup(val);
2555
0
      else
2556
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2557
#ifdef XP_DEBUG_OBJ_USAGE
2558
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2559
#endif
2560
0
      return(ret);
2561
0
  } else if ((cache->miscObjs != NULL) &&
2562
0
      (cache->miscObjs->number != 0))
2563
0
  {
2564
0
      xmlXPathObjectPtr ret;
2565
2566
0
      ret = (xmlXPathObjectPtr)
2567
0
    cache->miscObjs->items[--cache->miscObjs->number];
2568
2569
0
      ret->type = XPATH_STRING;
2570
0
      if (val != NULL)
2571
0
    ret->stringval = xmlStrdup(val);
2572
0
      else
2573
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2574
#ifdef XP_DEBUG_OBJ_USAGE
2575
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2576
#endif
2577
0
      return(ret);
2578
0
  }
2579
0
    }
2580
508k
    return(xmlXPathNewString(val));
2581
508k
}
2582
2583
/**
2584
 * xmlXPathCacheNewBoolean:
2585
 * @ctxt: the XPath context
2586
 * @val:  the boolean value
2587
 *
2588
 * This is the cached version of xmlXPathNewBoolean().
2589
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2590
 *
2591
 * Returns the created or reused object.
2592
 */
2593
static xmlXPathObjectPtr
2594
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2595
153k
{
2596
153k
    if ((ctxt != NULL) && (ctxt->cache)) {
2597
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2598
2599
0
  if ((cache->booleanObjs != NULL) &&
2600
0
      (cache->booleanObjs->number != 0))
2601
0
  {
2602
0
      xmlXPathObjectPtr ret;
2603
2604
0
      ret = (xmlXPathObjectPtr)
2605
0
    cache->booleanObjs->items[--cache->booleanObjs->number];
2606
0
      ret->type = XPATH_BOOLEAN;
2607
0
      ret->boolval = (val != 0);
2608
#ifdef XP_DEBUG_OBJ_USAGE
2609
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2610
#endif
2611
0
      return(ret);
2612
0
  } else if ((cache->miscObjs != NULL) &&
2613
0
      (cache->miscObjs->number != 0))
2614
0
  {
2615
0
      xmlXPathObjectPtr ret;
2616
2617
0
      ret = (xmlXPathObjectPtr)
2618
0
    cache->miscObjs->items[--cache->miscObjs->number];
2619
2620
0
      ret->type = XPATH_BOOLEAN;
2621
0
      ret->boolval = (val != 0);
2622
#ifdef XP_DEBUG_OBJ_USAGE
2623
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2624
#endif
2625
0
      return(ret);
2626
0
  }
2627
0
    }
2628
153k
    return(xmlXPathNewBoolean(val));
2629
153k
}
2630
2631
/**
2632
 * xmlXPathCacheNewFloat:
2633
 * @ctxt: the XPath context
2634
 * @val:  the double value
2635
 *
2636
 * This is the cached version of xmlXPathNewFloat().
2637
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2638
 *
2639
 * Returns the created or reused object.
2640
 */
2641
static xmlXPathObjectPtr
2642
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2643
720k
{
2644
720k
     if ((ctxt != NULL) && (ctxt->cache)) {
2645
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2646
2647
0
  if ((cache->numberObjs != NULL) &&
2648
0
      (cache->numberObjs->number != 0))
2649
0
  {
2650
0
      xmlXPathObjectPtr ret;
2651
2652
0
      ret = (xmlXPathObjectPtr)
2653
0
    cache->numberObjs->items[--cache->numberObjs->number];
2654
0
      ret->type = XPATH_NUMBER;
2655
0
      ret->floatval = val;
2656
#ifdef XP_DEBUG_OBJ_USAGE
2657
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2658
#endif
2659
0
      return(ret);
2660
0
  } else if ((cache->miscObjs != NULL) &&
2661
0
      (cache->miscObjs->number != 0))
2662
0
  {
2663
0
      xmlXPathObjectPtr ret;
2664
2665
0
      ret = (xmlXPathObjectPtr)
2666
0
    cache->miscObjs->items[--cache->miscObjs->number];
2667
2668
0
      ret->type = XPATH_NUMBER;
2669
0
      ret->floatval = val;
2670
#ifdef XP_DEBUG_OBJ_USAGE
2671
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2672
#endif
2673
0
      return(ret);
2674
0
  }
2675
0
    }
2676
720k
    return(xmlXPathNewFloat(val));
2677
720k
}
2678
2679
/**
2680
 * xmlXPathCacheConvertString:
2681
 * @ctxt: the XPath context
2682
 * @val:  an XPath object
2683
 *
2684
 * This is the cached version of xmlXPathConvertString().
2685
 * Converts an existing object to its string() equivalent
2686
 *
2687
 * Returns a created or reused object, the old one is freed (cached)
2688
 *         (or the operation is done directly on @val)
2689
 */
2690
2691
static xmlXPathObjectPtr
2692
40.2k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2693
40.2k
    xmlChar *res = NULL;
2694
2695
40.2k
    if (val == NULL)
2696
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2697
2698
40.2k
    switch (val->type) {
2699
0
    case XPATH_UNDEFINED:
2700
#ifdef DEBUG_EXPR
2701
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2702
#endif
2703
0
  break;
2704
0
    case XPATH_NODESET:
2705
0
    case XPATH_XSLT_TREE:
2706
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2707
0
  break;
2708
40.2k
    case XPATH_STRING:
2709
40.2k
  return(val);
2710
0
    case XPATH_BOOLEAN:
2711
0
  res = xmlXPathCastBooleanToString(val->boolval);
2712
0
  break;
2713
0
    case XPATH_NUMBER:
2714
0
  res = xmlXPathCastNumberToString(val->floatval);
2715
0
  break;
2716
0
    case XPATH_USERS:
2717
#ifdef LIBXML_XPTR_LOCS_ENABLED
2718
    case XPATH_POINT:
2719
    case XPATH_RANGE:
2720
    case XPATH_LOCATIONSET:
2721
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2722
0
  TODO;
2723
0
  break;
2724
40.2k
    }
2725
0
    xmlXPathReleaseObject(ctxt, val);
2726
0
    if (res == NULL)
2727
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2728
0
    return(xmlXPathCacheWrapString(ctxt, res));
2729
0
}
2730
2731
/**
2732
 * xmlXPathCacheObjectCopy:
2733
 * @ctxt: the XPath context
2734
 * @val:  the original object
2735
 *
2736
 * This is the cached version of xmlXPathObjectCopy().
2737
 * Acquire a copy of a given object
2738
 *
2739
 * Returns a created or reused created object.
2740
 */
2741
static xmlXPathObjectPtr
2742
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2743
539k
{
2744
539k
    if (val == NULL)
2745
0
  return(NULL);
2746
2747
539k
    if (XP_HAS_CACHE(ctxt)) {
2748
0
  switch (val->type) {
2749
0
      case XPATH_NODESET:
2750
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2751
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2752
0
      case XPATH_STRING:
2753
0
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2754
0
      case XPATH_BOOLEAN:
2755
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2756
0
      case XPATH_NUMBER:
2757
0
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2758
0
      default:
2759
0
    break;
2760
0
  }
2761
0
    }
2762
539k
    return(xmlXPathObjectCopy(val));
2763
539k
}
2764
2765
/**
2766
 * xmlXPathCacheConvertBoolean:
2767
 * @ctxt: the XPath context
2768
 * @val:  an XPath object
2769
 *
2770
 * This is the cached version of xmlXPathConvertBoolean().
2771
 * Converts an existing object to its boolean() equivalent
2772
 *
2773
 * Returns a created or reused object, the old one is freed (or the operation
2774
 *         is done directly on @val)
2775
 */
2776
static xmlXPathObjectPtr
2777
19.6k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2778
19.6k
    xmlXPathObjectPtr ret;
2779
2780
19.6k
    if (val == NULL)
2781
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2782
19.6k
    if (val->type == XPATH_BOOLEAN)
2783
4.84k
  return(val);
2784
14.8k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2785
14.8k
    xmlXPathReleaseObject(ctxt, val);
2786
14.8k
    return(ret);
2787
19.6k
}
2788
2789
/**
2790
 * xmlXPathCacheConvertNumber:
2791
 * @ctxt: the XPath context
2792
 * @val:  an XPath object
2793
 *
2794
 * This is the cached version of xmlXPathConvertNumber().
2795
 * Converts an existing object to its number() equivalent
2796
 *
2797
 * Returns a created or reused object, the old one is freed (or the operation
2798
 *         is done directly on @val)
2799
 */
2800
static xmlXPathObjectPtr
2801
656k
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2802
656k
    xmlXPathObjectPtr ret;
2803
2804
656k
    if (val == NULL)
2805
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2806
656k
    if (val->type == XPATH_NUMBER)
2807
0
  return(val);
2808
656k
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2809
656k
    xmlXPathReleaseObject(ctxt, val);
2810
656k
    return(ret);
2811
656k
}
2812
2813
/************************************************************************
2814
 *                  *
2815
 *    Parser stacks related functions and macros    *
2816
 *                  *
2817
 ************************************************************************/
2818
2819
/**
2820
 * xmlXPathSetFrame:
2821
 * @ctxt: an XPath parser context
2822
 *
2823
 * Set the callee evaluation frame
2824
 *
2825
 * Returns the previous frame value to be restored once done
2826
 */
2827
static int
2828
4.39k
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2829
4.39k
    int ret;
2830
2831
4.39k
    if (ctxt == NULL)
2832
0
        return(0);
2833
4.39k
    ret = ctxt->valueFrame;
2834
4.39k
    ctxt->valueFrame = ctxt->valueNr;
2835
4.39k
    return(ret);
2836
4.39k
}
2837
2838
/**
2839
 * xmlXPathPopFrame:
2840
 * @ctxt: an XPath parser context
2841
 * @frame: the previous frame value
2842
 *
2843
 * Remove the callee evaluation frame
2844
 */
2845
static void
2846
1.06k
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2847
1.06k
    if (ctxt == NULL)
2848
0
        return;
2849
1.06k
    if (ctxt->valueNr < ctxt->valueFrame) {
2850
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2851
0
    }
2852
1.06k
    ctxt->valueFrame = frame;
2853
1.06k
}
2854
2855
/**
2856
 * valuePop:
2857
 * @ctxt: an XPath evaluation context
2858
 *
2859
 * Pops the top XPath object from the value stack
2860
 *
2861
 * Returns the XPath object just removed
2862
 */
2863
xmlXPathObjectPtr
2864
valuePop(xmlXPathParserContextPtr ctxt)
2865
4.55M
{
2866
4.55M
    xmlXPathObjectPtr ret;
2867
2868
4.55M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2869
529k
        return (NULL);
2870
2871
4.02M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2872
3.34k
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2873
3.34k
        return (NULL);
2874
3.34k
    }
2875
2876
4.02M
    ctxt->valueNr--;
2877
4.02M
    if (ctxt->valueNr > 0)
2878
1.69M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2879
2.32M
    else
2880
2.32M
        ctxt->value = NULL;
2881
4.02M
    ret = ctxt->valueTab[ctxt->valueNr];
2882
4.02M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2883
4.02M
    return (ret);
2884
4.02M
}
2885
/**
2886
 * valuePush:
2887
 * @ctxt:  an XPath evaluation context
2888
 * @value:  the XPath object
2889
 *
2890
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2891
 * a memory error is recorded in the parser context.
2892
 *
2893
 * Returns the number of items on the value stack, or -1 in case of error.
2894
 */
2895
int
2896
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2897
4.02M
{
2898
4.02M
    if (ctxt == NULL) return(-1);
2899
4.02M
    if (value == NULL) {
2900
        /*
2901
         * A NULL value typically indicates that a memory allocation failed,
2902
         * so we set ctxt->error here to propagate the error.
2903
         */
2904
0
  ctxt->error = XPATH_MEMORY_ERROR;
2905
0
        return(-1);
2906
0
    }
2907
4.02M
    if (ctxt->valueNr >= ctxt->valueMax) {
2908
18
        xmlXPathObjectPtr *tmp;
2909
2910
18
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2911
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2912
0
            return (-1);
2913
0
        }
2914
18
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2915
18
                                             2 * ctxt->valueMax *
2916
18
                                             sizeof(ctxt->valueTab[0]));
2917
18
        if (tmp == NULL) {
2918
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2919
0
            return (-1);
2920
0
        }
2921
18
        ctxt->valueMax *= 2;
2922
18
  ctxt->valueTab = tmp;
2923
18
    }
2924
4.02M
    ctxt->valueTab[ctxt->valueNr] = value;
2925
4.02M
    ctxt->value = value;
2926
4.02M
    return (ctxt->valueNr++);
2927
4.02M
}
2928
2929
/**
2930
 * xmlXPathPopBoolean:
2931
 * @ctxt:  an XPath parser context
2932
 *
2933
 * Pops a boolean from the stack, handling conversion if needed.
2934
 * Check error with #xmlXPathCheckError.
2935
 *
2936
 * Returns the boolean
2937
 */
2938
int
2939
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2940
0
    xmlXPathObjectPtr obj;
2941
0
    int ret;
2942
2943
0
    obj = valuePop(ctxt);
2944
0
    if (obj == NULL) {
2945
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2946
0
  return(0);
2947
0
    }
2948
0
    if (obj->type != XPATH_BOOLEAN)
2949
0
  ret = xmlXPathCastToBoolean(obj);
2950
0
    else
2951
0
        ret = obj->boolval;
2952
0
    xmlXPathReleaseObject(ctxt->context, obj);
2953
0
    return(ret);
2954
0
}
2955
2956
/**
2957
 * xmlXPathPopNumber:
2958
 * @ctxt:  an XPath parser context
2959
 *
2960
 * Pops a number from the stack, handling conversion if needed.
2961
 * Check error with #xmlXPathCheckError.
2962
 *
2963
 * Returns the number
2964
 */
2965
double
2966
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2967
0
    xmlXPathObjectPtr obj;
2968
0
    double ret;
2969
2970
0
    obj = valuePop(ctxt);
2971
0
    if (obj == NULL) {
2972
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2973
0
  return(0);
2974
0
    }
2975
0
    if (obj->type != XPATH_NUMBER)
2976
0
  ret = xmlXPathCastToNumber(obj);
2977
0
    else
2978
0
        ret = obj->floatval;
2979
0
    xmlXPathReleaseObject(ctxt->context, obj);
2980
0
    return(ret);
2981
0
}
2982
2983
/**
2984
 * xmlXPathPopString:
2985
 * @ctxt:  an XPath parser context
2986
 *
2987
 * Pops a string from the stack, handling conversion if needed.
2988
 * Check error with #xmlXPathCheckError.
2989
 *
2990
 * Returns the string
2991
 */
2992
xmlChar *
2993
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2994
0
    xmlXPathObjectPtr obj;
2995
0
    xmlChar * ret;
2996
2997
0
    obj = valuePop(ctxt);
2998
0
    if (obj == NULL) {
2999
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3000
0
  return(NULL);
3001
0
    }
3002
0
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3003
    /* TODO: needs refactoring somewhere else */
3004
0
    if (obj->stringval == ret)
3005
0
  obj->stringval = NULL;
3006
0
    xmlXPathReleaseObject(ctxt->context, obj);
3007
0
    return(ret);
3008
0
}
3009
3010
/**
3011
 * xmlXPathPopNodeSet:
3012
 * @ctxt:  an XPath parser context
3013
 *
3014
 * Pops a node-set from the stack, handling conversion if needed.
3015
 * Check error with #xmlXPathCheckError.
3016
 *
3017
 * Returns the node-set
3018
 */
3019
xmlNodeSetPtr
3020
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3021
0
    xmlXPathObjectPtr obj;
3022
0
    xmlNodeSetPtr ret;
3023
3024
0
    if (ctxt == NULL) return(NULL);
3025
0
    if (ctxt->value == NULL) {
3026
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3027
0
  return(NULL);
3028
0
    }
3029
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3030
0
  xmlXPathSetTypeError(ctxt);
3031
0
  return(NULL);
3032
0
    }
3033
0
    obj = valuePop(ctxt);
3034
0
    ret = obj->nodesetval;
3035
#if 0
3036
    /* to fix memory leak of not clearing obj->user */
3037
    if (obj->boolval && obj->user != NULL)
3038
        xmlFreeNodeList((xmlNodePtr) obj->user);
3039
#endif
3040
0
    obj->nodesetval = NULL;
3041
0
    xmlXPathReleaseObject(ctxt->context, obj);
3042
0
    return(ret);
3043
0
}
3044
3045
/**
3046
 * xmlXPathPopExternal:
3047
 * @ctxt:  an XPath parser context
3048
 *
3049
 * Pops an external object from the stack, handling conversion if needed.
3050
 * Check error with #xmlXPathCheckError.
3051
 *
3052
 * Returns the object
3053
 */
3054
void *
3055
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3056
0
    xmlXPathObjectPtr obj;
3057
0
    void * ret;
3058
3059
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3060
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3061
0
  return(NULL);
3062
0
    }
3063
0
    if (ctxt->value->type != XPATH_USERS) {
3064
0
  xmlXPathSetTypeError(ctxt);
3065
0
  return(NULL);
3066
0
    }
3067
0
    obj = valuePop(ctxt);
3068
0
    ret = obj->user;
3069
0
    obj->user = NULL;
3070
0
    xmlXPathReleaseObject(ctxt->context, obj);
3071
0
    return(ret);
3072
0
}
3073
3074
/*
3075
 * Macros for accessing the content. Those should be used only by the parser,
3076
 * and not exported.
3077
 *
3078
 * Dirty macros, i.e. one need to make assumption on the context to use them
3079
 *
3080
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3081
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3082
 *           in ISO-Latin or UTF-8.
3083
 *           This should be used internally by the parser
3084
 *           only to compare to ASCII values otherwise it would break when
3085
 *           running with UTF-8 encoding.
3086
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3087
 *           to compare on ASCII based substring.
3088
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3089
 *           strings within the parser.
3090
 *   CURRENT Returns the current char value, with the full decoding of
3091
 *           UTF-8 if we are using this mode. It returns an int.
3092
 *   NEXT    Skip to the next character, this does the proper decoding
3093
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3094
 *           It returns the pointer to the current xmlChar.
3095
 */
3096
3097
30.8M
#define CUR (*ctxt->cur)
3098
218k
#define SKIP(val) ctxt->cur += (val)
3099
1.89M
#define NXT(val) ctxt->cur[(val)]
3100
23.1k
#define CUR_PTR ctxt->cur
3101
10.0M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3102
3103
#define COPY_BUF(l,b,i,v)                                              \
3104
6.35M
    if (l == 1) b[i++] = v;                                            \
3105
6.35M
    else i += xmlCopyChar(l,&b[i],v)
3106
3107
9.03M
#define NEXTL(l)  ctxt->cur += l
3108
3109
#define SKIP_BLANKS             \
3110
16.0M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3111
3112
#define CURRENT (*ctxt->cur)
3113
13.8M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3114
3115
3116
#ifndef DBL_DIG
3117
#define DBL_DIG 16
3118
#endif
3119
#ifndef DBL_EPSILON
3120
#define DBL_EPSILON 1E-9
3121
#endif
3122
3123
0
#define UPPER_DOUBLE 1E9
3124
0
#define LOWER_DOUBLE 1E-5
3125
#define LOWER_DOUBLE_EXP 5
3126
3127
#define INTEGER_DIGITS DBL_DIG
3128
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3129
0
#define EXPONENT_DIGITS (3 + 2)
3130
3131
/**
3132
 * xmlXPathFormatNumber:
3133
 * @number:     number to format
3134
 * @buffer:     output buffer
3135
 * @buffersize: size of output buffer
3136
 *
3137
 * Convert the number into a string representation.
3138
 */
3139
static void
3140
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3141
0
{
3142
0
    switch (xmlXPathIsInf(number)) {
3143
0
    case 1:
3144
0
  if (buffersize > (int)sizeof("Infinity"))
3145
0
      snprintf(buffer, buffersize, "Infinity");
3146
0
  break;
3147
0
    case -1:
3148
0
  if (buffersize > (int)sizeof("-Infinity"))
3149
0
      snprintf(buffer, buffersize, "-Infinity");
3150
0
  break;
3151
0
    default:
3152
0
  if (xmlXPathIsNaN(number)) {
3153
0
      if (buffersize > (int)sizeof("NaN"))
3154
0
    snprintf(buffer, buffersize, "NaN");
3155
0
  } else if (number == 0) {
3156
            /* Omit sign for negative zero. */
3157
0
      snprintf(buffer, buffersize, "0");
3158
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3159
0
                   (number == (int) number)) {
3160
0
      char work[30];
3161
0
      char *ptr, *cur;
3162
0
      int value = (int) number;
3163
3164
0
            ptr = &buffer[0];
3165
0
      if (value == 0) {
3166
0
    *ptr++ = '0';
3167
0
      } else {
3168
0
    snprintf(work, 29, "%d", value);
3169
0
    cur = &work[0];
3170
0
    while ((*cur) && (ptr - buffer < buffersize)) {
3171
0
        *ptr++ = *cur++;
3172
0
    }
3173
0
      }
3174
0
      if (ptr - buffer < buffersize) {
3175
0
    *ptr = 0;
3176
0
      } else if (buffersize > 0) {
3177
0
    ptr--;
3178
0
    *ptr = 0;
3179
0
      }
3180
0
  } else {
3181
      /*
3182
        For the dimension of work,
3183
            DBL_DIG is number of significant digits
3184
      EXPONENT is only needed for "scientific notation"
3185
            3 is sign, decimal point, and terminating zero
3186
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3187
        Note that this dimension is slightly (a few characters)
3188
        larger than actually necessary.
3189
      */
3190
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3191
0
      int integer_place, fraction_place;
3192
0
      char *ptr;
3193
0
      char *after_fraction;
3194
0
      double absolute_value;
3195
0
      int size;
3196
3197
0
      absolute_value = fabs(number);
3198
3199
      /*
3200
       * First choose format - scientific or regular floating point.
3201
       * In either case, result is in work, and after_fraction points
3202
       * just past the fractional part.
3203
      */
3204
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
3205
0
      (absolute_value < LOWER_DOUBLE)) &&
3206
0
     (absolute_value != 0.0) ) {
3207
    /* Use scientific notation */
3208
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3209
0
    fraction_place = DBL_DIG - 1;
3210
0
    size = snprintf(work, sizeof(work),"%*.*e",
3211
0
       integer_place, fraction_place, number);
3212
0
    while ((size > 0) && (work[size] != 'e')) size--;
3213
3214
0
      }
3215
0
      else {
3216
    /* Use regular notation */
3217
0
    if (absolute_value > 0.0) {
3218
0
        integer_place = (int)log10(absolute_value);
3219
0
        if (integer_place > 0)
3220
0
            fraction_place = DBL_DIG - integer_place - 1;
3221
0
        else
3222
0
            fraction_place = DBL_DIG - integer_place;
3223
0
    } else {
3224
0
        fraction_place = 1;
3225
0
    }
3226
0
    size = snprintf(work, sizeof(work), "%0.*f",
3227
0
        fraction_place, number);
3228
0
      }
3229
3230
      /* Remove leading spaces sometimes inserted by snprintf */
3231
0
      while (work[0] == ' ') {
3232
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3233
0
    size--;
3234
0
      }
3235
3236
      /* Remove fractional trailing zeroes */
3237
0
      after_fraction = work + size;
3238
0
      ptr = after_fraction;
3239
0
      while (*(--ptr) == '0')
3240
0
    ;
3241
0
      if (*ptr != '.')
3242
0
          ptr++;
3243
0
      while ((*ptr++ = *after_fraction++) != 0);
3244
3245
      /* Finally copy result back to caller */
3246
0
      size = strlen(work) + 1;
3247
0
      if (size > buffersize) {
3248
0
    work[buffersize - 1] = 0;
3249
0
    size = buffersize;
3250
0
      }
3251
0
      memmove(buffer, work, size);
3252
0
  }
3253
0
  break;
3254
0
    }
3255
0
}
3256
3257
3258
/************************************************************************
3259
 *                  *
3260
 *      Routines to handle NodeSets     *
3261
 *                  *
3262
 ************************************************************************/
3263
3264
/**
3265
 * xmlXPathOrderDocElems:
3266
 * @doc:  an input document
3267
 *
3268
 * Call this routine to speed up XPath computation on static documents.
3269
 * This stamps all the element nodes with the document order
3270
 * Like for line information, the order is kept in the element->content
3271
 * field, the value stored is actually - the node number (starting at -1)
3272
 * to be able to differentiate from line numbers.
3273
 *
3274
 * Returns the number of elements found in the document or -1 in case
3275
 *    of error.
3276
 */
3277
long
3278
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
3279
0
    ptrdiff_t count = 0;
3280
0
    xmlNodePtr cur;
3281
3282
0
    if (doc == NULL)
3283
0
  return(-1);
3284
0
    cur = doc->children;
3285
0
    while (cur != NULL) {
3286
0
  if (cur->type == XML_ELEMENT_NODE) {
3287
0
      cur->content = (void *) (-(++count));
3288
0
      if (cur->children != NULL) {
3289
0
    cur = cur->children;
3290
0
    continue;
3291
0
      }
3292
0
  }
3293
0
  if (cur->next != NULL) {
3294
0
      cur = cur->next;
3295
0
      continue;
3296
0
  }
3297
0
  do {
3298
0
      cur = cur->parent;
3299
0
      if (cur == NULL)
3300
0
    break;
3301
0
      if (cur == (xmlNodePtr) doc) {
3302
0
    cur = NULL;
3303
0
    break;
3304
0
      }
3305
0
      if (cur->next != NULL) {
3306
0
    cur = cur->next;
3307
0
    break;
3308
0
      }
3309
0
  } while (cur != NULL);
3310
0
    }
3311
0
    return(count);
3312
0
}
3313
3314
/**
3315
 * xmlXPathCmpNodes:
3316
 * @node1:  the first node
3317
 * @node2:  the second node
3318
 *
3319
 * Compare two nodes w.r.t document order
3320
 *
3321
 * Returns -2 in case of error 1 if first point < second point, 0 if
3322
 *         it's the same node, -1 otherwise
3323
 */
3324
int
3325
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3326
0
    int depth1, depth2;
3327
0
    int attr1 = 0, attr2 = 0;
3328
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3329
0
    xmlNodePtr cur, root;
3330
3331
0
    if ((node1 == NULL) || (node2 == NULL))
3332
0
  return(-2);
3333
    /*
3334
     * a couple of optimizations which will avoid computations in most cases
3335
     */
3336
0
    if (node1 == node2)   /* trivial case */
3337
0
  return(0);
3338
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3339
0
  attr1 = 1;
3340
0
  attrNode1 = node1;
3341
0
  node1 = node1->parent;
3342
0
    }
3343
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3344
0
  attr2 = 1;
3345
0
  attrNode2 = node2;
3346
0
  node2 = node2->parent;
3347
0
    }
3348
0
    if (node1 == node2) {
3349
0
  if (attr1 == attr2) {
3350
      /* not required, but we keep attributes in order */
3351
0
      if (attr1 != 0) {
3352
0
          cur = attrNode2->prev;
3353
0
    while (cur != NULL) {
3354
0
        if (cur == attrNode1)
3355
0
            return (1);
3356
0
        cur = cur->prev;
3357
0
    }
3358
0
    return (-1);
3359
0
      }
3360
0
      return(0);
3361
0
  }
3362
0
  if (attr2 == 1)
3363
0
      return(1);
3364
0
  return(-1);
3365
0
    }
3366
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3367
0
        (node2->type == XML_NAMESPACE_DECL))
3368
0
  return(1);
3369
0
    if (node1 == node2->prev)
3370
0
  return(1);
3371
0
    if (node1 == node2->next)
3372
0
  return(-1);
3373
3374
    /*
3375
     * Speedup using document order if available.
3376
     */
3377
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3378
0
  (node2->type == XML_ELEMENT_NODE) &&
3379
0
  (0 > (ptrdiff_t) node1->content) &&
3380
0
  (0 > (ptrdiff_t) node2->content) &&
3381
0
  (node1->doc == node2->doc)) {
3382
0
  ptrdiff_t l1, l2;
3383
3384
0
  l1 = -((ptrdiff_t) node1->content);
3385
0
  l2 = -((ptrdiff_t) node2->content);
3386
0
  if (l1 < l2)
3387
0
      return(1);
3388
0
  if (l1 > l2)
3389
0
      return(-1);
3390
0
    }
3391
3392
    /*
3393
     * compute depth to root
3394
     */
3395
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3396
0
  if (cur->parent == node1)
3397
0
      return(1);
3398
0
  depth2++;
3399
0
    }
3400
0
    root = cur;
3401
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3402
0
  if (cur->parent == node2)
3403
0
      return(-1);
3404
0
  depth1++;
3405
0
    }
3406
    /*
3407
     * Distinct document (or distinct entities :-( ) case.
3408
     */
3409
0
    if (root != cur) {
3410
0
  return(-2);
3411
0
    }
3412
    /*
3413
     * get the nearest common ancestor.
3414
     */
3415
0
    while (depth1 > depth2) {
3416
0
  depth1--;
3417
0
  node1 = node1->parent;
3418
0
    }
3419
0
    while (depth2 > depth1) {
3420
0
  depth2--;
3421
0
  node2 = node2->parent;
3422
0
    }
3423
0
    while (node1->parent != node2->parent) {
3424
0
  node1 = node1->parent;
3425
0
  node2 = node2->parent;
3426
  /* should not happen but just in case ... */
3427
0
  if ((node1 == NULL) || (node2 == NULL))
3428
0
      return(-2);
3429
0
    }
3430
    /*
3431
     * Find who's first.
3432
     */
3433
0
    if (node1 == node2->prev)
3434
0
  return(1);
3435
0
    if (node1 == node2->next)
3436
0
  return(-1);
3437
    /*
3438
     * Speedup using document order if available.
3439
     */
3440
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3441
0
  (node2->type == XML_ELEMENT_NODE) &&
3442
0
  (0 > (ptrdiff_t) node1->content) &&
3443
0
  (0 > (ptrdiff_t) node2->content) &&
3444
0
  (node1->doc == node2->doc)) {
3445
0
  ptrdiff_t l1, l2;
3446
3447
0
  l1 = -((ptrdiff_t) node1->content);
3448
0
  l2 = -((ptrdiff_t) node2->content);
3449
0
  if (l1 < l2)
3450
0
      return(1);
3451
0
  if (l1 > l2)
3452
0
      return(-1);
3453
0
    }
3454
3455
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3456
0
  if (cur == node2)
3457
0
      return(1);
3458
0
    return(-1); /* assume there is no sibling list corruption */
3459
0
}
3460
3461
/**
3462
 * xmlXPathNodeSetSort:
3463
 * @set:  the node set
3464
 *
3465
 * Sort the node set in document order
3466
 */
3467
void
3468
71.2k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3469
#ifndef WITH_TIM_SORT
3470
    int i, j, incr, len;
3471
    xmlNodePtr tmp;
3472
#endif
3473
3474
71.2k
    if (set == NULL)
3475
0
  return;
3476
3477
#ifndef WITH_TIM_SORT
3478
    /*
3479
     * Use the old Shell's sort implementation to sort the node-set
3480
     * Timsort ought to be quite faster
3481
     */
3482
    len = set->nodeNr;
3483
    for (incr = len / 2; incr > 0; incr /= 2) {
3484
  for (i = incr; i < len; i++) {
3485
      j = i - incr;
3486
      while (j >= 0) {
3487
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3488
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3489
      set->nodeTab[j + incr]) == -1)
3490
#else
3491
    if (xmlXPathCmpNodes(set->nodeTab[j],
3492
      set->nodeTab[j + incr]) == -1)
3493
#endif
3494
    {
3495
        tmp = set->nodeTab[j];
3496
        set->nodeTab[j] = set->nodeTab[j + incr];
3497
        set->nodeTab[j + incr] = tmp;
3498
        j -= incr;
3499
    } else
3500
        break;
3501
      }
3502
  }
3503
    }
3504
#else /* WITH_TIM_SORT */
3505
71.2k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3506
71.2k
#endif /* WITH_TIM_SORT */
3507
71.2k
}
3508
3509
4.96M
#define XML_NODESET_DEFAULT 10
3510
/**
3511
 * xmlXPathNodeSetDupNs:
3512
 * @node:  the parent node of the namespace XPath node
3513
 * @ns:  the libxml namespace declaration node.
3514
 *
3515
 * Namespace node in libxml don't match the XPath semantic. In a node set
3516
 * the namespace nodes are duplicated and the next pointer is set to the
3517
 * parent node in the XPath semantic.
3518
 *
3519
 * Returns the newly created object.
3520
 */
3521
static xmlNodePtr
3522
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3523
0
    xmlNsPtr cur;
3524
3525
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3526
0
  return(NULL);
3527
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3528
0
  return((xmlNodePtr) ns);
3529
3530
    /*
3531
     * Allocate a new Namespace and fill the fields.
3532
     */
3533
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3534
0
    if (cur == NULL) {
3535
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3536
0
  return(NULL);
3537
0
    }
3538
0
    memset(cur, 0, sizeof(xmlNs));
3539
0
    cur->type = XML_NAMESPACE_DECL;
3540
0
    if (ns->href != NULL)
3541
0
  cur->href = xmlStrdup(ns->href);
3542
0
    if (ns->prefix != NULL)
3543
0
  cur->prefix = xmlStrdup(ns->prefix);
3544
0
    cur->next = (xmlNsPtr) node;
3545
0
    return((xmlNodePtr) cur);
3546
0
}
3547
3548
/**
3549
 * xmlXPathNodeSetFreeNs:
3550
 * @ns:  the XPath namespace node found in a nodeset.
3551
 *
3552
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3553
 * the namespace nodes are duplicated and the next pointer is set to the
3554
 * parent node in the XPath semantic. Check if such a node needs to be freed
3555
 */
3556
void
3557
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3558
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3559
0
  return;
3560
3561
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3562
0
  if (ns->href != NULL)
3563
0
      xmlFree((xmlChar *)ns->href);
3564
0
  if (ns->prefix != NULL)
3565
0
      xmlFree((xmlChar *)ns->prefix);
3566
0
  xmlFree(ns);
3567
0
    }
3568
0
}
3569
3570
/**
3571
 * xmlXPathNodeSetCreate:
3572
 * @val:  an initial xmlNodePtr, or NULL
3573
 *
3574
 * Create a new xmlNodeSetPtr of type double and of value @val
3575
 *
3576
 * Returns the newly created object.
3577
 */
3578
xmlNodeSetPtr
3579
1.93M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3580
1.93M
    xmlNodeSetPtr ret;
3581
3582
1.93M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3583
1.93M
    if (ret == NULL) {
3584
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3585
0
  return(NULL);
3586
0
    }
3587
1.93M
    memset(ret, 0 , sizeof(xmlNodeSet));
3588
1.93M
    if (val != NULL) {
3589
1.07M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3590
1.07M
               sizeof(xmlNodePtr));
3591
1.07M
  if (ret->nodeTab == NULL) {
3592
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
      xmlFree(ret);
3594
0
      return(NULL);
3595
0
  }
3596
1.07M
  memset(ret->nodeTab, 0 ,
3597
1.07M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3598
1.07M
        ret->nodeMax = XML_NODESET_DEFAULT;
3599
1.07M
  if (val->type == XML_NAMESPACE_DECL) {
3600
0
      xmlNsPtr ns = (xmlNsPtr) val;
3601
3602
            /* TODO: Check memory error. */
3603
0
      ret->nodeTab[ret->nodeNr++] =
3604
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3605
0
  } else
3606
1.07M
      ret->nodeTab[ret->nodeNr++] = val;
3607
1.07M
    }
3608
1.93M
    return(ret);
3609
1.93M
}
3610
3611
/**
3612
 * xmlXPathNodeSetContains:
3613
 * @cur:  the node-set
3614
 * @val:  the node
3615
 *
3616
 * checks whether @cur contains @val
3617
 *
3618
 * Returns true (1) if @cur contains @val, false (0) otherwise
3619
 */
3620
int
3621
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3622
0
    int i;
3623
3624
0
    if ((cur == NULL) || (val == NULL)) return(0);
3625
0
    if (val->type == XML_NAMESPACE_DECL) {
3626
0
  for (i = 0; i < cur->nodeNr; i++) {
3627
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3628
0
    xmlNsPtr ns1, ns2;
3629
3630
0
    ns1 = (xmlNsPtr) val;
3631
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3632
0
    if (ns1 == ns2)
3633
0
        return(1);
3634
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3635
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3636
0
        return(1);
3637
0
      }
3638
0
  }
3639
0
    } else {
3640
0
  for (i = 0; i < cur->nodeNr; i++) {
3641
0
      if (cur->nodeTab[i] == val)
3642
0
    return(1);
3643
0
  }
3644
0
    }
3645
0
    return(0);
3646
0
}
3647
3648
/**
3649
 * xmlXPathNodeSetAddNs:
3650
 * @cur:  the initial node set
3651
 * @node:  the hosting node
3652
 * @ns:  a the namespace node
3653
 *
3654
 * add a new namespace node to an existing NodeSet
3655
 *
3656
 * Returns 0 in case of success and -1 in case of error
3657
 */
3658
int
3659
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3660
0
    int i;
3661
3662
3663
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3664
0
        (ns->type != XML_NAMESPACE_DECL) ||
3665
0
  (node->type != XML_ELEMENT_NODE))
3666
0
  return(-1);
3667
3668
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3669
    /*
3670
     * prevent duplicates
3671
     */
3672
0
    for (i = 0;i < cur->nodeNr;i++) {
3673
0
        if ((cur->nodeTab[i] != NULL) &&
3674
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3675
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3676
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3677
0
      return(0);
3678
0
    }
3679
3680
    /*
3681
     * grow the nodeTab if needed
3682
     */
3683
0
    if (cur->nodeMax == 0) {
3684
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3685
0
               sizeof(xmlNodePtr));
3686
0
  if (cur->nodeTab == NULL) {
3687
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3688
0
      return(-1);
3689
0
  }
3690
0
  memset(cur->nodeTab, 0 ,
3691
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3692
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3693
0
    } else if (cur->nodeNr == cur->nodeMax) {
3694
0
        xmlNodePtr *temp;
3695
3696
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3697
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3698
0
            return(-1);
3699
0
        }
3700
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3701
0
              sizeof(xmlNodePtr));
3702
0
  if (temp == NULL) {
3703
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3704
0
      return(-1);
3705
0
  }
3706
0
        cur->nodeMax *= 2;
3707
0
  cur->nodeTab = temp;
3708
0
    }
3709
    /* TODO: Check memory error. */
3710
0
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3711
0
    return(0);
3712
0
}
3713
3714
/**
3715
 * xmlXPathNodeSetAdd:
3716
 * @cur:  the initial node set
3717
 * @val:  a new xmlNodePtr
3718
 *
3719
 * add a new xmlNodePtr to an existing NodeSet
3720
 *
3721
 * Returns 0 in case of success, and -1 in case of error
3722
 */
3723
int
3724
1.91k
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3725
1.91k
    int i;
3726
3727
1.91k
    if ((cur == NULL) || (val == NULL)) return(-1);
3728
3729
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3730
    /*
3731
     * prevent duplicates
3732
     */
3733
1.91k
    for (i = 0;i < cur->nodeNr;i++)
3734
0
        if (cur->nodeTab[i] == val) return(0);
3735
3736
    /*
3737
     * grow the nodeTab if needed
3738
     */
3739
1.91k
    if (cur->nodeMax == 0) {
3740
1.91k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3741
1.91k
               sizeof(xmlNodePtr));
3742
1.91k
  if (cur->nodeTab == NULL) {
3743
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3744
0
      return(-1);
3745
0
  }
3746
1.91k
  memset(cur->nodeTab, 0 ,
3747
1.91k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3748
1.91k
        cur->nodeMax = XML_NODESET_DEFAULT;
3749
1.91k
    } else if (cur->nodeNr == cur->nodeMax) {
3750
0
        xmlNodePtr *temp;
3751
3752
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3753
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3754
0
            return(-1);
3755
0
        }
3756
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3757
0
              sizeof(xmlNodePtr));
3758
0
  if (temp == NULL) {
3759
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3760
0
      return(-1);
3761
0
  }
3762
0
        cur->nodeMax *= 2;
3763
0
  cur->nodeTab = temp;
3764
0
    }
3765
1.91k
    if (val->type == XML_NAMESPACE_DECL) {
3766
0
  xmlNsPtr ns = (xmlNsPtr) val;
3767
3768
        /* TODO: Check memory error. */
3769
0
  cur->nodeTab[cur->nodeNr++] =
3770
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3771
0
    } else
3772
1.91k
  cur->nodeTab[cur->nodeNr++] = val;
3773
1.91k
    return(0);
3774
1.91k
}
3775
3776
/**
3777
 * xmlXPathNodeSetAddUnique:
3778
 * @cur:  the initial node set
3779
 * @val:  a new xmlNodePtr
3780
 *
3781
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3782
 * when we are sure the node is not already in the set.
3783
 *
3784
 * Returns 0 in case of success and -1 in case of failure
3785
 */
3786
int
3787
19.9M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3788
19.9M
    if ((cur == NULL) || (val == NULL)) return(-1);
3789
3790
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3791
    /*
3792
     * grow the nodeTab if needed
3793
     */
3794
19.9M
    if (cur->nodeMax == 0) {
3795
482k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3796
482k
               sizeof(xmlNodePtr));
3797
482k
  if (cur->nodeTab == NULL) {
3798
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3799
0
      return(-1);
3800
0
  }
3801
482k
  memset(cur->nodeTab, 0 ,
3802
482k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3803
482k
        cur->nodeMax = XML_NODESET_DEFAULT;
3804
19.5M
    } else if (cur->nodeNr == cur->nodeMax) {
3805
291k
        xmlNodePtr *temp;
3806
3807
291k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3808
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3809
0
            return(-1);
3810
0
        }
3811
291k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3812
291k
              sizeof(xmlNodePtr));
3813
291k
  if (temp == NULL) {
3814
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3815
0
      return(-1);
3816
0
  }
3817
291k
  cur->nodeTab = temp;
3818
291k
        cur->nodeMax *= 2;
3819
291k
    }
3820
19.9M
    if (val->type == XML_NAMESPACE_DECL) {
3821
0
  xmlNsPtr ns = (xmlNsPtr) val;
3822
3823
        /* TODO: Check memory error. */
3824
0
  cur->nodeTab[cur->nodeNr++] =
3825
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3826
0
    } else
3827
19.9M
  cur->nodeTab[cur->nodeNr++] = val;
3828
19.9M
    return(0);
3829
19.9M
}
3830
3831
/**
3832
 * xmlXPathNodeSetMerge:
3833
 * @val1:  the first NodeSet or NULL
3834
 * @val2:  the second NodeSet
3835
 *
3836
 * Merges two nodesets, all nodes from @val2 are added to @val1
3837
 * if @val1 is NULL, a new set is created and copied from @val2
3838
 *
3839
 * Returns @val1 once extended or NULL in case of error.
3840
 */
3841
xmlNodeSetPtr
3842
35.1k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3843
35.1k
    int i, j, initNr, skip;
3844
35.1k
    xmlNodePtr n1, n2;
3845
3846
35.1k
    if (val2 == NULL) return(val1);
3847
33.9k
    if (val1 == NULL) {
3848
2.59k
  val1 = xmlXPathNodeSetCreate(NULL);
3849
2.59k
    if (val1 == NULL)
3850
0
        return (NULL);
3851
#if 0
3852
  /*
3853
  * TODO: The optimization won't work in every case, since
3854
  *  those nasty namespace nodes need to be added with
3855
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3856
  *  memcpy is not possible.
3857
  *  If there was a flag on the nodesetval, indicating that
3858
  *  some temporary nodes are in, that would be helpful.
3859
  */
3860
  /*
3861
  * Optimization: Create an equally sized node-set
3862
  * and memcpy the content.
3863
  */
3864
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3865
  if (val1 == NULL)
3866
      return(NULL);
3867
  if (val2->nodeNr != 0) {
3868
      if (val2->nodeNr == 1)
3869
    *(val1->nodeTab) = *(val2->nodeTab);
3870
      else {
3871
    memcpy(val1->nodeTab, val2->nodeTab,
3872
        val2->nodeNr * sizeof(xmlNodePtr));
3873
      }
3874
      val1->nodeNr = val2->nodeNr;
3875
  }
3876
  return(val1);
3877
#endif
3878
2.59k
    }
3879
3880
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3881
33.9k
    initNr = val1->nodeNr;
3882
3883
651k
    for (i = 0;i < val2->nodeNr;i++) {
3884
617k
  n2 = val2->nodeTab[i];
3885
  /*
3886
   * check against duplicates
3887
   */
3888
617k
  skip = 0;
3889
12.3M
  for (j = 0; j < initNr; j++) {
3890
11.7M
      n1 = val1->nodeTab[j];
3891
11.7M
      if (n1 == n2) {
3892
11.1k
    skip = 1;
3893
11.1k
    break;
3894
11.7M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3895
11.7M
           (n2->type == XML_NAMESPACE_DECL)) {
3896
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3897
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3898
0
      ((xmlNsPtr) n2)->prefix)))
3899
0
    {
3900
0
        skip = 1;
3901
0
        break;
3902
0
    }
3903
0
      }
3904
11.7M
  }
3905
617k
  if (skip)
3906
11.1k
      continue;
3907
3908
  /*
3909
   * grow the nodeTab if needed
3910
   */
3911
606k
  if (val1->nodeMax == 0) {
3912
18.0k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3913
18.0k
                sizeof(xmlNodePtr));
3914
18.0k
      if (val1->nodeTab == NULL) {
3915
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3916
0
    return(NULL);
3917
0
      }
3918
18.0k
      memset(val1->nodeTab, 0 ,
3919
18.0k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3920
18.0k
      val1->nodeMax = XML_NODESET_DEFAULT;
3921
588k
  } else if (val1->nodeNr == val1->nodeMax) {
3922
18.1k
      xmlNodePtr *temp;
3923
3924
18.1k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3925
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3926
0
                return(NULL);
3927
0
            }
3928
18.1k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3929
18.1k
               sizeof(xmlNodePtr));
3930
18.1k
      if (temp == NULL) {
3931
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3932
0
    return(NULL);
3933
0
      }
3934
18.1k
      val1->nodeTab = temp;
3935
18.1k
      val1->nodeMax *= 2;
3936
18.1k
  }
3937
606k
  if (n2->type == XML_NAMESPACE_DECL) {
3938
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3939
3940
            /* TODO: Check memory error. */
3941
0
      val1->nodeTab[val1->nodeNr++] =
3942
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3943
0
  } else
3944
606k
      val1->nodeTab[val1->nodeNr++] = n2;
3945
606k
    }
3946
3947
33.9k
    return(val1);
3948
33.9k
}
3949
3950
3951
/**
3952
 * xmlXPathNodeSetMergeAndClear:
3953
 * @set1:  the first NodeSet or NULL
3954
 * @set2:  the second NodeSet
3955
 *
3956
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3957
 * Checks for duplicate nodes. Clears set2.
3958
 *
3959
 * Returns @set1 once extended or NULL in case of error.
3960
 */
3961
static xmlNodeSetPtr
3962
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3963
1.14M
{
3964
1.14M
    {
3965
1.14M
  int i, j, initNbSet1;
3966
1.14M
  xmlNodePtr n1, n2;
3967
3968
1.14M
  initNbSet1 = set1->nodeNr;
3969
6.83M
  for (i = 0;i < set2->nodeNr;i++) {
3970
5.68M
      n2 = set2->nodeTab[i];
3971
      /*
3972
      * Skip duplicates.
3973
      */
3974
4.79G
      for (j = 0; j < initNbSet1; j++) {
3975
4.79G
    n1 = set1->nodeTab[j];
3976
4.79G
    if (n1 == n2) {
3977
4.99M
        goto skip_node;
3978
4.78G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3979
4.78G
        (n2->type == XML_NAMESPACE_DECL))
3980
0
    {
3981
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3982
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3983
0
      ((xmlNsPtr) n2)->prefix)))
3984
0
        {
3985
      /*
3986
      * Free the namespace node.
3987
      */
3988
0
      set2->nodeTab[i] = NULL;
3989
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3990
0
      goto skip_node;
3991
0
        }
3992
0
    }
3993
4.79G
      }
3994
      /*
3995
      * grow the nodeTab if needed
3996
      */
3997
689k
      if (set1->nodeMax == 0) {
3998
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3999
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4000
0
    if (set1->nodeTab == NULL) {
4001
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4002
0
        return(NULL);
4003
0
    }
4004
0
    memset(set1->nodeTab, 0,
4005
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4006
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4007
689k
      } else if (set1->nodeNr >= set1->nodeMax) {
4008
10.8k
    xmlNodePtr *temp;
4009
4010
10.8k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4011
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4012
0
                    return(NULL);
4013
0
                }
4014
10.8k
    temp = (xmlNodePtr *) xmlRealloc(
4015
10.8k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4016
10.8k
    if (temp == NULL) {
4017
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4018
0
        return(NULL);
4019
0
    }
4020
10.8k
    set1->nodeTab = temp;
4021
10.8k
    set1->nodeMax *= 2;
4022
10.8k
      }
4023
689k
      set1->nodeTab[set1->nodeNr++] = n2;
4024
5.68M
skip_node:
4025
5.68M
      {}
4026
5.68M
  }
4027
1.14M
    }
4028
1.14M
    set2->nodeNr = 0;
4029
1.14M
    return(set1);
4030
1.14M
}
4031
4032
/**
4033
 * xmlXPathNodeSetMergeAndClearNoDupls:
4034
 * @set1:  the first NodeSet or NULL
4035
 * @set2:  the second NodeSet
4036
 *
4037
 * Merges two nodesets, all nodes from @set2 are added to @set1.
4038
 * Doesn't check for duplicate nodes. Clears set2.
4039
 *
4040
 * Returns @set1 once extended or NULL in case of error.
4041
 */
4042
static xmlNodeSetPtr
4043
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4044
1.23M
{
4045
1.23M
    {
4046
1.23M
  int i;
4047
1.23M
  xmlNodePtr n2;
4048
4049
3.24M
  for (i = 0;i < set2->nodeNr;i++) {
4050
2.01M
      n2 = set2->nodeTab[i];
4051
2.01M
      if (set1->nodeMax == 0) {
4052
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4053
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4054
0
    if (set1->nodeTab == NULL) {
4055
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4056
0
        return(NULL);
4057
0
    }
4058
0
    memset(set1->nodeTab, 0,
4059
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4060
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4061
2.01M
      } else if (set1->nodeNr >= set1->nodeMax) {
4062
47.0k
    xmlNodePtr *temp;
4063
4064
47.0k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4065
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4066
0
                    return(NULL);
4067
0
                }
4068
47.0k
    temp = (xmlNodePtr *) xmlRealloc(
4069
47.0k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4070
47.0k
    if (temp == NULL) {
4071
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4072
0
        return(NULL);
4073
0
    }
4074
47.0k
    set1->nodeTab = temp;
4075
47.0k
    set1->nodeMax *= 2;
4076
47.0k
      }
4077
2.01M
      set1->nodeTab[set1->nodeNr++] = n2;
4078
2.01M
  }
4079
1.23M
    }
4080
1.23M
    set2->nodeNr = 0;
4081
1.23M
    return(set1);
4082
1.23M
}
4083
4084
/**
4085
 * xmlXPathNodeSetDel:
4086
 * @cur:  the initial node set
4087
 * @val:  an xmlNodePtr
4088
 *
4089
 * Removes an xmlNodePtr from an existing NodeSet
4090
 */
4091
void
4092
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4093
0
    int i;
4094
4095
0
    if (cur == NULL) return;
4096
0
    if (val == NULL) return;
4097
4098
    /*
4099
     * find node in nodeTab
4100
     */
4101
0
    for (i = 0;i < cur->nodeNr;i++)
4102
0
        if (cur->nodeTab[i] == val) break;
4103
4104
0
    if (i >= cur->nodeNr) { /* not found */
4105
#ifdef DEBUG
4106
        xmlGenericError(xmlGenericErrorContext,
4107
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4108
    val->name);
4109
#endif
4110
0
        return;
4111
0
    }
4112
0
    if ((cur->nodeTab[i] != NULL) &&
4113
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4114
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4115
0
    cur->nodeNr--;
4116
0
    for (;i < cur->nodeNr;i++)
4117
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4118
0
    cur->nodeTab[cur->nodeNr] = NULL;
4119
0
}
4120
4121
/**
4122
 * xmlXPathNodeSetRemove:
4123
 * @cur:  the initial node set
4124
 * @val:  the index to remove
4125
 *
4126
 * Removes an entry from an existing NodeSet list.
4127
 */
4128
void
4129
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4130
0
    if (cur == NULL) return;
4131
0
    if (val >= cur->nodeNr) return;
4132
0
    if ((cur->nodeTab[val] != NULL) &&
4133
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4134
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4135
0
    cur->nodeNr--;
4136
0
    for (;val < cur->nodeNr;val++)
4137
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4138
0
    cur->nodeTab[cur->nodeNr] = NULL;
4139
0
}
4140
4141
/**
4142
 * xmlXPathFreeNodeSet:
4143
 * @obj:  the xmlNodeSetPtr to free
4144
 *
4145
 * Free the NodeSet compound (not the actual nodes !).
4146
 */
4147
void
4148
1.92M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4149
1.92M
    if (obj == NULL) return;
4150
1.92M
    if (obj->nodeTab != NULL) {
4151
1.57M
  int i;
4152
4153
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4154
17.3M
  for (i = 0;i < obj->nodeNr;i++)
4155
15.8M
      if ((obj->nodeTab[i] != NULL) &&
4156
15.8M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4157
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4158
1.57M
  xmlFree(obj->nodeTab);
4159
1.57M
    }
4160
1.92M
    xmlFree(obj);
4161
1.92M
}
4162
4163
/**
4164
 * xmlXPathNodeSetClearFromPos:
4165
 * @set: the node set to be cleared
4166
 * @pos: the start position to clear from
4167
 *
4168
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4169
 * are feed) starting with the entry at @pos, but does *not* free the list
4170
 * itself. Sets the length of the list to @pos.
4171
 */
4172
static void
4173
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4174
844
{
4175
844
    if ((set == NULL) || (pos >= set->nodeNr))
4176
0
  return;
4177
844
    else if ((hasNsNodes)) {
4178
69
  int i;
4179
69
  xmlNodePtr node;
4180
4181
795
  for (i = pos; i < set->nodeNr; i++) {
4182
726
      node = set->nodeTab[i];
4183
726
      if ((node != NULL) &&
4184
726
    (node->type == XML_NAMESPACE_DECL))
4185
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
726
  }
4187
69
    }
4188
844
    set->nodeNr = pos;
4189
844
}
4190
4191
/**
4192
 * xmlXPathNodeSetClear:
4193
 * @set:  the node set to clear
4194
 *
4195
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4196
 * are feed), but does *not* free the list itself. Sets the length of the
4197
 * list to 0.
4198
 */
4199
static void
4200
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4201
775
{
4202
775
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4203
775
}
4204
4205
/**
4206
 * xmlXPathNodeSetKeepLast:
4207
 * @set: the node set to be cleared
4208
 *
4209
 * Move the last node to the first position and clear temporary XPath objects
4210
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4211
 * to 1.
4212
 */
4213
static void
4214
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4215
0
{
4216
0
    int i;
4217
0
    xmlNodePtr node;
4218
4219
0
    if ((set == NULL) || (set->nodeNr <= 1))
4220
0
  return;
4221
0
    for (i = 0; i < set->nodeNr - 1; i++) {
4222
0
        node = set->nodeTab[i];
4223
0
        if ((node != NULL) &&
4224
0
            (node->type == XML_NAMESPACE_DECL))
4225
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4226
0
    }
4227
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4228
0
    set->nodeNr = 1;
4229
0
}
4230
4231
/**
4232
 * xmlXPathFreeValueTree:
4233
 * @obj:  the xmlNodeSetPtr to free
4234
 *
4235
 * Free the NodeSet compound and the actual tree, this is different
4236
 * from xmlXPathFreeNodeSet()
4237
 */
4238
static void
4239
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4240
0
    int i;
4241
4242
0
    if (obj == NULL) return;
4243
4244
0
    if (obj->nodeTab != NULL) {
4245
0
  for (i = 0;i < obj->nodeNr;i++) {
4246
0
      if (obj->nodeTab[i] != NULL) {
4247
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4248
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4249
0
    } else {
4250
0
        xmlFreeNodeList(obj->nodeTab[i]);
4251
0
    }
4252
0
      }
4253
0
  }
4254
0
  xmlFree(obj->nodeTab);
4255
0
    }
4256
0
    xmlFree(obj);
4257
0
}
4258
4259
#if defined(DEBUG) || defined(DEBUG_STEP)
4260
/**
4261
 * xmlGenericErrorContextNodeSet:
4262
 * @output:  a FILE * for the output
4263
 * @obj:  the xmlNodeSetPtr to display
4264
 *
4265
 * Quick display of a NodeSet
4266
 */
4267
void
4268
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4269
    int i;
4270
4271
    if (output == NULL) output = xmlGenericErrorContext;
4272
    if (obj == NULL)  {
4273
        fprintf(output, "NodeSet == NULL !\n");
4274
  return;
4275
    }
4276
    if (obj->nodeNr == 0) {
4277
        fprintf(output, "NodeSet is empty\n");
4278
  return;
4279
    }
4280
    if (obj->nodeTab == NULL) {
4281
  fprintf(output, " nodeTab == NULL !\n");
4282
  return;
4283
    }
4284
    for (i = 0; i < obj->nodeNr; i++) {
4285
        if (obj->nodeTab[i] == NULL) {
4286
      fprintf(output, " NULL !\n");
4287
      return;
4288
        }
4289
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4290
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4291
      fprintf(output, " /");
4292
  else if (obj->nodeTab[i]->name == NULL)
4293
      fprintf(output, " noname!");
4294
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4295
    }
4296
    fprintf(output, "\n");
4297
}
4298
#endif
4299
4300
/**
4301
 * xmlXPathNewNodeSet:
4302
 * @val:  the NodePtr value
4303
 *
4304
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4305
 * it with the single Node @val
4306
 *
4307
 * Returns the newly created object.
4308
 */
4309
xmlXPathObjectPtr
4310
1.15M
xmlXPathNewNodeSet(xmlNodePtr val) {
4311
1.15M
    xmlXPathObjectPtr ret;
4312
4313
1.15M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4314
1.15M
    if (ret == NULL) {
4315
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4316
0
  return(NULL);
4317
0
    }
4318
1.15M
    memset(ret, 0 , sizeof(xmlXPathObject));
4319
1.15M
    ret->type = XPATH_NODESET;
4320
1.15M
    ret->boolval = 0;
4321
    /* TODO: Check memory error. */
4322
1.15M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4323
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4324
#ifdef XP_DEBUG_OBJ_USAGE
4325
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4326
#endif
4327
1.15M
    return(ret);
4328
1.15M
}
4329
4330
/**
4331
 * xmlXPathNewValueTree:
4332
 * @val:  the NodePtr value
4333
 *
4334
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4335
 * it with the tree root @val
4336
 *
4337
 * Returns the newly created object.
4338
 */
4339
xmlXPathObjectPtr
4340
0
xmlXPathNewValueTree(xmlNodePtr val) {
4341
0
    xmlXPathObjectPtr ret;
4342
4343
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4344
0
    if (ret == NULL) {
4345
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4346
0
  return(NULL);
4347
0
    }
4348
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4349
0
    ret->type = XPATH_XSLT_TREE;
4350
0
    ret->boolval = 1;
4351
0
    ret->user = (void *) val;
4352
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4353
#ifdef XP_DEBUG_OBJ_USAGE
4354
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4355
#endif
4356
0
    return(ret);
4357
0
}
4358
4359
/**
4360
 * xmlXPathNewNodeSetList:
4361
 * @val:  an existing NodeSet
4362
 *
4363
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4364
 * it with the Nodeset @val
4365
 *
4366
 * Returns the newly created object.
4367
 */
4368
xmlXPathObjectPtr
4369
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4370
0
{
4371
0
    xmlXPathObjectPtr ret;
4372
0
    int i;
4373
4374
0
    if (val == NULL)
4375
0
        ret = NULL;
4376
0
    else if (val->nodeTab == NULL)
4377
0
        ret = xmlXPathNewNodeSet(NULL);
4378
0
    else {
4379
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4380
0
        if (ret) {
4381
0
            for (i = 1; i < val->nodeNr; ++i) {
4382
                /* TODO: Propagate memory error. */
4383
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4384
0
        < 0) break;
4385
0
      }
4386
0
  }
4387
0
    }
4388
4389
0
    return (ret);
4390
0
}
4391
4392
/**
4393
 * xmlXPathWrapNodeSet:
4394
 * @val:  the NodePtr value
4395
 *
4396
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4397
 *
4398
 * Returns the newly created object.
4399
 */
4400
xmlXPathObjectPtr
4401
787k
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4402
787k
    xmlXPathObjectPtr ret;
4403
4404
787k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4405
787k
    if (ret == NULL) {
4406
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4407
0
  return(NULL);
4408
0
    }
4409
787k
    memset(ret, 0 , sizeof(xmlXPathObject));
4410
787k
    ret->type = XPATH_NODESET;
4411
787k
    ret->nodesetval = val;
4412
#ifdef XP_DEBUG_OBJ_USAGE
4413
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4414
#endif
4415
787k
    return(ret);
4416
787k
}
4417
4418
/**
4419
 * xmlXPathFreeNodeSetList:
4420
 * @obj:  an existing NodeSetList object
4421
 *
4422
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4423
 * the list contrary to xmlXPathFreeObject().
4424
 */
4425
void
4426
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4427
0
    if (obj == NULL) return;
4428
#ifdef XP_DEBUG_OBJ_USAGE
4429
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4430
#endif
4431
0
    xmlFree(obj);
4432
0
}
4433
4434
/**
4435
 * xmlXPathDifference:
4436
 * @nodes1:  a node-set
4437
 * @nodes2:  a node-set
4438
 *
4439
 * Implements the EXSLT - Sets difference() function:
4440
 *    node-set set:difference (node-set, node-set)
4441
 *
4442
 * Returns the difference between the two node sets, or nodes1 if
4443
 *         nodes2 is empty
4444
 */
4445
xmlNodeSetPtr
4446
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4447
0
    xmlNodeSetPtr ret;
4448
0
    int i, l1;
4449
0
    xmlNodePtr cur;
4450
4451
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4452
0
  return(nodes1);
4453
4454
    /* TODO: Check memory error. */
4455
0
    ret = xmlXPathNodeSetCreate(NULL);
4456
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4457
0
  return(ret);
4458
4459
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4460
4461
0
    for (i = 0; i < l1; i++) {
4462
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4463
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4464
            /* TODO: Propagate memory error. */
4465
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4466
0
          break;
4467
0
  }
4468
0
    }
4469
0
    return(ret);
4470
0
}
4471
4472
/**
4473
 * xmlXPathIntersection:
4474
 * @nodes1:  a node-set
4475
 * @nodes2:  a node-set
4476
 *
4477
 * Implements the EXSLT - Sets intersection() function:
4478
 *    node-set set:intersection (node-set, node-set)
4479
 *
4480
 * Returns a node set comprising the nodes that are within both the
4481
 *         node sets passed as arguments
4482
 */
4483
xmlNodeSetPtr
4484
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4485
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4486
0
    int i, l1;
4487
0
    xmlNodePtr cur;
4488
4489
0
    if (ret == NULL)
4490
0
        return(ret);
4491
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4492
0
  return(ret);
4493
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4494
0
  return(ret);
4495
4496
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4497
4498
0
    for (i = 0; i < l1; i++) {
4499
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4500
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4501
            /* TODO: Propagate memory error. */
4502
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4503
0
          break;
4504
0
  }
4505
0
    }
4506
0
    return(ret);
4507
0
}
4508
4509
/**
4510
 * xmlXPathDistinctSorted:
4511
 * @nodes:  a node-set, sorted by document order
4512
 *
4513
 * Implements the EXSLT - Sets distinct() function:
4514
 *    node-set set:distinct (node-set)
4515
 *
4516
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4517
 *         it is empty
4518
 */
4519
xmlNodeSetPtr
4520
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4521
0
    xmlNodeSetPtr ret;
4522
0
    xmlHashTablePtr hash;
4523
0
    int i, l;
4524
0
    xmlChar * strval;
4525
0
    xmlNodePtr cur;
4526
4527
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4528
0
  return(nodes);
4529
4530
0
    ret = xmlXPathNodeSetCreate(NULL);
4531
0
    if (ret == NULL)
4532
0
        return(ret);
4533
0
    l = xmlXPathNodeSetGetLength(nodes);
4534
0
    hash = xmlHashCreate (l);
4535
0
    for (i = 0; i < l; i++) {
4536
0
  cur = xmlXPathNodeSetItem(nodes, i);
4537
0
  strval = xmlXPathCastNodeToString(cur);
4538
0
  if (xmlHashLookup(hash, strval) == NULL) {
4539
0
      xmlHashAddEntry(hash, strval, strval);
4540
            /* TODO: Propagate memory error. */
4541
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4542
0
          break;
4543
0
  } else {
4544
0
      xmlFree(strval);
4545
0
  }
4546
0
    }
4547
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4548
0
    return(ret);
4549
0
}
4550
4551
/**
4552
 * xmlXPathDistinct:
4553
 * @nodes:  a node-set
4554
 *
4555
 * Implements the EXSLT - Sets distinct() function:
4556
 *    node-set set:distinct (node-set)
4557
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4558
 * is called with the sorted node-set
4559
 *
4560
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4561
 *         it is empty
4562
 */
4563
xmlNodeSetPtr
4564
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4565
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4566
0
  return(nodes);
4567
4568
0
    xmlXPathNodeSetSort(nodes);
4569
0
    return(xmlXPathDistinctSorted(nodes));
4570
0
}
4571
4572
/**
4573
 * xmlXPathHasSameNodes:
4574
 * @nodes1:  a node-set
4575
 * @nodes2:  a node-set
4576
 *
4577
 * Implements the EXSLT - Sets has-same-nodes function:
4578
 *    boolean set:has-same-node(node-set, node-set)
4579
 *
4580
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4581
 *         otherwise
4582
 */
4583
int
4584
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4585
0
    int i, l;
4586
0
    xmlNodePtr cur;
4587
4588
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4589
0
  xmlXPathNodeSetIsEmpty(nodes2))
4590
0
  return(0);
4591
4592
0
    l = xmlXPathNodeSetGetLength(nodes1);
4593
0
    for (i = 0; i < l; i++) {
4594
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4595
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4596
0
      return(1);
4597
0
    }
4598
0
    return(0);
4599
0
}
4600
4601
/**
4602
 * xmlXPathNodeLeadingSorted:
4603
 * @nodes: a node-set, sorted by document order
4604
 * @node: a node
4605
 *
4606
 * Implements the EXSLT - Sets leading() function:
4607
 *    node-set set:leading (node-set, node-set)
4608
 *
4609
 * Returns the nodes in @nodes that precede @node in document order,
4610
 *         @nodes if @node is NULL or an empty node-set if @nodes
4611
 *         doesn't contain @node
4612
 */
4613
xmlNodeSetPtr
4614
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4615
0
    int i, l;
4616
0
    xmlNodePtr cur;
4617
0
    xmlNodeSetPtr ret;
4618
4619
0
    if (node == NULL)
4620
0
  return(nodes);
4621
4622
0
    ret = xmlXPathNodeSetCreate(NULL);
4623
0
    if (ret == NULL)
4624
0
        return(ret);
4625
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4626
0
  (!xmlXPathNodeSetContains(nodes, node)))
4627
0
  return(ret);
4628
4629
0
    l = xmlXPathNodeSetGetLength(nodes);
4630
0
    for (i = 0; i < l; i++) {
4631
0
  cur = xmlXPathNodeSetItem(nodes, i);
4632
0
  if (cur == node)
4633
0
      break;
4634
        /* TODO: Propagate memory error. */
4635
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4636
0
      break;
4637
0
    }
4638
0
    return(ret);
4639
0
}
4640
4641
/**
4642
 * xmlXPathNodeLeading:
4643
 * @nodes:  a node-set
4644
 * @node:  a node
4645
 *
4646
 * Implements the EXSLT - Sets leading() function:
4647
 *    node-set set:leading (node-set, node-set)
4648
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4649
 * is called.
4650
 *
4651
 * Returns the nodes in @nodes that precede @node in document order,
4652
 *         @nodes if @node is NULL or an empty node-set if @nodes
4653
 *         doesn't contain @node
4654
 */
4655
xmlNodeSetPtr
4656
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4657
0
    xmlXPathNodeSetSort(nodes);
4658
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4659
0
}
4660
4661
/**
4662
 * xmlXPathLeadingSorted:
4663
 * @nodes1:  a node-set, sorted by document order
4664
 * @nodes2:  a node-set, sorted by document order
4665
 *
4666
 * Implements the EXSLT - Sets leading() function:
4667
 *    node-set set:leading (node-set, node-set)
4668
 *
4669
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4670
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4671
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4672
 */
4673
xmlNodeSetPtr
4674
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4675
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4676
0
  return(nodes1);
4677
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4678
0
             xmlXPathNodeSetItem(nodes2, 1)));
4679
0
}
4680
4681
/**
4682
 * xmlXPathLeading:
4683
 * @nodes1:  a node-set
4684
 * @nodes2:  a node-set
4685
 *
4686
 * Implements the EXSLT - Sets leading() function:
4687
 *    node-set set:leading (node-set, node-set)
4688
 * @nodes1 and @nodes2 are sorted by document order, then
4689
 * #exslSetsLeadingSorted is called.
4690
 *
4691
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4692
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4693
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4694
 */
4695
xmlNodeSetPtr
4696
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4697
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4698
0
  return(nodes1);
4699
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4700
0
  return(xmlXPathNodeSetCreate(NULL));
4701
0
    xmlXPathNodeSetSort(nodes1);
4702
0
    xmlXPathNodeSetSort(nodes2);
4703
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4704
0
             xmlXPathNodeSetItem(nodes2, 1)));
4705
0
}
4706
4707
/**
4708
 * xmlXPathNodeTrailingSorted:
4709
 * @nodes: a node-set, sorted by document order
4710
 * @node: a node
4711
 *
4712
 * Implements the EXSLT - Sets trailing() function:
4713
 *    node-set set:trailing (node-set, node-set)
4714
 *
4715
 * Returns the nodes in @nodes that follow @node in document order,
4716
 *         @nodes if @node is NULL or an empty node-set if @nodes
4717
 *         doesn't contain @node
4718
 */
4719
xmlNodeSetPtr
4720
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4721
0
    int i, l;
4722
0
    xmlNodePtr cur;
4723
0
    xmlNodeSetPtr ret;
4724
4725
0
    if (node == NULL)
4726
0
  return(nodes);
4727
4728
0
    ret = xmlXPathNodeSetCreate(NULL);
4729
0
    if (ret == NULL)
4730
0
        return(ret);
4731
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4732
0
  (!xmlXPathNodeSetContains(nodes, node)))
4733
0
  return(ret);
4734
4735
0
    l = xmlXPathNodeSetGetLength(nodes);
4736
0
    for (i = l - 1; i >= 0; i--) {
4737
0
  cur = xmlXPathNodeSetItem(nodes, i);
4738
0
  if (cur == node)
4739
0
      break;
4740
        /* TODO: Propagate memory error. */
4741
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4742
0
      break;
4743
0
    }
4744
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4745
0
    return(ret);
4746
0
}
4747
4748
/**
4749
 * xmlXPathNodeTrailing:
4750
 * @nodes:  a node-set
4751
 * @node:  a node
4752
 *
4753
 * Implements the EXSLT - Sets trailing() function:
4754
 *    node-set set:trailing (node-set, node-set)
4755
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4756
 * is called.
4757
 *
4758
 * Returns the nodes in @nodes that follow @node in document order,
4759
 *         @nodes if @node is NULL or an empty node-set if @nodes
4760
 *         doesn't contain @node
4761
 */
4762
xmlNodeSetPtr
4763
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4764
0
    xmlXPathNodeSetSort(nodes);
4765
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4766
0
}
4767
4768
/**
4769
 * xmlXPathTrailingSorted:
4770
 * @nodes1:  a node-set, sorted by document order
4771
 * @nodes2:  a node-set, sorted by document order
4772
 *
4773
 * Implements the EXSLT - Sets trailing() function:
4774
 *    node-set set:trailing (node-set, node-set)
4775
 *
4776
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4777
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4778
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4779
 */
4780
xmlNodeSetPtr
4781
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4782
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4783
0
  return(nodes1);
4784
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4785
0
              xmlXPathNodeSetItem(nodes2, 0)));
4786
0
}
4787
4788
/**
4789
 * xmlXPathTrailing:
4790
 * @nodes1:  a node-set
4791
 * @nodes2:  a node-set
4792
 *
4793
 * Implements the EXSLT - Sets trailing() function:
4794
 *    node-set set:trailing (node-set, node-set)
4795
 * @nodes1 and @nodes2 are sorted by document order, then
4796
 * #xmlXPathTrailingSorted is called.
4797
 *
4798
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4799
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4800
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4801
 */
4802
xmlNodeSetPtr
4803
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4804
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4805
0
  return(nodes1);
4806
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4807
0
  return(xmlXPathNodeSetCreate(NULL));
4808
0
    xmlXPathNodeSetSort(nodes1);
4809
0
    xmlXPathNodeSetSort(nodes2);
4810
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4811
0
              xmlXPathNodeSetItem(nodes2, 0)));
4812
0
}
4813
4814
/************************************************************************
4815
 *                  *
4816
 *    Routines to handle extra functions      *
4817
 *                  *
4818
 ************************************************************************/
4819
4820
/**
4821
 * xmlXPathRegisterFunc:
4822
 * @ctxt:  the XPath context
4823
 * @name:  the function name
4824
 * @f:  the function implementation or NULL
4825
 *
4826
 * Register a new function. If @f is NULL it unregisters the function
4827
 *
4828
 * Returns 0 in case of success, -1 in case of error
4829
 */
4830
int
4831
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4832
7.68M
         xmlXPathFunction f) {
4833
7.68M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4834
7.68M
}
4835
4836
/**
4837
 * xmlXPathRegisterFuncNS:
4838
 * @ctxt:  the XPath context
4839
 * @name:  the function name
4840
 * @ns_uri:  the function namespace URI
4841
 * @f:  the function implementation or NULL
4842
 *
4843
 * Register a new function. If @f is NULL it unregisters the function
4844
 *
4845
 * Returns 0 in case of success, -1 in case of error
4846
 */
4847
int
4848
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4849
7.97M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4850
7.97M
    if (ctxt == NULL)
4851
0
  return(-1);
4852
7.97M
    if (name == NULL)
4853
0
  return(-1);
4854
4855
7.97M
    if (ctxt->funcHash == NULL)
4856
0
  ctxt->funcHash = xmlHashCreate(0);
4857
7.97M
    if (ctxt->funcHash == NULL)
4858
0
  return(-1);
4859
7.97M
    if (f == NULL)
4860
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4861
7.97M
XML_IGNORE_FPTR_CAST_WARNINGS
4862
7.97M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4863
7.97M
XML_POP_WARNINGS
4864
7.97M
}
4865
4866
/**
4867
 * xmlXPathRegisterFuncLookup:
4868
 * @ctxt:  the XPath context
4869
 * @f:  the lookup function
4870
 * @funcCtxt:  the lookup data
4871
 *
4872
 * Registers an external mechanism to do function lookup.
4873
 */
4874
void
4875
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4876
          xmlXPathFuncLookupFunc f,
4877
0
          void *funcCtxt) {
4878
0
    if (ctxt == NULL)
4879
0
  return;
4880
0
    ctxt->funcLookupFunc = f;
4881
0
    ctxt->funcLookupData = funcCtxt;
4882
0
}
4883
4884
/**
4885
 * xmlXPathFunctionLookup:
4886
 * @ctxt:  the XPath context
4887
 * @name:  the function name
4888
 *
4889
 * Search in the Function array of the context for the given
4890
 * function.
4891
 *
4892
 * Returns the xmlXPathFunction or NULL if not found
4893
 */
4894
xmlXPathFunction
4895
3.32k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4896
3.32k
    if (ctxt == NULL)
4897
0
  return (NULL);
4898
4899
3.32k
    if (ctxt->funcLookupFunc != NULL) {
4900
0
  xmlXPathFunction ret;
4901
0
  xmlXPathFuncLookupFunc f;
4902
4903
0
  f = ctxt->funcLookupFunc;
4904
0
  ret = f(ctxt->funcLookupData, name, NULL);
4905
0
  if (ret != NULL)
4906
0
      return(ret);
4907
0
    }
4908
3.32k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4909
3.32k
}
4910
4911
/**
4912
 * xmlXPathFunctionLookupNS:
4913
 * @ctxt:  the XPath context
4914
 * @name:  the function name
4915
 * @ns_uri:  the function namespace URI
4916
 *
4917
 * Search in the Function array of the context for the given
4918
 * function.
4919
 *
4920
 * Returns the xmlXPathFunction or NULL if not found
4921
 */
4922
xmlXPathFunction
4923
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4924
3.32k
       const xmlChar *ns_uri) {
4925
3.32k
    xmlXPathFunction ret;
4926
4927
3.32k
    if (ctxt == NULL)
4928
0
  return(NULL);
4929
3.32k
    if (name == NULL)
4930
0
  return(NULL);
4931
4932
3.32k
    if (ctxt->funcLookupFunc != NULL) {
4933
0
  xmlXPathFuncLookupFunc f;
4934
4935
0
  f = ctxt->funcLookupFunc;
4936
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4937
0
  if (ret != NULL)
4938
0
      return(ret);
4939
0
    }
4940
4941
3.32k
    if (ctxt->funcHash == NULL)
4942
0
  return(NULL);
4943
4944
3.32k
XML_IGNORE_FPTR_CAST_WARNINGS
4945
3.32k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4946
3.32k
XML_POP_WARNINGS
4947
3.32k
    return(ret);
4948
3.32k
}
4949
4950
/**
4951
 * xmlXPathRegisteredFuncsCleanup:
4952
 * @ctxt:  the XPath context
4953
 *
4954
 * Cleanup the XPath context data associated to registered functions
4955
 */
4956
void
4957
284k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4958
284k
    if (ctxt == NULL)
4959
0
  return;
4960
4961
284k
    xmlHashFree(ctxt->funcHash, NULL);
4962
284k
    ctxt->funcHash = NULL;
4963
284k
}
4964
4965
/************************************************************************
4966
 *                  *
4967
 *      Routines to handle Variables      *
4968
 *                  *
4969
 ************************************************************************/
4970
4971
/**
4972
 * xmlXPathRegisterVariable:
4973
 * @ctxt:  the XPath context
4974
 * @name:  the variable name
4975
 * @value:  the variable value or NULL
4976
 *
4977
 * Register a new variable value. If @value is NULL it unregisters
4978
 * the variable
4979
 *
4980
 * Returns 0 in case of success, -1 in case of error
4981
 */
4982
int
4983
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4984
0
       xmlXPathObjectPtr value) {
4985
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4986
0
}
4987
4988
/**
4989
 * xmlXPathRegisterVariableNS:
4990
 * @ctxt:  the XPath context
4991
 * @name:  the variable name
4992
 * @ns_uri:  the variable namespace URI
4993
 * @value:  the variable value or NULL
4994
 *
4995
 * Register a new variable value. If @value is NULL it unregisters
4996
 * the variable
4997
 *
4998
 * Returns 0 in case of success, -1 in case of error
4999
 */
5000
int
5001
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5002
         const xmlChar *ns_uri,
5003
0
         xmlXPathObjectPtr value) {
5004
0
    if (ctxt == NULL)
5005
0
  return(-1);
5006
0
    if (name == NULL)
5007
0
  return(-1);
5008
5009
0
    if (ctxt->varHash == NULL)
5010
0
  ctxt->varHash = xmlHashCreate(0);
5011
0
    if (ctxt->varHash == NULL)
5012
0
  return(-1);
5013
0
    if (value == NULL)
5014
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5015
0
                             xmlXPathFreeObjectEntry));
5016
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5017
0
             (void *) value, xmlXPathFreeObjectEntry));
5018
0
}
5019
5020
/**
5021
 * xmlXPathRegisterVariableLookup:
5022
 * @ctxt:  the XPath context
5023
 * @f:  the lookup function
5024
 * @data:  the lookup data
5025
 *
5026
 * register an external mechanism to do variable lookup
5027
 */
5028
void
5029
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5030
0
   xmlXPathVariableLookupFunc f, void *data) {
5031
0
    if (ctxt == NULL)
5032
0
  return;
5033
0
    ctxt->varLookupFunc = f;
5034
0
    ctxt->varLookupData = data;
5035
0
}
5036
5037
/**
5038
 * xmlXPathVariableLookup:
5039
 * @ctxt:  the XPath context
5040
 * @name:  the variable name
5041
 *
5042
 * Search in the Variable array of the context for the given
5043
 * variable value.
5044
 *
5045
 * Returns a copy of the value or NULL if not found
5046
 */
5047
xmlXPathObjectPtr
5048
2.33k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5049
2.33k
    if (ctxt == NULL)
5050
0
  return(NULL);
5051
5052
2.33k
    if (ctxt->varLookupFunc != NULL) {
5053
0
  xmlXPathObjectPtr ret;
5054
5055
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5056
0
          (ctxt->varLookupData, name, NULL);
5057
0
  return(ret);
5058
0
    }
5059
2.33k
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5060
2.33k
}
5061
5062
/**
5063
 * xmlXPathVariableLookupNS:
5064
 * @ctxt:  the XPath context
5065
 * @name:  the variable name
5066
 * @ns_uri:  the variable namespace URI
5067
 *
5068
 * Search in the Variable array of the context for the given
5069
 * variable value.
5070
 *
5071
 * Returns the a copy of the value or NULL if not found
5072
 */
5073
xmlXPathObjectPtr
5074
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5075
2.33k
       const xmlChar *ns_uri) {
5076
2.33k
    if (ctxt == NULL)
5077
0
  return(NULL);
5078
5079
2.33k
    if (ctxt->varLookupFunc != NULL) {
5080
0
  xmlXPathObjectPtr ret;
5081
5082
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5083
0
          (ctxt->varLookupData, name, ns_uri);
5084
0
  if (ret != NULL) return(ret);
5085
0
    }
5086
5087
2.33k
    if (ctxt->varHash == NULL)
5088
2.33k
  return(NULL);
5089
0
    if (name == NULL)
5090
0
  return(NULL);
5091
5092
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5093
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5094
0
}
5095
5096
/**
5097
 * xmlXPathRegisteredVariablesCleanup:
5098
 * @ctxt:  the XPath context
5099
 *
5100
 * Cleanup the XPath context data associated to registered variables
5101
 */
5102
void
5103
284k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5104
284k
    if (ctxt == NULL)
5105
0
  return;
5106
5107
284k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5108
284k
    ctxt->varHash = NULL;
5109
284k
}
5110
5111
/**
5112
 * xmlXPathRegisterNs:
5113
 * @ctxt:  the XPath context
5114
 * @prefix:  the namespace prefix cannot be NULL or empty string
5115
 * @ns_uri:  the namespace name
5116
 *
5117
 * Register a new namespace. If @ns_uri is NULL it unregisters
5118
 * the namespace
5119
 *
5120
 * Returns 0 in case of success, -1 in case of error
5121
 */
5122
int
5123
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5124
0
         const xmlChar *ns_uri) {
5125
0
    if (ctxt == NULL)
5126
0
  return(-1);
5127
0
    if (prefix == NULL)
5128
0
  return(-1);
5129
0
    if (prefix[0] == 0)
5130
0
  return(-1);
5131
5132
0
    if (ctxt->nsHash == NULL)
5133
0
  ctxt->nsHash = xmlHashCreate(10);
5134
0
    if (ctxt->nsHash == NULL)
5135
0
  return(-1);
5136
0
    if (ns_uri == NULL)
5137
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5138
0
                            xmlHashDefaultDeallocator));
5139
0
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5140
0
            xmlHashDefaultDeallocator));
5141
0
}
5142
5143
/**
5144
 * xmlXPathNsLookup:
5145
 * @ctxt:  the XPath context
5146
 * @prefix:  the namespace prefix value
5147
 *
5148
 * Search in the namespace declaration array of the context for the given
5149
 * namespace name associated to the given prefix
5150
 *
5151
 * Returns the value or NULL if not found
5152
 */
5153
const xmlChar *
5154
4.07k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5155
4.07k
    if (ctxt == NULL)
5156
0
  return(NULL);
5157
4.07k
    if (prefix == NULL)
5158
0
  return(NULL);
5159
5160
4.07k
#ifdef XML_XML_NAMESPACE
5161
4.07k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5162
279
  return(XML_XML_NAMESPACE);
5163
3.79k
#endif
5164
5165
3.79k
    if (ctxt->namespaces != NULL) {
5166
0
  int i;
5167
5168
0
  for (i = 0;i < ctxt->nsNr;i++) {
5169
0
      if ((ctxt->namespaces[i] != NULL) &&
5170
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5171
0
    return(ctxt->namespaces[i]->href);
5172
0
  }
5173
0
    }
5174
5175
3.79k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5176
3.79k
}
5177
5178
/**
5179
 * xmlXPathRegisteredNsCleanup:
5180
 * @ctxt:  the XPath context
5181
 *
5182
 * Cleanup the XPath context data associated to registered variables
5183
 */
5184
void
5185
284k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5186
284k
    if (ctxt == NULL)
5187
0
  return;
5188
5189
284k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5190
284k
    ctxt->nsHash = NULL;
5191
284k
}
5192
5193
/************************************************************************
5194
 *                  *
5195
 *      Routines to handle Values     *
5196
 *                  *
5197
 ************************************************************************/
5198
5199
/* Allocations are terrible, one needs to optimize all this !!! */
5200
5201
/**
5202
 * xmlXPathNewFloat:
5203
 * @val:  the double value
5204
 *
5205
 * Create a new xmlXPathObjectPtr of type double and of value @val
5206
 *
5207
 * Returns the newly created object.
5208
 */
5209
xmlXPathObjectPtr
5210
720k
xmlXPathNewFloat(double val) {
5211
720k
    xmlXPathObjectPtr ret;
5212
5213
720k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5214
720k
    if (ret == NULL) {
5215
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5216
0
  return(NULL);
5217
0
    }
5218
720k
    memset(ret, 0 , sizeof(xmlXPathObject));
5219
720k
    ret->type = XPATH_NUMBER;
5220
720k
    ret->floatval = val;
5221
#ifdef XP_DEBUG_OBJ_USAGE
5222
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5223
#endif
5224
720k
    return(ret);
5225
720k
}
5226
5227
/**
5228
 * xmlXPathNewBoolean:
5229
 * @val:  the boolean value
5230
 *
5231
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5232
 *
5233
 * Returns the newly created object.
5234
 */
5235
xmlXPathObjectPtr
5236
153k
xmlXPathNewBoolean(int val) {
5237
153k
    xmlXPathObjectPtr ret;
5238
5239
153k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5240
153k
    if (ret == NULL) {
5241
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5242
0
  return(NULL);
5243
0
    }
5244
153k
    memset(ret, 0 , sizeof(xmlXPathObject));
5245
153k
    ret->type = XPATH_BOOLEAN;
5246
153k
    ret->boolval = (val != 0);
5247
#ifdef XP_DEBUG_OBJ_USAGE
5248
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5249
#endif
5250
153k
    return(ret);
5251
153k
}
5252
5253
/**
5254
 * xmlXPathNewString:
5255
 * @val:  the xmlChar * value
5256
 *
5257
 * Create a new xmlXPathObjectPtr of type string and of value @val
5258
 *
5259
 * Returns the newly created object.
5260
 */
5261
xmlXPathObjectPtr
5262
548k
xmlXPathNewString(const xmlChar *val) {
5263
548k
    xmlXPathObjectPtr ret;
5264
5265
548k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5266
548k
    if (ret == NULL) {
5267
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5268
0
  return(NULL);
5269
0
    }
5270
548k
    memset(ret, 0 , sizeof(xmlXPathObject));
5271
548k
    ret->type = XPATH_STRING;
5272
548k
    if (val != NULL)
5273
548k
  ret->stringval = xmlStrdup(val);
5274
0
    else
5275
0
  ret->stringval = xmlStrdup((const xmlChar *)"");
5276
#ifdef XP_DEBUG_OBJ_USAGE
5277
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5278
#endif
5279
548k
    return(ret);
5280
548k
}
5281
5282
/**
5283
 * xmlXPathWrapString:
5284
 * @val:  the xmlChar * value
5285
 *
5286
 * Wraps the @val string into an XPath object.
5287
 *
5288
 * Returns the newly created object.
5289
 */
5290
xmlXPathObjectPtr
5291
0
xmlXPathWrapString (xmlChar *val) {
5292
0
    xmlXPathObjectPtr ret;
5293
5294
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5295
0
    if (ret == NULL) {
5296
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5297
0
  return(NULL);
5298
0
    }
5299
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5300
0
    ret->type = XPATH_STRING;
5301
0
    ret->stringval = val;
5302
#ifdef XP_DEBUG_OBJ_USAGE
5303
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5304
#endif
5305
0
    return(ret);
5306
0
}
5307
5308
/**
5309
 * xmlXPathNewCString:
5310
 * @val:  the char * value
5311
 *
5312
 * Create a new xmlXPathObjectPtr of type string and of value @val
5313
 *
5314
 * Returns the newly created object.
5315
 */
5316
xmlXPathObjectPtr
5317
0
xmlXPathNewCString(const char *val) {
5318
0
    xmlXPathObjectPtr ret;
5319
5320
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5321
0
    if (ret == NULL) {
5322
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5323
0
  return(NULL);
5324
0
    }
5325
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5326
0
    ret->type = XPATH_STRING;
5327
0
    ret->stringval = xmlStrdup(BAD_CAST val);
5328
#ifdef XP_DEBUG_OBJ_USAGE
5329
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5330
#endif
5331
0
    return(ret);
5332
0
}
5333
5334
/**
5335
 * xmlXPathWrapCString:
5336
 * @val:  the char * value
5337
 *
5338
 * Wraps a string into an XPath object.
5339
 *
5340
 * Returns the newly created object.
5341
 */
5342
xmlXPathObjectPtr
5343
0
xmlXPathWrapCString (char * val) {
5344
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5345
0
}
5346
5347
/**
5348
 * xmlXPathWrapExternal:
5349
 * @val:  the user data
5350
 *
5351
 * Wraps the @val data into an XPath object.
5352
 *
5353
 * Returns the newly created object.
5354
 */
5355
xmlXPathObjectPtr
5356
0
xmlXPathWrapExternal (void *val) {
5357
0
    xmlXPathObjectPtr ret;
5358
5359
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5360
0
    if (ret == NULL) {
5361
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5362
0
  return(NULL);
5363
0
    }
5364
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5365
0
    ret->type = XPATH_USERS;
5366
0
    ret->user = val;
5367
#ifdef XP_DEBUG_OBJ_USAGE
5368
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5369
#endif
5370
0
    return(ret);
5371
0
}
5372
5373
/**
5374
 * xmlXPathObjectCopy:
5375
 * @val:  the original object
5376
 *
5377
 * allocate a new copy of a given object
5378
 *
5379
 * Returns the newly created object.
5380
 */
5381
xmlXPathObjectPtr
5382
539k
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5383
539k
    xmlXPathObjectPtr ret;
5384
5385
539k
    if (val == NULL)
5386
0
  return(NULL);
5387
5388
539k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5389
539k
    if (ret == NULL) {
5390
0
        xmlXPathErrMemory(NULL, "copying object\n");
5391
0
  return(NULL);
5392
0
    }
5393
539k
    memcpy(ret, val , sizeof(xmlXPathObject));
5394
#ifdef XP_DEBUG_OBJ_USAGE
5395
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5396
#endif
5397
539k
    switch (val->type) {
5398
0
  case XPATH_BOOLEAN:
5399
463k
  case XPATH_NUMBER:
5400
#ifdef LIBXML_XPTR_LOCS_ENABLED
5401
  case XPATH_POINT:
5402
  case XPATH_RANGE:
5403
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5404
463k
      break;
5405
76.0k
  case XPATH_STRING:
5406
76.0k
      ret->stringval = xmlStrdup(val->stringval);
5407
76.0k
      break;
5408
0
  case XPATH_XSLT_TREE:
5409
#if 0
5410
/*
5411
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5412
  this previous handling is no longer correct, and can cause some serious
5413
  problems (ref. bug 145547)
5414
*/
5415
      if ((val->nodesetval != NULL) &&
5416
    (val->nodesetval->nodeTab != NULL)) {
5417
    xmlNodePtr cur, tmp;
5418
    xmlDocPtr top;
5419
5420
    ret->boolval = 1;
5421
    top =  xmlNewDoc(NULL);
5422
    top->name = (char *)
5423
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5424
    ret->user = top;
5425
    if (top != NULL) {
5426
        top->doc = top;
5427
        cur = val->nodesetval->nodeTab[0]->children;
5428
        while (cur != NULL) {
5429
      tmp = xmlDocCopyNode(cur, top, 1);
5430
      xmlAddChild((xmlNodePtr) top, tmp);
5431
      cur = cur->next;
5432
        }
5433
    }
5434
5435
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5436
      } else
5437
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5438
      /* Deallocate the copied tree value */
5439
      break;
5440
#endif
5441
0
  case XPATH_NODESET:
5442
            /* TODO: Check memory error. */
5443
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5444
      /* Do not deallocate the copied tree value */
5445
0
      ret->boolval = 0;
5446
0
      break;
5447
#ifdef LIBXML_XPTR_LOCS_ENABLED
5448
  case XPATH_LOCATIONSET:
5449
  {
5450
      xmlLocationSetPtr loc = val->user;
5451
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5452
      break;
5453
  }
5454
#endif
5455
0
        case XPATH_USERS:
5456
0
      ret->user = val->user;
5457
0
      break;
5458
0
        case XPATH_UNDEFINED:
5459
0
      xmlGenericError(xmlGenericErrorContext,
5460
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5461
0
        val->type);
5462
0
      break;
5463
539k
    }
5464
539k
    return(ret);
5465
539k
}
5466
5467
/**
5468
 * xmlXPathFreeObject:
5469
 * @obj:  the object to free
5470
 *
5471
 * Free up an xmlXPathObjectPtr object.
5472
 */
5473
void
5474
3.99M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5475
3.99M
    if (obj == NULL) return;
5476
3.89M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5477
1.93M
  if (obj->boolval) {
5478
#if 0
5479
      if (obj->user != NULL) {
5480
                xmlXPathFreeNodeSet(obj->nodesetval);
5481
    xmlFreeNodeList((xmlNodePtr) obj->user);
5482
      } else
5483
#endif
5484
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5485
0
      if (obj->nodesetval != NULL)
5486
0
    xmlXPathFreeValueTree(obj->nodesetval);
5487
1.93M
  } else {
5488
1.93M
      if (obj->nodesetval != NULL)
5489
1.89M
    xmlXPathFreeNodeSet(obj->nodesetval);
5490
1.93M
  }
5491
#ifdef LIBXML_XPTR_LOCS_ENABLED
5492
    } else if (obj->type == XPATH_LOCATIONSET) {
5493
  if (obj->user != NULL)
5494
      xmlXPtrFreeLocationSet(obj->user);
5495
#endif
5496
1.96M
    } else if (obj->type == XPATH_STRING) {
5497
624k
  if (obj->stringval != NULL)
5498
624k
      xmlFree(obj->stringval);
5499
624k
    }
5500
#ifdef XP_DEBUG_OBJ_USAGE
5501
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5502
#endif
5503
3.89M
    xmlFree(obj);
5504
3.89M
}
5505
5506
static void
5507
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5508
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5509
0
}
5510
5511
/**
5512
 * xmlXPathReleaseObject:
5513
 * @obj:  the xmlXPathObjectPtr to free or to cache
5514
 *
5515
 * Depending on the state of the cache this frees the given
5516
 * XPath object or stores it in the cache.
5517
 */
5518
static void
5519
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5520
3.56M
{
5521
3.56M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5522
0
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5523
0
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5524
5525
3.56M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5526
5527
3.56M
    if (obj == NULL)
5528
0
  return;
5529
3.56M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5530
3.56M
   xmlXPathFreeObject(obj);
5531
3.56M
    } else {
5532
0
  xmlXPathContextCachePtr cache =
5533
0
      (xmlXPathContextCachePtr) ctxt->cache;
5534
5535
0
  switch (obj->type) {
5536
0
      case XPATH_NODESET:
5537
0
      case XPATH_XSLT_TREE:
5538
0
    if (obj->nodesetval != NULL) {
5539
0
        if (obj->boolval) {
5540
      /*
5541
      * It looks like the @boolval is used for
5542
      * evaluation if this an XSLT Result Tree Fragment.
5543
      * TODO: Check if this assumption is correct.
5544
      */
5545
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5546
0
      xmlXPathFreeValueTree(obj->nodesetval);
5547
0
      obj->nodesetval = NULL;
5548
0
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5549
0
      (XP_CACHE_WANTS(cache->nodesetObjs,
5550
0
          cache->maxNodeset)))
5551
0
        {
5552
0
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5553
0
      goto obj_cached;
5554
0
        } else {
5555
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5556
0
      obj->nodesetval = NULL;
5557
0
        }
5558
0
    }
5559
0
    break;
5560
0
      case XPATH_STRING:
5561
0
    if (obj->stringval != NULL)
5562
0
        xmlFree(obj->stringval);
5563
5564
0
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5565
0
        XP_CACHE_ADD(cache->stringObjs, obj);
5566
0
        goto obj_cached;
5567
0
    }
5568
0
    break;
5569
0
      case XPATH_BOOLEAN:
5570
0
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5571
0
        XP_CACHE_ADD(cache->booleanObjs, obj);
5572
0
        goto obj_cached;
5573
0
    }
5574
0
    break;
5575
0
      case XPATH_NUMBER:
5576
0
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5577
0
        XP_CACHE_ADD(cache->numberObjs, obj);
5578
0
        goto obj_cached;
5579
0
    }
5580
0
    break;
5581
#ifdef LIBXML_XPTR_LOCS_ENABLED
5582
      case XPATH_LOCATIONSET:
5583
    if (obj->user != NULL) {
5584
        xmlXPtrFreeLocationSet(obj->user);
5585
    }
5586
    goto free_obj;
5587
#endif
5588
0
      default:
5589
0
    goto free_obj;
5590
0
  }
5591
5592
  /*
5593
  * Fallback to adding to the misc-objects slot.
5594
  */
5595
0
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5596
0
      XP_CACHE_ADD(cache->miscObjs, obj);
5597
0
  } else
5598
0
      goto free_obj;
5599
5600
0
obj_cached:
5601
5602
#ifdef XP_DEBUG_OBJ_USAGE
5603
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5604
#endif
5605
5606
0
  if (obj->nodesetval != NULL) {
5607
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
5608
5609
      /*
5610
      * TODO: Due to those nasty ns-nodes, we need to traverse
5611
      *  the list and free the ns-nodes.
5612
      * URGENT TODO: Check if it's actually slowing things down.
5613
      *  Maybe we shouldn't try to preserve the list.
5614
      */
5615
0
      if (tmpset->nodeNr > 1) {
5616
0
    int i;
5617
0
    xmlNodePtr node;
5618
5619
0
    for (i = 0; i < tmpset->nodeNr; i++) {
5620
0
        node = tmpset->nodeTab[i];
5621
0
        if ((node != NULL) &&
5622
0
      (node->type == XML_NAMESPACE_DECL))
5623
0
        {
5624
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5625
0
        }
5626
0
    }
5627
0
      } else if (tmpset->nodeNr == 1) {
5628
0
    if ((tmpset->nodeTab[0] != NULL) &&
5629
0
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5630
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5631
0
      }
5632
0
      tmpset->nodeNr = 0;
5633
0
      memset(obj, 0, sizeof(xmlXPathObject));
5634
0
      obj->nodesetval = tmpset;
5635
0
  } else
5636
0
      memset(obj, 0, sizeof(xmlXPathObject));
5637
5638
0
  return;
5639
5640
0
free_obj:
5641
  /*
5642
  * Cache is full; free the object.
5643
  */
5644
0
  if (obj->nodesetval != NULL)
5645
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5646
#ifdef XP_DEBUG_OBJ_USAGE
5647
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5648
#endif
5649
0
  xmlFree(obj);
5650
0
    }
5651
3.56M
    return;
5652
3.56M
}
5653
5654
5655
/************************************************************************
5656
 *                  *
5657
 *      Type Casting Routines       *
5658
 *                  *
5659
 ************************************************************************/
5660
5661
/**
5662
 * xmlXPathCastBooleanToString:
5663
 * @val:  a boolean
5664
 *
5665
 * Converts a boolean to its string value.
5666
 *
5667
 * Returns a newly allocated string.
5668
 */
5669
xmlChar *
5670
0
xmlXPathCastBooleanToString (int val) {
5671
0
    xmlChar *ret;
5672
0
    if (val)
5673
0
  ret = xmlStrdup((const xmlChar *) "true");
5674
0
    else
5675
0
  ret = xmlStrdup((const xmlChar *) "false");
5676
0
    return(ret);
5677
0
}
5678
5679
/**
5680
 * xmlXPathCastNumberToString:
5681
 * @val:  a number
5682
 *
5683
 * Converts a number to its string value.
5684
 *
5685
 * Returns a newly allocated string.
5686
 */
5687
xmlChar *
5688
0
xmlXPathCastNumberToString (double val) {
5689
0
    xmlChar *ret;
5690
0
    switch (xmlXPathIsInf(val)) {
5691
0
    case 1:
5692
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5693
0
  break;
5694
0
    case -1:
5695
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5696
0
  break;
5697
0
    default:
5698
0
  if (xmlXPathIsNaN(val)) {
5699
0
      ret = xmlStrdup((const xmlChar *) "NaN");
5700
0
  } else if (val == 0) {
5701
            /* Omit sign for negative zero. */
5702
0
      ret = xmlStrdup((const xmlChar *) "0");
5703
0
  } else {
5704
      /* could be improved */
5705
0
      char buf[100];
5706
0
      xmlXPathFormatNumber(val, buf, 99);
5707
0
      buf[99] = 0;
5708
0
      ret = xmlStrdup((const xmlChar *) buf);
5709
0
  }
5710
0
    }
5711
0
    return(ret);
5712
0
}
5713
5714
/**
5715
 * xmlXPathCastNodeToString:
5716
 * @node:  a node
5717
 *
5718
 * Converts a node to its string value.
5719
 *
5720
 * Returns a newly allocated string.
5721
 */
5722
xmlChar *
5723
1.12M
xmlXPathCastNodeToString (xmlNodePtr node) {
5724
1.12M
xmlChar *ret;
5725
1.12M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5726
11.7k
  ret = xmlStrdup((const xmlChar *) "");
5727
1.12M
    return(ret);
5728
1.12M
}
5729
5730
/**
5731
 * xmlXPathCastNodeSetToString:
5732
 * @ns:  a node-set
5733
 *
5734
 * Converts a node-set to its string value.
5735
 *
5736
 * Returns a newly allocated string.
5737
 */
5738
xmlChar *
5739
344k
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5740
344k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5741
75.7k
  return(xmlStrdup((const xmlChar *) ""));
5742
5743
268k
    if (ns->nodeNr > 1)
5744
42.2k
  xmlXPathNodeSetSort(ns);
5745
268k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5746
344k
}
5747
5748
/**
5749
 * xmlXPathCastToString:
5750
 * @val:  an XPath object
5751
 *
5752
 * Converts an existing object to its string() equivalent
5753
 *
5754
 * Returns the allocated string value of the object, NULL in case of error.
5755
 *         It's up to the caller to free the string memory with xmlFree().
5756
 */
5757
xmlChar *
5758
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
5759
0
    xmlChar *ret = NULL;
5760
5761
0
    if (val == NULL)
5762
0
  return(xmlStrdup((const xmlChar *) ""));
5763
0
    switch (val->type) {
5764
0
  case XPATH_UNDEFINED:
5765
#ifdef DEBUG_EXPR
5766
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5767
#endif
5768
0
      ret = xmlStrdup((const xmlChar *) "");
5769
0
      break;
5770
0
        case XPATH_NODESET:
5771
0
        case XPATH_XSLT_TREE:
5772
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5773
0
      break;
5774
0
  case XPATH_STRING:
5775
0
      return(xmlStrdup(val->stringval));
5776
0
        case XPATH_BOOLEAN:
5777
0
      ret = xmlXPathCastBooleanToString(val->boolval);
5778
0
      break;
5779
0
  case XPATH_NUMBER: {
5780
0
      ret = xmlXPathCastNumberToString(val->floatval);
5781
0
      break;
5782
0
  }
5783
0
  case XPATH_USERS:
5784
#ifdef LIBXML_XPTR_LOCS_ENABLED
5785
  case XPATH_POINT:
5786
  case XPATH_RANGE:
5787
  case XPATH_LOCATIONSET:
5788
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5789
0
      TODO
5790
0
      ret = xmlStrdup((const xmlChar *) "");
5791
0
      break;
5792
0
    }
5793
0
    return(ret);
5794
0
}
5795
5796
/**
5797
 * xmlXPathConvertString:
5798
 * @val:  an XPath object
5799
 *
5800
 * Converts an existing object to its string() equivalent
5801
 *
5802
 * Returns the new object, the old one is freed (or the operation
5803
 *         is done directly on @val)
5804
 */
5805
xmlXPathObjectPtr
5806
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5807
0
    xmlChar *res = NULL;
5808
5809
0
    if (val == NULL)
5810
0
  return(xmlXPathNewCString(""));
5811
5812
0
    switch (val->type) {
5813
0
    case XPATH_UNDEFINED:
5814
#ifdef DEBUG_EXPR
5815
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5816
#endif
5817
0
  break;
5818
0
    case XPATH_NODESET:
5819
0
    case XPATH_XSLT_TREE:
5820
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5821
0
  break;
5822
0
    case XPATH_STRING:
5823
0
  return(val);
5824
0
    case XPATH_BOOLEAN:
5825
0
  res = xmlXPathCastBooleanToString(val->boolval);
5826
0
  break;
5827
0
    case XPATH_NUMBER:
5828
0
  res = xmlXPathCastNumberToString(val->floatval);
5829
0
  break;
5830
0
    case XPATH_USERS:
5831
#ifdef LIBXML_XPTR_LOCS_ENABLED
5832
    case XPATH_POINT:
5833
    case XPATH_RANGE:
5834
    case XPATH_LOCATIONSET:
5835
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5836
0
  TODO;
5837
0
  break;
5838
0
    }
5839
0
    xmlXPathFreeObject(val);
5840
0
    if (res == NULL)
5841
0
  return(xmlXPathNewCString(""));
5842
0
    return(xmlXPathWrapString(res));
5843
0
}
5844
5845
/**
5846
 * xmlXPathCastBooleanToNumber:
5847
 * @val:  a boolean
5848
 *
5849
 * Converts a boolean to its number value
5850
 *
5851
 * Returns the number value
5852
 */
5853
double
5854
8.36k
xmlXPathCastBooleanToNumber(int val) {
5855
8.36k
    if (val)
5856
1.27k
  return(1.0);
5857
7.08k
    return(0.0);
5858
8.36k
}
5859
5860
/**
5861
 * xmlXPathCastStringToNumber:
5862
 * @val:  a string
5863
 *
5864
 * Converts a string to its number value
5865
 *
5866
 * Returns the number value
5867
 */
5868
double
5869
1.26M
xmlXPathCastStringToNumber(const xmlChar * val) {
5870
1.26M
    return(xmlXPathStringEvalNumber(val));
5871
1.26M
}
5872
5873
/**
5874
 * xmlXPathCastNodeToNumber:
5875
 * @node:  a node
5876
 *
5877
 * Converts a node to its number value
5878
 *
5879
 * Returns the number value
5880
 */
5881
double
5882
358k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5883
358k
    xmlChar *strval;
5884
358k
    double ret;
5885
5886
358k
    if (node == NULL)
5887
0
  return(xmlXPathNAN);
5888
358k
    strval = xmlXPathCastNodeToString(node);
5889
358k
    if (strval == NULL)
5890
0
  return(xmlXPathNAN);
5891
358k
    ret = xmlXPathCastStringToNumber(strval);
5892
358k
    xmlFree(strval);
5893
5894
358k
    return(ret);
5895
358k
}
5896
5897
/**
5898
 * xmlXPathCastNodeSetToNumber:
5899
 * @ns:  a node-set
5900
 *
5901
 * Converts a node-set to its number value
5902
 *
5903
 * Returns the number value
5904
 */
5905
double
5906
348k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5907
348k
    xmlChar *str;
5908
348k
    double ret;
5909
5910
348k
    if (ns == NULL)
5911
4.54k
  return(xmlXPathNAN);
5912
344k
    str = xmlXPathCastNodeSetToString(ns);
5913
344k
    ret = xmlXPathCastStringToNumber(str);
5914
344k
    xmlFree(str);
5915
344k
    return(ret);
5916
348k
}
5917
5918
/**
5919
 * xmlXPathCastToNumber:
5920
 * @val:  an XPath object
5921
 *
5922
 * Converts an XPath object to its number value
5923
 *
5924
 * Returns the number value
5925
 */
5926
double
5927
969k
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5928
969k
    double ret = 0.0;
5929
5930
969k
    if (val == NULL)
5931
0
  return(xmlXPathNAN);
5932
969k
    switch (val->type) {
5933
0
    case XPATH_UNDEFINED:
5934
#ifdef DEBUG_EXPR
5935
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5936
#endif
5937
0
  ret = xmlXPathNAN;
5938
0
  break;
5939
348k
    case XPATH_NODESET:
5940
348k
    case XPATH_XSLT_TREE:
5941
348k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5942
348k
  break;
5943
565k
    case XPATH_STRING:
5944
565k
  ret = xmlXPathCastStringToNumber(val->stringval);
5945
565k
  break;
5946
47.1k
    case XPATH_NUMBER:
5947
47.1k
  ret = val->floatval;
5948
47.1k
  break;
5949
8.36k
    case XPATH_BOOLEAN:
5950
8.36k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5951
8.36k
  break;
5952
0
    case XPATH_USERS:
5953
#ifdef LIBXML_XPTR_LOCS_ENABLED
5954
    case XPATH_POINT:
5955
    case XPATH_RANGE:
5956
    case XPATH_LOCATIONSET:
5957
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5958
0
  TODO;
5959
0
  ret = xmlXPathNAN;
5960
0
  break;
5961
969k
    }
5962
969k
    return(ret);
5963
969k
}
5964
5965
/**
5966
 * xmlXPathConvertNumber:
5967
 * @val:  an XPath object
5968
 *
5969
 * Converts an existing object to its number() equivalent
5970
 *
5971
 * Returns the new object, the old one is freed (or the operation
5972
 *         is done directly on @val)
5973
 */
5974
xmlXPathObjectPtr
5975
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5976
0
    xmlXPathObjectPtr ret;
5977
5978
0
    if (val == NULL)
5979
0
  return(xmlXPathNewFloat(0.0));
5980
0
    if (val->type == XPATH_NUMBER)
5981
0
  return(val);
5982
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5983
0
    xmlXPathFreeObject(val);
5984
0
    return(ret);
5985
0
}
5986
5987
/**
5988
 * xmlXPathCastNumberToBoolean:
5989
 * @val:  a number
5990
 *
5991
 * Converts a number to its boolean value
5992
 *
5993
 * Returns the boolean value
5994
 */
5995
int
5996
14.8k
xmlXPathCastNumberToBoolean (double val) {
5997
14.8k
     if (xmlXPathIsNaN(val) || (val == 0.0))
5998
12.0k
   return(0);
5999
2.81k
     return(1);
6000
14.8k
}
6001
6002
/**
6003
 * xmlXPathCastStringToBoolean:
6004
 * @val:  a string
6005
 *
6006
 * Converts a string to its boolean value
6007
 *
6008
 * Returns the boolean value
6009
 */
6010
int
6011
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
6012
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
6013
0
  return(0);
6014
0
    return(1);
6015
0
}
6016
6017
/**
6018
 * xmlXPathCastNodeSetToBoolean:
6019
 * @ns:  a node-set
6020
 *
6021
 * Converts a node-set to its boolean value
6022
 *
6023
 * Returns the boolean value
6024
 */
6025
int
6026
9.71k
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6027
9.71k
    if ((ns == NULL) || (ns->nodeNr == 0))
6028
8.07k
  return(0);
6029
1.64k
    return(1);
6030
9.71k
}
6031
6032
/**
6033
 * xmlXPathCastToBoolean:
6034
 * @val:  an XPath object
6035
 *
6036
 * Converts an XPath object to its boolean value
6037
 *
6038
 * Returns the boolean value
6039
 */
6040
int
6041
14.8k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6042
14.8k
    int ret = 0;
6043
6044
14.8k
    if (val == NULL)
6045
0
  return(0);
6046
14.8k
    switch (val->type) {
6047
0
    case XPATH_UNDEFINED:
6048
#ifdef DEBUG_EXPR
6049
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6050
#endif
6051
0
  ret = 0;
6052
0
  break;
6053
9.71k
    case XPATH_NODESET:
6054
9.71k
    case XPATH_XSLT_TREE:
6055
9.71k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6056
9.71k
  break;
6057
0
    case XPATH_STRING:
6058
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
6059
0
  break;
6060
5.12k
    case XPATH_NUMBER:
6061
5.12k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6062
5.12k
  break;
6063
0
    case XPATH_BOOLEAN:
6064
0
  ret = val->boolval;
6065
0
  break;
6066
0
    case XPATH_USERS:
6067
#ifdef LIBXML_XPTR_LOCS_ENABLED
6068
    case XPATH_POINT:
6069
    case XPATH_RANGE:
6070
    case XPATH_LOCATIONSET:
6071
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6072
0
  TODO;
6073
0
  ret = 0;
6074
0
  break;
6075
14.8k
    }
6076
14.8k
    return(ret);
6077
14.8k
}
6078
6079
6080
/**
6081
 * xmlXPathConvertBoolean:
6082
 * @val:  an XPath object
6083
 *
6084
 * Converts an existing object to its boolean() equivalent
6085
 *
6086
 * Returns the new object, the old one is freed (or the operation
6087
 *         is done directly on @val)
6088
 */
6089
xmlXPathObjectPtr
6090
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6091
0
    xmlXPathObjectPtr ret;
6092
6093
0
    if (val == NULL)
6094
0
  return(xmlXPathNewBoolean(0));
6095
0
    if (val->type == XPATH_BOOLEAN)
6096
0
  return(val);
6097
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6098
0
    xmlXPathFreeObject(val);
6099
0
    return(ret);
6100
0
}
6101
6102
/************************************************************************
6103
 *                  *
6104
 *    Routines to handle XPath contexts     *
6105
 *                  *
6106
 ************************************************************************/
6107
6108
/**
6109
 * xmlXPathNewContext:
6110
 * @doc:  the XML document
6111
 *
6112
 * Create a new xmlXPathContext
6113
 *
6114
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6115
 */
6116
xmlXPathContextPtr
6117
284k
xmlXPathNewContext(xmlDocPtr doc) {
6118
284k
    xmlXPathContextPtr ret;
6119
6120
284k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6121
284k
    if (ret == NULL) {
6122
0
        xmlXPathErrMemory(NULL, "creating context\n");
6123
0
  return(NULL);
6124
0
    }
6125
284k
    memset(ret, 0 , sizeof(xmlXPathContext));
6126
284k
    ret->doc = doc;
6127
284k
    ret->node = NULL;
6128
6129
284k
    ret->varHash = NULL;
6130
6131
284k
    ret->nb_types = 0;
6132
284k
    ret->max_types = 0;
6133
284k
    ret->types = NULL;
6134
6135
284k
    ret->funcHash = xmlHashCreate(0);
6136
6137
284k
    ret->nb_axis = 0;
6138
284k
    ret->max_axis = 0;
6139
284k
    ret->axis = NULL;
6140
6141
284k
    ret->nsHash = NULL;
6142
284k
    ret->user = NULL;
6143
6144
284k
    ret->contextSize = -1;
6145
284k
    ret->proximityPosition = -1;
6146
6147
#ifdef XP_DEFAULT_CACHE_ON
6148
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6149
  xmlXPathFreeContext(ret);
6150
  return(NULL);
6151
    }
6152
#endif
6153
6154
284k
    xmlXPathRegisterAllFunctions(ret);
6155
6156
284k
    return(ret);
6157
284k
}
6158
6159
/**
6160
 * xmlXPathFreeContext:
6161
 * @ctxt:  the context to free
6162
 *
6163
 * Free up an xmlXPathContext
6164
 */
6165
void
6166
284k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6167
284k
    if (ctxt == NULL) return;
6168
6169
284k
    if (ctxt->cache != NULL)
6170
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6171
284k
    xmlXPathRegisteredNsCleanup(ctxt);
6172
284k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6173
284k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6174
284k
    xmlResetError(&ctxt->lastError);
6175
284k
    xmlFree(ctxt);
6176
284k
}
6177
6178
/************************************************************************
6179
 *                  *
6180
 *    Routines to handle XPath parser contexts    *
6181
 *                  *
6182
 ************************************************************************/
6183
6184
#define CHECK_CTXT(ctxt)            \
6185
0
    if (ctxt == NULL) {           \
6186
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6187
0
    NULL, NULL, XML_FROM_XPATH,       \
6188
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6189
0
    __FILE__, __LINE__,         \
6190
0
    NULL, NULL, NULL, 0, 0,         \
6191
0
    "NULL context pointer\n");        \
6192
0
  return(NULL);             \
6193
0
    }                  \
6194
6195
#define CHECK_CTXT_NEG(ctxt)            \
6196
0
    if (ctxt == NULL) {           \
6197
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6198
0
    NULL, NULL, XML_FROM_XPATH,       \
6199
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6200
0
    __FILE__, __LINE__,         \
6201
0
    NULL, NULL, NULL, 0, 0,         \
6202
0
    "NULL context pointer\n");        \
6203
0
  return(-1);             \
6204
0
    }                  \
6205
6206
6207
#define CHECK_CONTEXT(ctxt)           \
6208
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6209
        (ctxt->doc->children == NULL)) {        \
6210
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6211
  return(NULL);             \
6212
    }
6213
6214
6215
/**
6216
 * xmlXPathNewParserContext:
6217
 * @str:  the XPath expression
6218
 * @ctxt:  the XPath context
6219
 *
6220
 * Create a new xmlXPathParserContext
6221
 *
6222
 * Returns the xmlXPathParserContext just allocated.
6223
 */
6224
xmlXPathParserContextPtr
6225
284k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6226
284k
    xmlXPathParserContextPtr ret;
6227
6228
284k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6229
284k
    if (ret == NULL) {
6230
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6231
0
  return(NULL);
6232
0
    }
6233
284k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6234
284k
    ret->cur = ret->base = str;
6235
284k
    ret->context = ctxt;
6236
6237
284k
    ret->comp = xmlXPathNewCompExpr();
6238
284k
    if (ret->comp == NULL) {
6239
0
  xmlFree(ret->valueTab);
6240
0
  xmlFree(ret);
6241
0
  return(NULL);
6242
0
    }
6243
284k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6244
0
        ret->comp->dict = ctxt->dict;
6245
0
  xmlDictReference(ret->comp->dict);
6246
0
    }
6247
6248
284k
    return(ret);
6249
284k
}
6250
6251
/**
6252
 * xmlXPathCompParserContext:
6253
 * @comp:  the XPath compiled expression
6254
 * @ctxt:  the XPath context
6255
 *
6256
 * Create a new xmlXPathParserContext when processing a compiled expression
6257
 *
6258
 * Returns the xmlXPathParserContext just allocated.
6259
 */
6260
static xmlXPathParserContextPtr
6261
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6262
0
    xmlXPathParserContextPtr ret;
6263
6264
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6265
0
    if (ret == NULL) {
6266
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6267
0
  return(NULL);
6268
0
    }
6269
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6270
6271
    /* Allocate the value stack */
6272
0
    ret->valueTab = (xmlXPathObjectPtr *)
6273
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6274
0
    if (ret->valueTab == NULL) {
6275
0
  xmlFree(ret);
6276
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6277
0
  return(NULL);
6278
0
    }
6279
0
    ret->valueNr = 0;
6280
0
    ret->valueMax = 10;
6281
0
    ret->value = NULL;
6282
0
    ret->valueFrame = 0;
6283
6284
0
    ret->context = ctxt;
6285
0
    ret->comp = comp;
6286
6287
0
    return(ret);
6288
0
}
6289
6290
/**
6291
 * xmlXPathFreeParserContext:
6292
 * @ctxt:  the context to free
6293
 *
6294
 * Free up an xmlXPathParserContext
6295
 */
6296
void
6297
284k
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6298
284k
    int i;
6299
6300
284k
    if (ctxt->valueTab != NULL) {
6301
287k
        for (i = 0; i < ctxt->valueNr; i++) {
6302
2.77k
            if (ctxt->context)
6303
2.77k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6304
0
            else
6305
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6306
2.77k
        }
6307
284k
        xmlFree(ctxt->valueTab);
6308
284k
    }
6309
284k
    if (ctxt->comp != NULL) {
6310
284k
#ifdef XPATH_STREAMING
6311
284k
  if (ctxt->comp->stream != NULL) {
6312
43.9k
      xmlFreePatternList(ctxt->comp->stream);
6313
43.9k
      ctxt->comp->stream = NULL;
6314
43.9k
  }
6315
284k
#endif
6316
284k
  xmlXPathFreeCompExpr(ctxt->comp);
6317
284k
    }
6318
284k
    xmlFree(ctxt);
6319
284k
}
6320
6321
/************************************************************************
6322
 *                  *
6323
 *    The implicit core function library      *
6324
 *                  *
6325
 ************************************************************************/
6326
6327
/**
6328
 * xmlXPathNodeValHash:
6329
 * @node:  a node pointer
6330
 *
6331
 * Function computing the beginning of the string value of the node,
6332
 * used to speed up comparisons
6333
 *
6334
 * Returns an int usable as a hash
6335
 */
6336
static unsigned int
6337
114k
xmlXPathNodeValHash(xmlNodePtr node) {
6338
114k
    int len = 2;
6339
114k
    const xmlChar * string = NULL;
6340
114k
    xmlNodePtr tmp = NULL;
6341
114k
    unsigned int ret = 0;
6342
6343
114k
    if (node == NULL)
6344
0
  return(0);
6345
6346
114k
    if (node->type == XML_DOCUMENT_NODE) {
6347
11.4k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6348
11.4k
  if (tmp == NULL)
6349
0
      node = node->children;
6350
11.4k
  else
6351
11.4k
      node = tmp;
6352
6353
11.4k
  if (node == NULL)
6354
0
      return(0);
6355
11.4k
    }
6356
6357
114k
    switch (node->type) {
6358
978
  case XML_COMMENT_NODE:
6359
1.21k
  case XML_PI_NODE:
6360
1.35k
  case XML_CDATA_SECTION_NODE:
6361
24.1k
  case XML_TEXT_NODE:
6362
24.1k
      string = node->content;
6363
24.1k
      if (string == NULL)
6364
143
    return(0);
6365
24.0k
      if (string[0] == 0)
6366
32
    return(0);
6367
23.9k
      return(string[0] + (string[1] << 8));
6368
0
  case XML_NAMESPACE_DECL:
6369
0
      string = ((xmlNsPtr)node)->href;
6370
0
      if (string == NULL)
6371
0
    return(0);
6372
0
      if (string[0] == 0)
6373
0
    return(0);
6374
0
      return(string[0] + (string[1] << 8));
6375
7.71k
  case XML_ATTRIBUTE_NODE:
6376
7.71k
      tmp = ((xmlAttrPtr) node)->children;
6377
7.71k
      break;
6378
83.0k
  case XML_ELEMENT_NODE:
6379
83.0k
      tmp = node->children;
6380
83.0k
      break;
6381
0
  default:
6382
0
      return(0);
6383
114k
    }
6384
136k
    while (tmp != NULL) {
6385
91.5k
  switch (tmp->type) {
6386
76
      case XML_CDATA_SECTION_NODE:
6387
52.1k
      case XML_TEXT_NODE:
6388
52.1k
    string = tmp->content;
6389
52.1k
    break;
6390
39.4k
      default:
6391
39.4k
                string = NULL;
6392
39.4k
    break;
6393
91.5k
  }
6394
91.5k
  if ((string != NULL) && (string[0] != 0)) {
6395
51.9k
      if (len == 1) {
6396
3.37k
    return(ret + (string[0] << 8));
6397
3.37k
      }
6398
48.5k
      if (string[1] == 0) {
6399
6.09k
    len = 1;
6400
6.09k
    ret = string[0];
6401
42.4k
      } else {
6402
42.4k
    return(string[0] + (string[1] << 8));
6403
42.4k
      }
6404
48.5k
  }
6405
  /*
6406
   * Skip to next node
6407
   */
6408
45.7k
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6409
15.3k
      if (tmp->children->type != XML_ENTITY_DECL) {
6410
15.2k
    tmp = tmp->children;
6411
15.2k
    continue;
6412
15.2k
      }
6413
15.3k
  }
6414
30.4k
  if (tmp == node)
6415
0
      break;
6416
6417
30.4k
  if (tmp->next != NULL) {
6418
25.3k
      tmp = tmp->next;
6419
25.3k
      continue;
6420
25.3k
  }
6421
6422
6.85k
  do {
6423
6.85k
      tmp = tmp->parent;
6424
6.85k
      if (tmp == NULL)
6425
0
    break;
6426
6.85k
      if (tmp == node) {
6427
3.98k
    tmp = NULL;
6428
3.98k
    break;
6429
3.98k
      }
6430
2.86k
      if (tmp->next != NULL) {
6431
1.11k
    tmp = tmp->next;
6432
1.11k
    break;
6433
1.11k
      }
6434
2.86k
  } while (tmp != NULL);
6435
5.09k
    }
6436
44.9k
    return(ret);
6437
90.7k
}
6438
6439
/**
6440
 * xmlXPathStringHash:
6441
 * @string:  a string
6442
 *
6443
 * Function computing the beginning of the string value of the node,
6444
 * used to speed up comparisons
6445
 *
6446
 * Returns an int usable as a hash
6447
 */
6448
static unsigned int
6449
1.55k
xmlXPathStringHash(const xmlChar * string) {
6450
1.55k
    if (string == NULL)
6451
0
  return(0);
6452
1.55k
    if (string[0] == 0)
6453
222
  return(0);
6454
1.33k
    return(string[0] + (string[1] << 8));
6455
1.55k
}
6456
6457
/**
6458
 * xmlXPathCompareNodeSetFloat:
6459
 * @ctxt:  the XPath Parser context
6460
 * @inf:  less than (1) or greater than (0)
6461
 * @strict:  is the comparison strict
6462
 * @arg:  the node set
6463
 * @f:  the value
6464
 *
6465
 * Implement the compare operation between a nodeset and a number
6466
 *     @ns < @val    (1, 1, ...
6467
 *     @ns <= @val   (1, 0, ...
6468
 *     @ns > @val    (0, 1, ...
6469
 *     @ns >= @val   (0, 0, ...
6470
 *
6471
 * If one object to be compared is a node-set and the other is a number,
6472
 * then the comparison will be true if and only if there is a node in the
6473
 * node-set such that the result of performing the comparison on the number
6474
 * to be compared and on the result of converting the string-value of that
6475
 * node to a number using the number function is true.
6476
 *
6477
 * Returns 0 or 1 depending on the results of the test.
6478
 */
6479
static int
6480
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6481
9.66k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6482
9.66k
    int i, ret = 0;
6483
9.66k
    xmlNodeSetPtr ns;
6484
9.66k
    xmlChar *str2;
6485
6486
9.66k
    if ((f == NULL) || (arg == NULL) ||
6487
9.66k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6488
0
  xmlXPathReleaseObject(ctxt->context, arg);
6489
0
  xmlXPathReleaseObject(ctxt->context, f);
6490
0
        return(0);
6491
0
    }
6492
9.66k
    ns = arg->nodesetval;
6493
9.66k
    if (ns != NULL) {
6494
350k
  for (i = 0;i < ns->nodeNr;i++) {
6495
341k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6496
341k
       if (str2 != NULL) {
6497
341k
     valuePush(ctxt,
6498
341k
         xmlXPathCacheNewString(ctxt->context, str2));
6499
341k
     xmlFree(str2);
6500
341k
     xmlXPathNumberFunction(ctxt, 1);
6501
341k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6502
341k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6503
341k
     if (ret)
6504
736
         break;
6505
341k
       }
6506
341k
  }
6507
9.33k
    }
6508
9.66k
    xmlXPathReleaseObject(ctxt->context, arg);
6509
9.66k
    xmlXPathReleaseObject(ctxt->context, f);
6510
9.66k
    return(ret);
6511
9.66k
}
6512
6513
/**
6514
 * xmlXPathCompareNodeSetString:
6515
 * @ctxt:  the XPath Parser context
6516
 * @inf:  less than (1) or greater than (0)
6517
 * @strict:  is the comparison strict
6518
 * @arg:  the node set
6519
 * @s:  the value
6520
 *
6521
 * Implement the compare operation between a nodeset and a string
6522
 *     @ns < @val    (1, 1, ...
6523
 *     @ns <= @val   (1, 0, ...
6524
 *     @ns > @val    (0, 1, ...
6525
 *     @ns >= @val   (0, 0, ...
6526
 *
6527
 * If one object to be compared is a node-set and the other is a string,
6528
 * then the comparison will be true if and only if there is a node in
6529
 * the node-set such that the result of performing the comparison on the
6530
 * string-value of the node and the other string is true.
6531
 *
6532
 * Returns 0 or 1 depending on the results of the test.
6533
 */
6534
static int
6535
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6536
1.92k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6537
1.92k
    int i, ret = 0;
6538
1.92k
    xmlNodeSetPtr ns;
6539
1.92k
    xmlChar *str2;
6540
6541
1.92k
    if ((s == NULL) || (arg == NULL) ||
6542
1.92k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6543
0
  xmlXPathReleaseObject(ctxt->context, arg);
6544
0
  xmlXPathReleaseObject(ctxt->context, s);
6545
0
        return(0);
6546
0
    }
6547
1.92k
    ns = arg->nodesetval;
6548
1.92k
    if (ns != NULL) {
6549
35.7k
  for (i = 0;i < ns->nodeNr;i++) {
6550
33.8k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6551
33.8k
       if (str2 != NULL) {
6552
33.8k
     valuePush(ctxt,
6553
33.8k
         xmlXPathCacheNewString(ctxt->context, str2));
6554
33.8k
     xmlFree(str2);
6555
33.8k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6556
33.8k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6557
33.8k
     if (ret)
6558
0
         break;
6559
33.8k
       }
6560
33.8k
  }
6561
1.91k
    }
6562
1.92k
    xmlXPathReleaseObject(ctxt->context, arg);
6563
1.92k
    xmlXPathReleaseObject(ctxt->context, s);
6564
1.92k
    return(ret);
6565
1.92k
}
6566
6567
/**
6568
 * xmlXPathCompareNodeSets:
6569
 * @inf:  less than (1) or greater than (0)
6570
 * @strict:  is the comparison strict
6571
 * @arg1:  the first node set object
6572
 * @arg2:  the second node set object
6573
 *
6574
 * Implement the compare operation on nodesets:
6575
 *
6576
 * If both objects to be compared are node-sets, then the comparison
6577
 * will be true if and only if there is a node in the first node-set
6578
 * and a node in the second node-set such that the result of performing
6579
 * the comparison on the string-values of the two nodes is true.
6580
 * ....
6581
 * When neither object to be compared is a node-set and the operator
6582
 * is <=, <, >= or >, then the objects are compared by converting both
6583
 * objects to numbers and comparing the numbers according to IEEE 754.
6584
 * ....
6585
 * The number function converts its argument to a number as follows:
6586
 *  - a string that consists of optional whitespace followed by an
6587
 *    optional minus sign followed by a Number followed by whitespace
6588
 *    is converted to the IEEE 754 number that is nearest (according
6589
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6590
 *    represented by the string; any other string is converted to NaN
6591
 *
6592
 * Conclusion all nodes need to be converted first to their string value
6593
 * and then the comparison must be done when possible
6594
 */
6595
static int
6596
xmlXPathCompareNodeSets(int inf, int strict,
6597
7.96k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6598
7.96k
    int i, j, init = 0;
6599
7.96k
    double val1;
6600
7.96k
    double *values2;
6601
7.96k
    int ret = 0;
6602
7.96k
    xmlNodeSetPtr ns1;
6603
7.96k
    xmlNodeSetPtr ns2;
6604
6605
7.96k
    if ((arg1 == NULL) ||
6606
7.96k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6607
0
  xmlXPathFreeObject(arg2);
6608
0
        return(0);
6609
0
    }
6610
7.96k
    if ((arg2 == NULL) ||
6611
7.96k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6612
0
  xmlXPathFreeObject(arg1);
6613
0
  xmlXPathFreeObject(arg2);
6614
0
        return(0);
6615
0
    }
6616
6617
7.96k
    ns1 = arg1->nodesetval;
6618
7.96k
    ns2 = arg2->nodesetval;
6619
6620
7.96k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6621
1.98k
  xmlXPathFreeObject(arg1);
6622
1.98k
  xmlXPathFreeObject(arg2);
6623
1.98k
  return(0);
6624
1.98k
    }
6625
5.97k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6626
1.41k
  xmlXPathFreeObject(arg1);
6627
1.41k
  xmlXPathFreeObject(arg2);
6628
1.41k
  return(0);
6629
1.41k
    }
6630
6631
4.56k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6632
4.56k
    if (values2 == NULL) {
6633
        /* TODO: Propagate memory error. */
6634
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6635
0
  xmlXPathFreeObject(arg1);
6636
0
  xmlXPathFreeObject(arg2);
6637
0
  return(0);
6638
0
    }
6639
324k
    for (i = 0;i < ns1->nodeNr;i++) {
6640
319k
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6641
319k
  if (xmlXPathIsNaN(val1))
6642
314k
      continue;
6643
108k
  for (j = 0;j < ns2->nodeNr;j++) {
6644
103k
      if (init == 0) {
6645
38.9k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6646
38.9k
      }
6647
103k
      if (xmlXPathIsNaN(values2[j]))
6648
98.1k
    continue;
6649
4.84k
      if (inf && strict)
6650
4.02k
    ret = (val1 < values2[j]);
6651
819
      else if (inf && !strict)
6652
0
    ret = (val1 <= values2[j]);
6653
819
      else if (!inf && strict)
6654
783
    ret = (val1 > values2[j]);
6655
36
      else if (!inf && !strict)
6656
36
    ret = (val1 >= values2[j]);
6657
4.84k
      if (ret)
6658
125
    break;
6659
4.84k
  }
6660
5.20k
  if (ret)
6661
125
      break;
6662
5.08k
  init = 1;
6663
5.08k
    }
6664
4.56k
    xmlFree(values2);
6665
4.56k
    xmlXPathFreeObject(arg1);
6666
4.56k
    xmlXPathFreeObject(arg2);
6667
4.56k
    return(ret);
6668
4.56k
}
6669
6670
/**
6671
 * xmlXPathCompareNodeSetValue:
6672
 * @ctxt:  the XPath Parser context
6673
 * @inf:  less than (1) or greater than (0)
6674
 * @strict:  is the comparison strict
6675
 * @arg:  the node set
6676
 * @val:  the value
6677
 *
6678
 * Implement the compare operation between a nodeset and a value
6679
 *     @ns < @val    (1, 1, ...
6680
 *     @ns <= @val   (1, 0, ...
6681
 *     @ns > @val    (0, 1, ...
6682
 *     @ns >= @val   (0, 0, ...
6683
 *
6684
 * If one object to be compared is a node-set and the other is a boolean,
6685
 * then the comparison will be true if and only if the result of performing
6686
 * the comparison on the boolean and on the result of converting
6687
 * the node-set to a boolean using the boolean function is true.
6688
 *
6689
 * Returns 0 or 1 depending on the results of the test.
6690
 */
6691
static int
6692
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6693
14.5k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6694
14.5k
    if ((val == NULL) || (arg == NULL) ||
6695
14.5k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6696
0
        return(0);
6697
6698
14.5k
    switch(val->type) {
6699
9.66k
        case XPATH_NUMBER:
6700
9.66k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6701
0
        case XPATH_NODESET:
6702
0
        case XPATH_XSLT_TREE:
6703
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6704
1.92k
        case XPATH_STRING:
6705
1.92k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6706
2.95k
        case XPATH_BOOLEAN:
6707
2.95k
      valuePush(ctxt, arg);
6708
2.95k
      xmlXPathBooleanFunction(ctxt, 1);
6709
2.95k
      valuePush(ctxt, val);
6710
2.95k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6711
0
  default:
6712
0
            xmlGenericError(xmlGenericErrorContext,
6713
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6714
0
                    "and object of type %d\n",
6715
0
                    val->type);
6716
0
            xmlXPathReleaseObject(ctxt->context, arg);
6717
0
            xmlXPathReleaseObject(ctxt->context, val);
6718
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6719
14.5k
    }
6720
0
    return(0);
6721
14.5k
}
6722
6723
/**
6724
 * xmlXPathEqualNodeSetString:
6725
 * @arg:  the nodeset object argument
6726
 * @str:  the string to compare to.
6727
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6728
 *
6729
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6730
 * If one object to be compared is a node-set and the other is a string,
6731
 * then the comparison will be true if and only if there is a node in
6732
 * the node-set such that the result of performing the comparison on the
6733
 * string-value of the node and the other string is true.
6734
 *
6735
 * Returns 0 or 1 depending on the results of the test.
6736
 */
6737
static int
6738
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6739
4.33k
{
6740
4.33k
    int i;
6741
4.33k
    xmlNodeSetPtr ns;
6742
4.33k
    xmlChar *str2;
6743
4.33k
    unsigned int hash;
6744
6745
4.33k
    if ((str == NULL) || (arg == NULL) ||
6746
4.33k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6747
0
        return (0);
6748
4.33k
    ns = arg->nodesetval;
6749
    /*
6750
     * A NULL nodeset compared with a string is always false
6751
     * (since there is no node equal, and no node not equal)
6752
     */
6753
4.33k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6754
2.77k
        return (0);
6755
1.55k
    hash = xmlXPathStringHash(str);
6756
33.1k
    for (i = 0; i < ns->nodeNr; i++) {
6757
31.9k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6758
135
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6759
135
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6760
78
                xmlFree(str2);
6761
78
    if (neq)
6762
36
        continue;
6763
42
                return (1);
6764
78
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6765
22
    if (neq)
6766
0
        continue;
6767
22
                return (1);
6768
35
            } else if (neq) {
6769
0
    if (str2 != NULL)
6770
0
        xmlFree(str2);
6771
0
    return (1);
6772
0
      }
6773
35
            if (str2 != NULL)
6774
35
                xmlFree(str2);
6775
31.8k
        } else if (neq)
6776
245
      return (1);
6777
31.9k
    }
6778
1.24k
    return (0);
6779
1.55k
}
6780
6781
/**
6782
 * xmlXPathEqualNodeSetFloat:
6783
 * @arg:  the nodeset object argument
6784
 * @f:  the float to compare to
6785
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6786
 *
6787
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6788
 * If one object to be compared is a node-set and the other is a number,
6789
 * then the comparison will be true if and only if there is a node in
6790
 * the node-set such that the result of performing the comparison on the
6791
 * number to be compared and on the result of converting the string-value
6792
 * of that node to a number using the number function is true.
6793
 *
6794
 * Returns 0 or 1 depending on the results of the test.
6795
 */
6796
static int
6797
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6798
17.3k
    xmlXPathObjectPtr arg, double f, int neq) {
6799
17.3k
  int i, ret=0;
6800
17.3k
  xmlNodeSetPtr ns;
6801
17.3k
  xmlChar *str2;
6802
17.3k
  xmlXPathObjectPtr val;
6803
17.3k
  double v;
6804
6805
17.3k
    if ((arg == NULL) ||
6806
17.3k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6807
0
        return(0);
6808
6809
17.3k
    ns = arg->nodesetval;
6810
17.3k
    if (ns != NULL) {
6811
138k
  for (i=0;i<ns->nodeNr;i++) {
6812
121k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6813
121k
      if (str2 != NULL) {
6814
121k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6815
121k
    xmlFree(str2);
6816
121k
    xmlXPathNumberFunction(ctxt, 1);
6817
121k
    val = valuePop(ctxt);
6818
121k
    v = val->floatval;
6819
121k
    xmlXPathReleaseObject(ctxt->context, val);
6820
121k
    if (!xmlXPathIsNaN(v)) {
6821
2.29k
        if ((!neq) && (v==f)) {
6822
34
      ret = 1;
6823
34
      break;
6824
2.25k
        } else if ((neq) && (v!=f)) {
6825
41
      ret = 1;
6826
41
      break;
6827
41
        }
6828
119k
    } else { /* NaN is unequal to any value */
6829
119k
        if (neq)
6830
1.18k
      ret = 1;
6831
119k
    }
6832
121k
      }
6833
121k
  }
6834
16.6k
    }
6835
6836
17.3k
    return(ret);
6837
17.3k
}
6838
6839
6840
/**
6841
 * xmlXPathEqualNodeSets:
6842
 * @arg1:  first nodeset object argument
6843
 * @arg2:  second nodeset object argument
6844
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6845
 *
6846
 * Implement the equal / not equal operation on XPath nodesets:
6847
 * @arg1 == @arg2  or  @arg1 != @arg2
6848
 * If both objects to be compared are node-sets, then the comparison
6849
 * will be true if and only if there is a node in the first node-set and
6850
 * a node in the second node-set such that the result of performing the
6851
 * comparison on the string-values of the two nodes is true.
6852
 *
6853
 * (needless to say, this is a costly operation)
6854
 *
6855
 * Returns 0 or 1 depending on the results of the test.
6856
 */
6857
static int
6858
26.1k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6859
26.1k
    int i, j;
6860
26.1k
    unsigned int *hashs1;
6861
26.1k
    unsigned int *hashs2;
6862
26.1k
    xmlChar **values1;
6863
26.1k
    xmlChar **values2;
6864
26.1k
    int ret = 0;
6865
26.1k
    xmlNodeSetPtr ns1;
6866
26.1k
    xmlNodeSetPtr ns2;
6867
6868
26.1k
    if ((arg1 == NULL) ||
6869
26.1k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6870
0
        return(0);
6871
26.1k
    if ((arg2 == NULL) ||
6872
26.1k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6873
0
        return(0);
6874
6875
26.1k
    ns1 = arg1->nodesetval;
6876
26.1k
    ns2 = arg2->nodesetval;
6877
6878
26.1k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6879
11.4k
  return(0);
6880
14.7k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6881
1.80k
  return(0);
6882
6883
    /*
6884
     * for equal, check if there is a node pertaining to both sets
6885
     */
6886
12.9k
    if (neq == 0)
6887
67.4k
  for (i = 0;i < ns1->nodeNr;i++)
6888
2.36M
      for (j = 0;j < ns2->nodeNr;j++)
6889
2.31M
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6890
274
        return(1);
6891
6892
12.6k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6893
12.6k
    if (values1 == NULL) {
6894
        /* TODO: Propagate memory error. */
6895
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
0
  return(0);
6897
0
    }
6898
12.6k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6899
12.6k
    if (hashs1 == NULL) {
6900
        /* TODO: Propagate memory error. */
6901
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902
0
  xmlFree(values1);
6903
0
  return(0);
6904
0
    }
6905
12.6k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6906
12.6k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6907
12.6k
    if (values2 == NULL) {
6908
        /* TODO: Propagate memory error. */
6909
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910
0
  xmlFree(hashs1);
6911
0
  xmlFree(values1);
6912
0
  return(0);
6913
0
    }
6914
12.6k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6915
12.6k
    if (hashs2 == NULL) {
6916
        /* TODO: Propagate memory error. */
6917
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918
0
  xmlFree(hashs1);
6919
0
  xmlFree(values1);
6920
0
  xmlFree(values2);
6921
0
  return(0);
6922
0
    }
6923
12.6k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6924
44.2k
    for (i = 0;i < ns1->nodeNr;i++) {
6925
33.2k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6926
308k
  for (j = 0;j < ns2->nodeNr;j++) {
6927
276k
      if (i == 0)
6928
49.7k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6929
276k
      if (hashs1[i] != hashs2[j]) {
6930
269k
    if (neq) {
6931
211
        ret = 1;
6932
211
        break;
6933
211
    }
6934
269k
      }
6935
7.74k
      else {
6936
7.74k
    if (values1[i] == NULL)
6937
5.57k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6938
7.74k
    if (values2[j] == NULL)
6939
5.26k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6940
7.74k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6941
7.74k
    if (ret)
6942
1.38k
        break;
6943
7.74k
      }
6944
276k
  }
6945
33.2k
  if (ret)
6946
1.59k
      break;
6947
33.2k
    }
6948
70.0k
    for (i = 0;i < ns1->nodeNr;i++)
6949
57.4k
  if (values1[i] != NULL)
6950
5.57k
      xmlFree(values1[i]);
6951
64.7k
    for (j = 0;j < ns2->nodeNr;j++)
6952
52.1k
  if (values2[j] != NULL)
6953
5.26k
      xmlFree(values2[j]);
6954
12.6k
    xmlFree(values1);
6955
12.6k
    xmlFree(values2);
6956
12.6k
    xmlFree(hashs1);
6957
12.6k
    xmlFree(hashs2);
6958
12.6k
    return(ret);
6959
12.6k
}
6960
6961
static int
6962
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6963
59.3k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6964
59.3k
    int ret = 0;
6965
    /*
6966
     *At this point we are assured neither arg1 nor arg2
6967
     *is a nodeset, so we can just pick the appropriate routine.
6968
     */
6969
59.3k
    switch (arg1->type) {
6970
0
        case XPATH_UNDEFINED:
6971
#ifdef DEBUG_EXPR
6972
      xmlGenericError(xmlGenericErrorContext,
6973
        "Equal: undefined\n");
6974
#endif
6975
0
      break;
6976
12.3k
        case XPATH_BOOLEAN:
6977
12.3k
      switch (arg2->type) {
6978
0
          case XPATH_UNDEFINED:
6979
#ifdef DEBUG_EXPR
6980
        xmlGenericError(xmlGenericErrorContext,
6981
          "Equal: undefined\n");
6982
#endif
6983
0
        break;
6984
1.88k
    case XPATH_BOOLEAN:
6985
#ifdef DEBUG_EXPR
6986
        xmlGenericError(xmlGenericErrorContext,
6987
          "Equal: %d boolean %d \n",
6988
          arg1->boolval, arg2->boolval);
6989
#endif
6990
1.88k
        ret = (arg1->boolval == arg2->boolval);
6991
1.88k
        break;
6992
9.52k
    case XPATH_NUMBER:
6993
9.52k
        ret = (arg1->boolval ==
6994
9.52k
         xmlXPathCastNumberToBoolean(arg2->floatval));
6995
9.52k
        break;
6996
906
    case XPATH_STRING:
6997
906
        if ((arg2->stringval == NULL) ||
6998
906
      (arg2->stringval[0] == 0)) ret = 0;
6999
888
        else
7000
888
      ret = 1;
7001
906
        ret = (arg1->boolval == ret);
7002
906
        break;
7003
0
    case XPATH_USERS:
7004
#ifdef LIBXML_XPTR_LOCS_ENABLED
7005
    case XPATH_POINT:
7006
    case XPATH_RANGE:
7007
    case XPATH_LOCATIONSET:
7008
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7009
0
        TODO
7010
0
        break;
7011
0
    case XPATH_NODESET:
7012
0
    case XPATH_XSLT_TREE:
7013
0
        break;
7014
12.3k
      }
7015
12.3k
      break;
7016
47.0k
        case XPATH_NUMBER:
7017
47.0k
      switch (arg2->type) {
7018
0
          case XPATH_UNDEFINED:
7019
#ifdef DEBUG_EXPR
7020
        xmlGenericError(xmlGenericErrorContext,
7021
          "Equal: undefined\n");
7022
#endif
7023
0
        break;
7024
242
    case XPATH_BOOLEAN:
7025
242
        ret = (arg2->boolval==
7026
242
         xmlXPathCastNumberToBoolean(arg1->floatval));
7027
242
        break;
7028
33.1k
    case XPATH_STRING:
7029
33.1k
        valuePush(ctxt, arg2);
7030
33.1k
        xmlXPathNumberFunction(ctxt, 1);
7031
33.1k
        arg2 = valuePop(ctxt);
7032
                    /* Falls through. */
7033
46.8k
    case XPATH_NUMBER:
7034
        /* Hand check NaN and Infinity equalities */
7035
46.8k
        if (xmlXPathIsNaN(arg1->floatval) ||
7036
46.8k
          xmlXPathIsNaN(arg2->floatval)) {
7037
38.6k
            ret = 0;
7038
38.6k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7039
3.28k
            if (xmlXPathIsInf(arg2->floatval) == 1)
7040
412
          ret = 1;
7041
2.87k
      else
7042
2.87k
          ret = 0;
7043
4.90k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7044
326
      if (xmlXPathIsInf(arg2->floatval) == -1)
7045
45
          ret = 1;
7046
281
      else
7047
281
          ret = 0;
7048
4.57k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7049
1.77k
      if (xmlXPathIsInf(arg1->floatval) == 1)
7050
0
          ret = 1;
7051
1.77k
      else
7052
1.77k
          ret = 0;
7053
2.80k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7054
607
      if (xmlXPathIsInf(arg1->floatval) == -1)
7055
0
          ret = 1;
7056
607
      else
7057
607
          ret = 0;
7058
2.19k
        } else {
7059
2.19k
            ret = (arg1->floatval == arg2->floatval);
7060
2.19k
        }
7061
46.8k
        break;
7062
0
    case XPATH_USERS:
7063
#ifdef LIBXML_XPTR_LOCS_ENABLED
7064
    case XPATH_POINT:
7065
    case XPATH_RANGE:
7066
    case XPATH_LOCATIONSET:
7067
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7068
0
        TODO
7069
0
        break;
7070
0
    case XPATH_NODESET:
7071
0
    case XPATH_XSLT_TREE:
7072
0
        break;
7073
47.0k
      }
7074
47.0k
      break;
7075
47.0k
        case XPATH_STRING:
7076
25
      switch (arg2->type) {
7077
0
          case XPATH_UNDEFINED:
7078
#ifdef DEBUG_EXPR
7079
        xmlGenericError(xmlGenericErrorContext,
7080
          "Equal: undefined\n");
7081
#endif
7082
0
        break;
7083
0
    case XPATH_BOOLEAN:
7084
0
        if ((arg1->stringval == NULL) ||
7085
0
      (arg1->stringval[0] == 0)) ret = 0;
7086
0
        else
7087
0
      ret = 1;
7088
0
        ret = (arg2->boolval == ret);
7089
0
        break;
7090
24
    case XPATH_STRING:
7091
24
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7092
24
        break;
7093
1
    case XPATH_NUMBER:
7094
1
        valuePush(ctxt, arg1);
7095
1
        xmlXPathNumberFunction(ctxt, 1);
7096
1
        arg1 = valuePop(ctxt);
7097
        /* Hand check NaN and Infinity equalities */
7098
1
        if (xmlXPathIsNaN(arg1->floatval) ||
7099
1
          xmlXPathIsNaN(arg2->floatval)) {
7100
1
            ret = 0;
7101
1
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7102
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7103
0
          ret = 1;
7104
0
      else
7105
0
          ret = 0;
7106
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7107
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7108
0
          ret = 1;
7109
0
      else
7110
0
          ret = 0;
7111
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7112
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7113
0
          ret = 1;
7114
0
      else
7115
0
          ret = 0;
7116
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7117
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7118
0
          ret = 1;
7119
0
      else
7120
0
          ret = 0;
7121
0
        } else {
7122
0
            ret = (arg1->floatval == arg2->floatval);
7123
0
        }
7124
1
        break;
7125
0
    case XPATH_USERS:
7126
#ifdef LIBXML_XPTR_LOCS_ENABLED
7127
    case XPATH_POINT:
7128
    case XPATH_RANGE:
7129
    case XPATH_LOCATIONSET:
7130
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7131
0
        TODO
7132
0
        break;
7133
0
    case XPATH_NODESET:
7134
0
    case XPATH_XSLT_TREE:
7135
0
        break;
7136
25
      }
7137
25
      break;
7138
25
        case XPATH_USERS:
7139
#ifdef LIBXML_XPTR_LOCS_ENABLED
7140
  case XPATH_POINT:
7141
  case XPATH_RANGE:
7142
  case XPATH_LOCATIONSET:
7143
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7144
0
      TODO
7145
0
      break;
7146
0
  case XPATH_NODESET:
7147
0
  case XPATH_XSLT_TREE:
7148
0
      break;
7149
59.3k
    }
7150
59.3k
    xmlXPathReleaseObject(ctxt->context, arg1);
7151
59.3k
    xmlXPathReleaseObject(ctxt->context, arg2);
7152
59.3k
    return(ret);
7153
59.3k
}
7154
7155
/**
7156
 * xmlXPathEqualValues:
7157
 * @ctxt:  the XPath Parser context
7158
 *
7159
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7160
 *
7161
 * Returns 0 or 1 depending on the results of the test.
7162
 */
7163
int
7164
67.8k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165
67.8k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7166
67.8k
    int ret = 0;
7167
7168
67.8k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7169
67.8k
    arg2 = valuePop(ctxt);
7170
67.8k
    arg1 = valuePop(ctxt);
7171
67.8k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7172
0
  if (arg1 != NULL)
7173
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7174
0
  else
7175
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7176
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7177
0
    }
7178
7179
67.8k
    if (arg1 == arg2) {
7180
#ifdef DEBUG_EXPR
7181
        xmlGenericError(xmlGenericErrorContext,
7182
    "Equal: by pointer\n");
7183
#endif
7184
0
  xmlXPathFreeObject(arg1);
7185
0
        return(1);
7186
0
    }
7187
7188
    /*
7189
     *If either argument is a nodeset, it's a 'special case'
7190
     */
7191
67.8k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192
67.8k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193
  /*
7194
   *Hack it to assure arg1 is the nodeset
7195
   */
7196
46.8k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197
8.49k
    argtmp = arg2;
7198
8.49k
    arg2 = arg1;
7199
8.49k
    arg1 = argtmp;
7200
8.49k
  }
7201
46.8k
  switch (arg2->type) {
7202
0
      case XPATH_UNDEFINED:
7203
#ifdef DEBUG_EXPR
7204
    xmlGenericError(xmlGenericErrorContext,
7205
      "Equal: undefined\n");
7206
#endif
7207
0
    break;
7208
24.2k
      case XPATH_NODESET:
7209
24.2k
      case XPATH_XSLT_TREE:
7210
24.2k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211
24.2k
    break;
7212
4.33k
      case XPATH_BOOLEAN:
7213
4.33k
    if ((arg1->nodesetval == NULL) ||
7214
4.33k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7215
461
    else
7216
461
        ret = 1;
7217
4.33k
    ret = (ret == arg2->boolval);
7218
4.33k
    break;
7219
14.4k
      case XPATH_NUMBER:
7220
14.4k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221
14.4k
    break;
7222
3.79k
      case XPATH_STRING:
7223
3.79k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224
3.79k
    break;
7225
0
      case XPATH_USERS:
7226
#ifdef LIBXML_XPTR_LOCS_ENABLED
7227
      case XPATH_POINT:
7228
      case XPATH_RANGE:
7229
      case XPATH_LOCATIONSET:
7230
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7231
0
    TODO
7232
0
    break;
7233
46.8k
  }
7234
46.8k
  xmlXPathReleaseObject(ctxt->context, arg1);
7235
46.8k
  xmlXPathReleaseObject(ctxt->context, arg2);
7236
46.8k
  return(ret);
7237
46.8k
    }
7238
7239
20.9k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240
67.8k
}
7241
7242
/**
7243
 * xmlXPathNotEqualValues:
7244
 * @ctxt:  the XPath Parser context
7245
 *
7246
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7247
 *
7248
 * Returns 0 or 1 depending on the results of the test.
7249
 */
7250
int
7251
44.3k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252
44.3k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7253
44.3k
    int ret = 0;
7254
7255
44.3k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256
44.3k
    arg2 = valuePop(ctxt);
7257
44.3k
    arg1 = valuePop(ctxt);
7258
44.3k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7259
0
  if (arg1 != NULL)
7260
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7261
0
  else
7262
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7263
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7264
0
    }
7265
7266
44.3k
    if (arg1 == arg2) {
7267
#ifdef DEBUG_EXPR
7268
        xmlGenericError(xmlGenericErrorContext,
7269
    "NotEqual: by pointer\n");
7270
#endif
7271
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7272
0
        return(0);
7273
0
    }
7274
7275
    /*
7276
     *If either argument is a nodeset, it's a 'special case'
7277
     */
7278
44.3k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279
44.3k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280
  /*
7281
   *Hack it to assure arg1 is the nodeset
7282
   */
7283
5.90k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284
1.44k
    argtmp = arg2;
7285
1.44k
    arg2 = arg1;
7286
1.44k
    arg1 = argtmp;
7287
1.44k
  }
7288
5.90k
  switch (arg2->type) {
7289
0
      case XPATH_UNDEFINED:
7290
#ifdef DEBUG_EXPR
7291
    xmlGenericError(xmlGenericErrorContext,
7292
      "NotEqual: undefined\n");
7293
#endif
7294
0
    break;
7295
1.85k
      case XPATH_NODESET:
7296
1.85k
      case XPATH_XSLT_TREE:
7297
1.85k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298
1.85k
    break;
7299
663
      case XPATH_BOOLEAN:
7300
663
    if ((arg1->nodesetval == NULL) ||
7301
663
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302
55
    else
7303
55
        ret = 1;
7304
663
    ret = (ret != arg2->boolval);
7305
663
    break;
7306
2.84k
      case XPATH_NUMBER:
7307
2.84k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308
2.84k
    break;
7309
544
      case XPATH_STRING:
7310
544
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311
544
    break;
7312
0
      case XPATH_USERS:
7313
#ifdef LIBXML_XPTR_LOCS_ENABLED
7314
      case XPATH_POINT:
7315
      case XPATH_RANGE:
7316
      case XPATH_LOCATIONSET:
7317
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7318
0
    TODO
7319
0
    break;
7320
5.90k
  }
7321
5.90k
  xmlXPathReleaseObject(ctxt->context, arg1);
7322
5.90k
  xmlXPathReleaseObject(ctxt->context, arg2);
7323
5.90k
  return(ret);
7324
5.90k
    }
7325
7326
38.4k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7327
44.3k
}
7328
7329
/**
7330
 * xmlXPathCompareValues:
7331
 * @ctxt:  the XPath Parser context
7332
 * @inf:  less than (1) or greater than (0)
7333
 * @strict:  is the comparison strict
7334
 *
7335
 * Implement the compare operation on XPath objects:
7336
 *     @arg1 < @arg2    (1, 1, ...
7337
 *     @arg1 <= @arg2   (1, 0, ...
7338
 *     @arg1 > @arg2    (0, 1, ...
7339
 *     @arg1 >= @arg2   (0, 0, ...
7340
 *
7341
 * When neither object to be compared is a node-set and the operator is
7342
 * <=, <, >=, >, then the objects are compared by converted both objects
7343
 * to numbers and comparing the numbers according to IEEE 754. The <
7344
 * comparison will be true if and only if the first number is less than the
7345
 * second number. The <= comparison will be true if and only if the first
7346
 * number is less than or equal to the second number. The > comparison
7347
 * will be true if and only if the first number is greater than the second
7348
 * number. The >= comparison will be true if and only if the first number
7349
 * is greater than or equal to the second number.
7350
 *
7351
 * Returns 1 if the comparison succeeded, 0 if it failed
7352
 */
7353
int
7354
404k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7355
404k
    int ret = 0, arg1i = 0, arg2i = 0;
7356
404k
    xmlXPathObjectPtr arg1, arg2;
7357
7358
404k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7359
404k
    arg2 = valuePop(ctxt);
7360
404k
    arg1 = valuePop(ctxt);
7361
404k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7362
0
  if (arg1 != NULL)
7363
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7364
0
  else
7365
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7366
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7367
0
    }
7368
7369
404k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7370
404k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7371
  /*
7372
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7373
   * are not freed from within this routine; they will be freed from the
7374
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7375
   */
7376
22.5k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7377
22.5k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7378
7.96k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7379
14.5k
  } else {
7380
14.5k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7381
7.68k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7382
7.68k
                                arg1, arg2);
7383
7.68k
      } else {
7384
6.85k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7385
6.85k
                                arg2, arg1);
7386
6.85k
      }
7387
14.5k
  }
7388
22.5k
  return(ret);
7389
22.5k
    }
7390
7391
382k
    if (arg1->type != XPATH_NUMBER) {
7392
39.1k
  valuePush(ctxt, arg1);
7393
39.1k
  xmlXPathNumberFunction(ctxt, 1);
7394
39.1k
  arg1 = valuePop(ctxt);
7395
39.1k
    }
7396
382k
    if (arg1->type != XPATH_NUMBER) {
7397
0
  xmlXPathFreeObject(arg1);
7398
0
  xmlXPathFreeObject(arg2);
7399
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7400
0
    }
7401
382k
    if (arg2->type != XPATH_NUMBER) {
7402
37.0k
  valuePush(ctxt, arg2);
7403
37.0k
  xmlXPathNumberFunction(ctxt, 1);
7404
37.0k
  arg2 = valuePop(ctxt);
7405
37.0k
    }
7406
382k
    if (arg2->type != XPATH_NUMBER) {
7407
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7408
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7409
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7410
0
    }
7411
    /*
7412
     * Add tests for infinity and nan
7413
     * => feedback on 3.4 for Inf and NaN
7414
     */
7415
    /* Hand check NaN and Infinity comparisons */
7416
382k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7417
374k
  ret=0;
7418
374k
    } else {
7419
7.35k
  arg1i=xmlXPathIsInf(arg1->floatval);
7420
7.35k
  arg2i=xmlXPathIsInf(arg2->floatval);
7421
7.35k
  if (inf && strict) {
7422
2.77k
      if ((arg1i == -1 && arg2i != -1) ||
7423
2.77k
    (arg2i == 1 && arg1i != 1)) {
7424
65
    ret = 1;
7425
2.71k
      } else if (arg1i == 0 && arg2i == 0) {
7426
2.71k
    ret = (arg1->floatval < arg2->floatval);
7427
2.71k
      } else {
7428
2
    ret = 0;
7429
2
      }
7430
2.77k
  }
7431
4.58k
  else if (inf && !strict) {
7432
499
      if (arg1i == -1 || arg2i == 1) {
7433
12
    ret = 1;
7434
487
      } else if (arg1i == 0 && arg2i == 0) {
7435
485
    ret = (arg1->floatval <= arg2->floatval);
7436
485
      } else {
7437
2
    ret = 0;
7438
2
      }
7439
499
  }
7440
4.08k
  else if (!inf && strict) {
7441
3.82k
      if ((arg1i == 1 && arg2i != 1) ||
7442
3.82k
    (arg2i == -1 && arg1i != -1)) {
7443
113
    ret = 1;
7444
3.70k
      } else if (arg1i == 0 && arg2i == 0) {
7445
1.45k
    ret = (arg1->floatval > arg2->floatval);
7446
2.25k
      } else {
7447
2.25k
    ret = 0;
7448
2.25k
      }
7449
3.82k
  }
7450
261
  else if (!inf && !strict) {
7451
261
      if (arg1i == 1 || arg2i == -1) {
7452
12
    ret = 1;
7453
249
      } else if (arg1i == 0 && arg2i == 0) {
7454
236
    ret = (arg1->floatval >= arg2->floatval);
7455
236
      } else {
7456
13
    ret = 0;
7457
13
      }
7458
261
  }
7459
7.35k
    }
7460
382k
    xmlXPathReleaseObject(ctxt->context, arg1);
7461
382k
    xmlXPathReleaseObject(ctxt->context, arg2);
7462
382k
    return(ret);
7463
382k
}
7464
7465
/**
7466
 * xmlXPathValueFlipSign:
7467
 * @ctxt:  the XPath Parser context
7468
 *
7469
 * Implement the unary - operation on an XPath object
7470
 * The numeric operators convert their operands to numbers as if
7471
 * by calling the number function.
7472
 */
7473
void
7474
33.3k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7475
33.3k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7476
33.3k
    CAST_TO_NUMBER;
7477
33.3k
    CHECK_TYPE(XPATH_NUMBER);
7478
33.3k
    ctxt->value->floatval = -ctxt->value->floatval;
7479
33.3k
}
7480
7481
/**
7482
 * xmlXPathAddValues:
7483
 * @ctxt:  the XPath Parser context
7484
 *
7485
 * Implement the add operation on XPath objects:
7486
 * The numeric operators convert their operands to numbers as if
7487
 * by calling the number function.
7488
 */
7489
void
7490
25.9k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7491
25.9k
    xmlXPathObjectPtr arg;
7492
25.9k
    double val;
7493
7494
25.9k
    arg = valuePop(ctxt);
7495
25.9k
    if (arg == NULL)
7496
25.9k
  XP_ERROR(XPATH_INVALID_OPERAND);
7497
25.9k
    val = xmlXPathCastToNumber(arg);
7498
25.9k
    xmlXPathReleaseObject(ctxt->context, arg);
7499
25.9k
    CAST_TO_NUMBER;
7500
25.9k
    CHECK_TYPE(XPATH_NUMBER);
7501
25.9k
    ctxt->value->floatval += val;
7502
25.9k
}
7503
7504
/**
7505
 * xmlXPathSubValues:
7506
 * @ctxt:  the XPath Parser context
7507
 *
7508
 * Implement the subtraction operation on XPath objects:
7509
 * The numeric operators convert their operands to numbers as if
7510
 * by calling the number function.
7511
 */
7512
void
7513
35.3k
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7514
35.3k
    xmlXPathObjectPtr arg;
7515
35.3k
    double val;
7516
7517
35.3k
    arg = valuePop(ctxt);
7518
35.3k
    if (arg == NULL)
7519
35.3k
  XP_ERROR(XPATH_INVALID_OPERAND);
7520
35.3k
    val = xmlXPathCastToNumber(arg);
7521
35.3k
    xmlXPathReleaseObject(ctxt->context, arg);
7522
35.3k
    CAST_TO_NUMBER;
7523
35.3k
    CHECK_TYPE(XPATH_NUMBER);
7524
35.3k
    ctxt->value->floatval -= val;
7525
35.3k
}
7526
7527
/**
7528
 * xmlXPathMultValues:
7529
 * @ctxt:  the XPath Parser context
7530
 *
7531
 * Implement the multiply operation on XPath objects:
7532
 * The numeric operators convert their operands to numbers as if
7533
 * by calling the number function.
7534
 */
7535
void
7536
251k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7537
251k
    xmlXPathObjectPtr arg;
7538
251k
    double val;
7539
7540
251k
    arg = valuePop(ctxt);
7541
251k
    if (arg == NULL)
7542
251k
  XP_ERROR(XPATH_INVALID_OPERAND);
7543
251k
    val = xmlXPathCastToNumber(arg);
7544
251k
    xmlXPathReleaseObject(ctxt->context, arg);
7545
251k
    CAST_TO_NUMBER;
7546
251k
    CHECK_TYPE(XPATH_NUMBER);
7547
251k
    ctxt->value->floatval *= val;
7548
251k
}
7549
7550
/**
7551
 * xmlXPathDivValues:
7552
 * @ctxt:  the XPath Parser context
7553
 *
7554
 * Implement the div 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
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7559
void
7560
297
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7561
297
    xmlXPathObjectPtr arg;
7562
297
    double val;
7563
7564
297
    arg = valuePop(ctxt);
7565
297
    if (arg == NULL)
7566
297
  XP_ERROR(XPATH_INVALID_OPERAND);
7567
297
    val = xmlXPathCastToNumber(arg);
7568
297
    xmlXPathReleaseObject(ctxt->context, arg);
7569
297
    CAST_TO_NUMBER;
7570
297
    CHECK_TYPE(XPATH_NUMBER);
7571
297
    ctxt->value->floatval /= val;
7572
297
}
7573
7574
/**
7575
 * xmlXPathModValues:
7576
 * @ctxt:  the XPath Parser context
7577
 *
7578
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7579
 * The numeric operators convert their operands to numbers as if
7580
 * by calling the number function.
7581
 */
7582
void
7583
419
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7584
419
    xmlXPathObjectPtr arg;
7585
419
    double arg1, arg2;
7586
7587
419
    arg = valuePop(ctxt);
7588
419
    if (arg == NULL)
7589
419
  XP_ERROR(XPATH_INVALID_OPERAND);
7590
419
    arg2 = xmlXPathCastToNumber(arg);
7591
419
    xmlXPathReleaseObject(ctxt->context, arg);
7592
419
    CAST_TO_NUMBER;
7593
419
    CHECK_TYPE(XPATH_NUMBER);
7594
419
    arg1 = ctxt->value->floatval;
7595
419
    if (arg2 == 0)
7596
0
  ctxt->value->floatval = xmlXPathNAN;
7597
419
    else {
7598
419
  ctxt->value->floatval = fmod(arg1, arg2);
7599
419
    }
7600
419
}
7601
7602
/************************************************************************
7603
 *                  *
7604
 *    The traversal functions         *
7605
 *                  *
7606
 ************************************************************************/
7607
7608
/*
7609
 * A traversal function enumerates nodes along an axis.
7610
 * Initially it must be called with NULL, and it indicates
7611
 * termination on the axis by returning NULL.
7612
 */
7613
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7614
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7615
7616
/*
7617
 * xmlXPathTraversalFunctionExt:
7618
 * A traversal function enumerates nodes along an axis.
7619
 * Initially it must be called with NULL, and it indicates
7620
 * termination on the axis by returning NULL.
7621
 * The context node of the traversal is specified via @contextNode.
7622
 */
7623
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7624
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7625
7626
/*
7627
 * xmlXPathNodeSetMergeFunction:
7628
 * Used for merging node sets in xmlXPathCollectAndTest().
7629
 */
7630
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7631
        (xmlNodeSetPtr, xmlNodeSetPtr);
7632
7633
7634
/**
7635
 * xmlXPathNextSelf:
7636
 * @ctxt:  the XPath Parser context
7637
 * @cur:  the current node in the traversal
7638
 *
7639
 * Traversal function for the "self" direction
7640
 * The self axis contains just the context node itself
7641
 *
7642
 * Returns the next element following that axis
7643
 */
7644
xmlNodePtr
7645
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7646
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7647
0
    if (cur == NULL)
7648
0
        return(ctxt->context->node);
7649
0
    return(NULL);
7650
0
}
7651
7652
/**
7653
 * xmlXPathNextChild:
7654
 * @ctxt:  the XPath Parser context
7655
 * @cur:  the current node in the traversal
7656
 *
7657
 * Traversal function for the "child" direction
7658
 * The child axis contains the children of the context node in document order.
7659
 *
7660
 * Returns the next element following that axis
7661
 */
7662
xmlNodePtr
7663
3.42M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7664
3.42M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7665
3.42M
    if (cur == NULL) {
7666
1.98M
  if (ctxt->context->node == NULL) return(NULL);
7667
1.98M
  switch (ctxt->context->node->type) {
7668
861k
            case XML_ELEMENT_NODE:
7669
1.87M
            case XML_TEXT_NODE:
7670
1.88M
            case XML_CDATA_SECTION_NODE:
7671
1.88M
            case XML_ENTITY_REF_NODE:
7672
1.88M
            case XML_ENTITY_NODE:
7673
1.89M
            case XML_PI_NODE:
7674
1.97M
            case XML_COMMENT_NODE:
7675
1.97M
            case XML_NOTATION_NODE:
7676
1.97M
            case XML_DTD_NODE:
7677
1.97M
    return(ctxt->context->node->children);
7678
12.4k
            case XML_DOCUMENT_NODE:
7679
12.4k
            case XML_DOCUMENT_TYPE_NODE:
7680
12.4k
            case XML_DOCUMENT_FRAG_NODE:
7681
12.4k
            case XML_HTML_DOCUMENT_NODE:
7682
12.4k
    return(((xmlDocPtr) ctxt->context->node)->children);
7683
0
      case XML_ELEMENT_DECL:
7684
0
      case XML_ATTRIBUTE_DECL:
7685
0
      case XML_ENTITY_DECL:
7686
0
            case XML_ATTRIBUTE_NODE:
7687
0
      case XML_NAMESPACE_DECL:
7688
0
      case XML_XINCLUDE_START:
7689
0
      case XML_XINCLUDE_END:
7690
0
    return(NULL);
7691
1.98M
  }
7692
0
  return(NULL);
7693
1.98M
    }
7694
1.43M
    if ((cur->type == XML_DOCUMENT_NODE) ||
7695
1.43M
        (cur->type == XML_HTML_DOCUMENT_NODE))
7696
0
  return(NULL);
7697
1.43M
    return(cur->next);
7698
1.43M
}
7699
7700
/**
7701
 * xmlXPathNextChildElement:
7702
 * @ctxt:  the XPath Parser context
7703
 * @cur:  the current node in the traversal
7704
 *
7705
 * Traversal function for the "child" direction and nodes of type element.
7706
 * The child axis contains the children of the context node in document order.
7707
 *
7708
 * Returns the next element following that axis
7709
 */
7710
static xmlNodePtr
7711
6.56M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712
6.56M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713
6.56M
    if (cur == NULL) {
7714
3.00M
  cur = ctxt->context->node;
7715
3.00M
  if (cur == NULL) return(NULL);
7716
  /*
7717
  * Get the first element child.
7718
  */
7719
3.00M
  switch (cur->type) {
7720
2.24M
            case XML_ELEMENT_NODE:
7721
2.24M
      case XML_DOCUMENT_FRAG_NODE:
7722
2.24M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723
2.24M
            case XML_ENTITY_NODE:
7724
2.24M
    cur = cur->children;
7725
2.24M
    if (cur != NULL) {
7726
1.34M
        if (cur->type == XML_ELEMENT_NODE)
7727
469k
      return(cur);
7728
905k
        do {
7729
905k
      cur = cur->next;
7730
905k
        } while ((cur != NULL) &&
7731
905k
      (cur->type != XML_ELEMENT_NODE));
7732
876k
        return(cur);
7733
1.34M
    }
7734
902k
    return(NULL);
7735
379k
            case XML_DOCUMENT_NODE:
7736
379k
            case XML_HTML_DOCUMENT_NODE:
7737
379k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7738
377k
      default:
7739
377k
    return(NULL);
7740
3.00M
  }
7741
0
  return(NULL);
7742
3.00M
    }
7743
    /*
7744
    * Get the next sibling element node.
7745
    */
7746
3.56M
    switch (cur->type) {
7747
3.56M
  case XML_ELEMENT_NODE:
7748
3.56M
  case XML_TEXT_NODE:
7749
3.56M
  case XML_ENTITY_REF_NODE:
7750
3.56M
  case XML_ENTITY_NODE:
7751
3.56M
  case XML_CDATA_SECTION_NODE:
7752
3.56M
  case XML_PI_NODE:
7753
3.56M
  case XML_COMMENT_NODE:
7754
3.56M
  case XML_XINCLUDE_END:
7755
3.56M
      break;
7756
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7757
0
  default:
7758
0
      return(NULL);
7759
3.56M
    }
7760
3.56M
    if (cur->next != NULL) {
7761
2.62M
  if (cur->next->type == XML_ELEMENT_NODE)
7762
1.07M
      return(cur->next);
7763
1.54M
  cur = cur->next;
7764
2.22M
  do {
7765
2.22M
      cur = cur->next;
7766
2.22M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7767
1.54M
  return(cur);
7768
2.62M
    }
7769
940k
    return(NULL);
7770
3.56M
}
7771
7772
#if 0
7773
/**
7774
 * xmlXPathNextDescendantOrSelfElemParent:
7775
 * @ctxt:  the XPath Parser context
7776
 * @cur:  the current node in the traversal
7777
 *
7778
 * Traversal function for the "descendant-or-self" axis.
7779
 * Additionally it returns only nodes which can be parents of
7780
 * element nodes.
7781
 *
7782
 *
7783
 * Returns the next element following that axis
7784
 */
7785
static xmlNodePtr
7786
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7787
               xmlNodePtr contextNode)
7788
{
7789
    if (cur == NULL) {
7790
  if (contextNode == NULL)
7791
      return(NULL);
7792
  switch (contextNode->type) {
7793
      case XML_ELEMENT_NODE:
7794
      case XML_XINCLUDE_START:
7795
      case XML_DOCUMENT_FRAG_NODE:
7796
      case XML_DOCUMENT_NODE:
7797
      case XML_HTML_DOCUMENT_NODE:
7798
    return(contextNode);
7799
      default:
7800
    return(NULL);
7801
  }
7802
  return(NULL);
7803
    } else {
7804
  xmlNodePtr start = cur;
7805
7806
  while (cur != NULL) {
7807
      switch (cur->type) {
7808
    case XML_ELEMENT_NODE:
7809
    /* TODO: OK to have XInclude here? */
7810
    case XML_XINCLUDE_START:
7811
    case XML_DOCUMENT_FRAG_NODE:
7812
        if (cur != start)
7813
      return(cur);
7814
        if (cur->children != NULL) {
7815
      cur = cur->children;
7816
      continue;
7817
        }
7818
        break;
7819
    /* Not sure if we need those here. */
7820
    case XML_DOCUMENT_NODE:
7821
    case XML_HTML_DOCUMENT_NODE:
7822
        if (cur != start)
7823
      return(cur);
7824
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7825
    default:
7826
        break;
7827
      }
7828
7829
next_sibling:
7830
      if ((cur == NULL) || (cur == contextNode))
7831
    return(NULL);
7832
      if (cur->next != NULL) {
7833
    cur = cur->next;
7834
      } else {
7835
    cur = cur->parent;
7836
    goto next_sibling;
7837
      }
7838
  }
7839
    }
7840
    return(NULL);
7841
}
7842
#endif
7843
7844
/**
7845
 * xmlXPathNextDescendant:
7846
 * @ctxt:  the XPath Parser context
7847
 * @cur:  the current node in the traversal
7848
 *
7849
 * Traversal function for the "descendant" direction
7850
 * the descendant axis contains the descendants of the context node in document
7851
 * order; a descendant is a child or a child of a child and so on.
7852
 *
7853
 * Returns the next element following that axis
7854
 */
7855
xmlNodePtr
7856
21.2M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7857
21.2M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7858
21.2M
    if (cur == NULL) {
7859
155k
  if (ctxt->context->node == NULL)
7860
0
      return(NULL);
7861
155k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7862
155k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7863
1.40k
      return(NULL);
7864
7865
154k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7866
30.5k
      return(ctxt->context->doc->children);
7867
123k
        return(ctxt->context->node->children);
7868
154k
    }
7869
7870
21.0M
    if (cur->type == XML_NAMESPACE_DECL)
7871
0
        return(NULL);
7872
21.0M
    if (cur->children != NULL) {
7873
  /*
7874
   * Do not descend on entities declarations
7875
   */
7876
4.78M
  if (cur->children->type != XML_ENTITY_DECL) {
7877
4.78M
      cur = cur->children;
7878
      /*
7879
       * Skip DTDs
7880
       */
7881
4.78M
      if (cur->type != XML_DTD_NODE)
7882
4.78M
    return(cur);
7883
4.78M
  }
7884
4.78M
    }
7885
7886
16.2M
    if (cur == ctxt->context->node) return(NULL);
7887
7888
16.2M
    while (cur->next != NULL) {
7889
13.3M
  cur = cur->next;
7890
13.3M
  if ((cur->type != XML_ENTITY_DECL) &&
7891
13.3M
      (cur->type != XML_DTD_NODE))
7892
13.3M
      return(cur);
7893
13.3M
    }
7894
7895
4.86M
    do {
7896
4.86M
        cur = cur->parent;
7897
4.86M
  if (cur == NULL) break;
7898
4.86M
  if (cur == ctxt->context->node) return(NULL);
7899
4.70M
  if (cur->next != NULL) {
7900
2.77M
      cur = cur->next;
7901
2.77M
      return(cur);
7902
2.77M
  }
7903
4.70M
    } while (cur != NULL);
7904
0
    return(cur);
7905
2.93M
}
7906
7907
/**
7908
 * xmlXPathNextDescendantOrSelf:
7909
 * @ctxt:  the XPath Parser context
7910
 * @cur:  the current node in the traversal
7911
 *
7912
 * Traversal function for the "descendant-or-self" direction
7913
 * the descendant-or-self axis contains the context node and the descendants
7914
 * of the context node in document order; thus the context node is the first
7915
 * node on the axis, and the first child of the context node is the second node
7916
 * on the axis
7917
 *
7918
 * Returns the next element following that axis
7919
 */
7920
xmlNodePtr
7921
11.8M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922
11.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923
11.8M
    if (cur == NULL)
7924
143k
        return(ctxt->context->node);
7925
7926
11.7M
    if (ctxt->context->node == NULL)
7927
0
        return(NULL);
7928
11.7M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7929
11.7M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7930
5.92k
        return(NULL);
7931
7932
11.7M
    return(xmlXPathNextDescendant(ctxt, cur));
7933
11.7M
}
7934
7935
/**
7936
 * xmlXPathNextParent:
7937
 * @ctxt:  the XPath Parser context
7938
 * @cur:  the current node in the traversal
7939
 *
7940
 * Traversal function for the "parent" direction
7941
 * The parent axis contains the parent of the context node, if there is one.
7942
 *
7943
 * Returns the next element following that axis
7944
 */
7945
xmlNodePtr
7946
2.11M
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7947
2.11M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7948
    /*
7949
     * the parent of an attribute or namespace node is the element
7950
     * to which the attribute or namespace node is attached
7951
     * Namespace handling !!!
7952
     */
7953
2.11M
    if (cur == NULL) {
7954
1.05M
  if (ctxt->context->node == NULL) return(NULL);
7955
1.05M
  switch (ctxt->context->node->type) {
7956
489k
            case XML_ELEMENT_NODE:
7957
1.00M
            case XML_TEXT_NODE:
7958
1.00M
            case XML_CDATA_SECTION_NODE:
7959
1.00M
            case XML_ENTITY_REF_NODE:
7960
1.00M
            case XML_ENTITY_NODE:
7961
1.01M
            case XML_PI_NODE:
7962
1.05M
            case XML_COMMENT_NODE:
7963
1.05M
            case XML_NOTATION_NODE:
7964
1.05M
            case XML_DTD_NODE:
7965
1.05M
      case XML_ELEMENT_DECL:
7966
1.05M
      case XML_ATTRIBUTE_DECL:
7967
1.05M
      case XML_XINCLUDE_START:
7968
1.05M
      case XML_XINCLUDE_END:
7969
1.05M
      case XML_ENTITY_DECL:
7970
1.05M
    if (ctxt->context->node->parent == NULL)
7971
0
        return((xmlNodePtr) ctxt->context->doc);
7972
1.05M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7973
1.05M
        ((ctxt->context->node->parent->name[0] == ' ') ||
7974
1.04M
         (xmlStrEqual(ctxt->context->node->parent->name,
7975
1.04M
         BAD_CAST "fake node libxslt"))))
7976
0
        return(NULL);
7977
1.05M
    return(ctxt->context->node->parent);
7978
1.97k
            case XML_ATTRIBUTE_NODE: {
7979
1.97k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7980
7981
1.97k
    return(att->parent);
7982
1.05M
      }
7983
3.58k
            case XML_DOCUMENT_NODE:
7984
3.58k
            case XML_DOCUMENT_TYPE_NODE:
7985
3.58k
            case XML_DOCUMENT_FRAG_NODE:
7986
3.58k
            case XML_HTML_DOCUMENT_NODE:
7987
3.58k
                return(NULL);
7988
0
      case XML_NAMESPACE_DECL: {
7989
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7990
7991
0
    if ((ns->next != NULL) &&
7992
0
        (ns->next->type != XML_NAMESPACE_DECL))
7993
0
        return((xmlNodePtr) ns->next);
7994
0
                return(NULL);
7995
0
      }
7996
1.05M
  }
7997
1.05M
    }
7998
1.05M
    return(NULL);
7999
2.11M
}
8000
8001
/**
8002
 * xmlXPathNextAncestor:
8003
 * @ctxt:  the XPath Parser context
8004
 * @cur:  the current node in the traversal
8005
 *
8006
 * Traversal function for the "ancestor" direction
8007
 * the ancestor axis contains the ancestors of the context node; the ancestors
8008
 * of the context node consist of the parent of context node and the parent's
8009
 * parent and so on; the nodes are ordered in reverse document order; thus the
8010
 * parent is the first node on the axis, and the parent's parent is the second
8011
 * node on the axis
8012
 *
8013
 * Returns the next element following that axis
8014
 */
8015
xmlNodePtr
8016
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8017
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8018
    /*
8019
     * the parent of an attribute or namespace node is the element
8020
     * to which the attribute or namespace node is attached
8021
     * !!!!!!!!!!!!!
8022
     */
8023
0
    if (cur == NULL) {
8024
0
  if (ctxt->context->node == NULL) return(NULL);
8025
0
  switch (ctxt->context->node->type) {
8026
0
            case XML_ELEMENT_NODE:
8027
0
            case XML_TEXT_NODE:
8028
0
            case XML_CDATA_SECTION_NODE:
8029
0
            case XML_ENTITY_REF_NODE:
8030
0
            case XML_ENTITY_NODE:
8031
0
            case XML_PI_NODE:
8032
0
            case XML_COMMENT_NODE:
8033
0
      case XML_DTD_NODE:
8034
0
      case XML_ELEMENT_DECL:
8035
0
      case XML_ATTRIBUTE_DECL:
8036
0
      case XML_ENTITY_DECL:
8037
0
            case XML_NOTATION_NODE:
8038
0
      case XML_XINCLUDE_START:
8039
0
      case XML_XINCLUDE_END:
8040
0
    if (ctxt->context->node->parent == NULL)
8041
0
        return((xmlNodePtr) ctxt->context->doc);
8042
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8043
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8044
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8045
0
         BAD_CAST "fake node libxslt"))))
8046
0
        return(NULL);
8047
0
    return(ctxt->context->node->parent);
8048
0
            case XML_ATTRIBUTE_NODE: {
8049
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8050
8051
0
    return(tmp->parent);
8052
0
      }
8053
0
            case XML_DOCUMENT_NODE:
8054
0
            case XML_DOCUMENT_TYPE_NODE:
8055
0
            case XML_DOCUMENT_FRAG_NODE:
8056
0
            case XML_HTML_DOCUMENT_NODE:
8057
0
                return(NULL);
8058
0
      case XML_NAMESPACE_DECL: {
8059
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8060
8061
0
    if ((ns->next != NULL) &&
8062
0
        (ns->next->type != XML_NAMESPACE_DECL))
8063
0
        return((xmlNodePtr) ns->next);
8064
    /* Bad, how did that namespace end up here ? */
8065
0
                return(NULL);
8066
0
      }
8067
0
  }
8068
0
  return(NULL);
8069
0
    }
8070
0
    if (cur == ctxt->context->doc->children)
8071
0
  return((xmlNodePtr) ctxt->context->doc);
8072
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8073
0
  return(NULL);
8074
0
    switch (cur->type) {
8075
0
  case XML_ELEMENT_NODE:
8076
0
  case XML_TEXT_NODE:
8077
0
  case XML_CDATA_SECTION_NODE:
8078
0
  case XML_ENTITY_REF_NODE:
8079
0
  case XML_ENTITY_NODE:
8080
0
  case XML_PI_NODE:
8081
0
  case XML_COMMENT_NODE:
8082
0
  case XML_NOTATION_NODE:
8083
0
  case XML_DTD_NODE:
8084
0
        case XML_ELEMENT_DECL:
8085
0
        case XML_ATTRIBUTE_DECL:
8086
0
        case XML_ENTITY_DECL:
8087
0
  case XML_XINCLUDE_START:
8088
0
  case XML_XINCLUDE_END:
8089
0
      if (cur->parent == NULL)
8090
0
    return(NULL);
8091
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8092
0
    ((cur->parent->name[0] == ' ') ||
8093
0
     (xmlStrEqual(cur->parent->name,
8094
0
            BAD_CAST "fake node libxslt"))))
8095
0
    return(NULL);
8096
0
      return(cur->parent);
8097
0
  case XML_ATTRIBUTE_NODE: {
8098
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8099
8100
0
      return(att->parent);
8101
0
  }
8102
0
  case XML_NAMESPACE_DECL: {
8103
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8104
8105
0
      if ((ns->next != NULL) &&
8106
0
          (ns->next->type != XML_NAMESPACE_DECL))
8107
0
          return((xmlNodePtr) ns->next);
8108
      /* Bad, how did that namespace end up here ? */
8109
0
            return(NULL);
8110
0
  }
8111
0
  case XML_DOCUMENT_NODE:
8112
0
  case XML_DOCUMENT_TYPE_NODE:
8113
0
  case XML_DOCUMENT_FRAG_NODE:
8114
0
  case XML_HTML_DOCUMENT_NODE:
8115
0
      return(NULL);
8116
0
    }
8117
0
    return(NULL);
8118
0
}
8119
8120
/**
8121
 * xmlXPathNextAncestorOrSelf:
8122
 * @ctxt:  the XPath Parser context
8123
 * @cur:  the current node in the traversal
8124
 *
8125
 * Traversal function for the "ancestor-or-self" direction
8126
 * he ancestor-or-self axis contains the context node and ancestors of
8127
 * the context node in reverse document order; thus the context node is
8128
 * the first node on the axis, and the context node's parent the second;
8129
 * parent here is defined the same as with the parent axis.
8130
 *
8131
 * Returns the next element following that axis
8132
 */
8133
xmlNodePtr
8134
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8135
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8136
0
    if (cur == NULL)
8137
0
        return(ctxt->context->node);
8138
0
    return(xmlXPathNextAncestor(ctxt, cur));
8139
0
}
8140
8141
/**
8142
 * xmlXPathNextFollowingSibling:
8143
 * @ctxt:  the XPath Parser context
8144
 * @cur:  the current node in the traversal
8145
 *
8146
 * Traversal function for the "following-sibling" direction
8147
 * The following-sibling axis contains the following siblings of the context
8148
 * node in document order.
8149
 *
8150
 * Returns the next element following that axis
8151
 */
8152
xmlNodePtr
8153
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157
0
  return(NULL);
8158
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8159
0
        return(NULL);
8160
0
    if (cur == NULL)
8161
0
        return(ctxt->context->node->next);
8162
0
    return(cur->next);
8163
0
}
8164
8165
/**
8166
 * xmlXPathNextPrecedingSibling:
8167
 * @ctxt:  the XPath Parser context
8168
 * @cur:  the current node in the traversal
8169
 *
8170
 * Traversal function for the "preceding-sibling" direction
8171
 * The preceding-sibling axis contains the preceding siblings of the context
8172
 * node in reverse document order; the first preceding sibling is first on the
8173
 * axis; the sibling preceding that node is the second on the axis and so on.
8174
 *
8175
 * Returns the next element following that axis
8176
 */
8177
xmlNodePtr
8178
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8181
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8182
0
  return(NULL);
8183
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8184
0
        return(NULL);
8185
0
    if (cur == NULL)
8186
0
        return(ctxt->context->node->prev);
8187
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8188
0
  cur = cur->prev;
8189
0
  if (cur == NULL)
8190
0
      return(ctxt->context->node->prev);
8191
0
    }
8192
0
    return(cur->prev);
8193
0
}
8194
8195
/**
8196
 * xmlXPathNextFollowing:
8197
 * @ctxt:  the XPath Parser context
8198
 * @cur:  the current node in the traversal
8199
 *
8200
 * Traversal function for the "following" direction
8201
 * The following axis contains all nodes in the same document as the context
8202
 * node that are after the context node in document order, excluding any
8203
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8204
 * are ordered in document order
8205
 *
8206
 * Returns the next element following that axis
8207
 */
8208
xmlNodePtr
8209
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8210
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8211
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8212
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8213
0
        return(cur->children);
8214
8215
0
    if (cur == NULL) {
8216
0
        cur = ctxt->context->node;
8217
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8218
0
            cur = cur->parent;
8219
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8220
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8221
8222
0
            if ((ns->next == NULL) ||
8223
0
                (ns->next->type == XML_NAMESPACE_DECL))
8224
0
                return (NULL);
8225
0
            cur = (xmlNodePtr) ns->next;
8226
0
        }
8227
0
    }
8228
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8229
0
    if (cur->next != NULL) return(cur->next) ;
8230
0
    do {
8231
0
        cur = cur->parent;
8232
0
        if (cur == NULL) break;
8233
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8234
0
        if (cur->next != NULL) return(cur->next);
8235
0
    } while (cur != NULL);
8236
0
    return(cur);
8237
0
}
8238
8239
/*
8240
 * xmlXPathIsAncestor:
8241
 * @ancestor:  the ancestor node
8242
 * @node:  the current node
8243
 *
8244
 * Check that @ancestor is a @node's ancestor
8245
 *
8246
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8247
 */
8248
static int
8249
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8250
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8251
0
    if (node->type == XML_NAMESPACE_DECL)
8252
0
        return(0);
8253
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8254
0
        return(0);
8255
    /* nodes need to be in the same document */
8256
0
    if (ancestor->doc != node->doc) return(0);
8257
    /* avoid searching if ancestor or node is the root node */
8258
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8259
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8260
0
    while (node->parent != NULL) {
8261
0
        if (node->parent == ancestor)
8262
0
            return(1);
8263
0
  node = node->parent;
8264
0
    }
8265
0
    return(0);
8266
0
}
8267
8268
/**
8269
 * xmlXPathNextPreceding:
8270
 * @ctxt:  the XPath Parser context
8271
 * @cur:  the current node in the traversal
8272
 *
8273
 * Traversal function for the "preceding" direction
8274
 * the preceding axis contains all nodes in the same document as the context
8275
 * node that are before the context node in document order, excluding any
8276
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8277
 * ordered in reverse document order
8278
 *
8279
 * Returns the next element following that axis
8280
 */
8281
xmlNodePtr
8282
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8283
0
{
8284
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8285
0
    if (cur == NULL) {
8286
0
        cur = ctxt->context->node;
8287
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8288
0
            cur = cur->parent;
8289
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8290
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8291
8292
0
            if ((ns->next == NULL) ||
8293
0
                (ns->next->type == XML_NAMESPACE_DECL))
8294
0
                return (NULL);
8295
0
            cur = (xmlNodePtr) ns->next;
8296
0
        }
8297
0
    }
8298
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8299
0
  return (NULL);
8300
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8301
0
  cur = cur->prev;
8302
0
    do {
8303
0
        if (cur->prev != NULL) {
8304
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8305
0
            return (cur);
8306
0
        }
8307
8308
0
        cur = cur->parent;
8309
0
        if (cur == NULL)
8310
0
            return (NULL);
8311
0
        if (cur == ctxt->context->doc->children)
8312
0
            return (NULL);
8313
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8314
0
    return (cur);
8315
0
}
8316
8317
/**
8318
 * xmlXPathNextPrecedingInternal:
8319
 * @ctxt:  the XPath Parser context
8320
 * @cur:  the current node in the traversal
8321
 *
8322
 * Traversal function for the "preceding" direction
8323
 * the preceding axis contains all nodes in the same document as the context
8324
 * node that are before the context node in document order, excluding any
8325
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8326
 * ordered in reverse document order
8327
 * This is a faster implementation but internal only since it requires a
8328
 * state kept in the parser context: ctxt->ancestor.
8329
 *
8330
 * Returns the next element following that axis
8331
 */
8332
static xmlNodePtr
8333
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8334
                              xmlNodePtr cur)
8335
0
{
8336
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8337
0
    if (cur == NULL) {
8338
0
        cur = ctxt->context->node;
8339
0
        if (cur == NULL)
8340
0
            return (NULL);
8341
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8342
0
            cur = cur->parent;
8343
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8344
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346
0
            if ((ns->next == NULL) ||
8347
0
                (ns->next->type == XML_NAMESPACE_DECL))
8348
0
                return (NULL);
8349
0
            cur = (xmlNodePtr) ns->next;
8350
0
        }
8351
0
        ctxt->ancestor = cur->parent;
8352
0
    }
8353
0
    if (cur->type == XML_NAMESPACE_DECL)
8354
0
        return(NULL);
8355
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8356
0
  cur = cur->prev;
8357
0
    while (cur->prev == NULL) {
8358
0
        cur = cur->parent;
8359
0
        if (cur == NULL)
8360
0
            return (NULL);
8361
0
        if (cur == ctxt->context->doc->children)
8362
0
            return (NULL);
8363
0
        if (cur != ctxt->ancestor)
8364
0
            return (cur);
8365
0
        ctxt->ancestor = cur->parent;
8366
0
    }
8367
0
    cur = cur->prev;
8368
0
    while (cur->last != NULL)
8369
0
        cur = cur->last;
8370
0
    return (cur);
8371
0
}
8372
8373
/**
8374
 * xmlXPathNextNamespace:
8375
 * @ctxt:  the XPath Parser context
8376
 * @cur:  the current attribute in the traversal
8377
 *
8378
 * Traversal function for the "namespace" direction
8379
 * the namespace axis contains the namespace nodes of the context node;
8380
 * the order of nodes on this axis is implementation-defined; the axis will
8381
 * be empty unless the context node is an element
8382
 *
8383
 * We keep the XML namespace node at the end of the list.
8384
 *
8385
 * Returns the next element following that axis
8386
 */
8387
xmlNodePtr
8388
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8389
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8390
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8391
0
    if (cur == NULL) {
8392
0
        if (ctxt->context->tmpNsList != NULL)
8393
0
      xmlFree(ctxt->context->tmpNsList);
8394
0
  ctxt->context->tmpNsList =
8395
0
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8396
0
  ctxt->context->tmpNsNr = 0;
8397
0
  if (ctxt->context->tmpNsList != NULL) {
8398
0
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8399
0
    ctxt->context->tmpNsNr++;
8400
0
      }
8401
0
  }
8402
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
8403
0
    }
8404
0
    if (ctxt->context->tmpNsNr > 0) {
8405
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8406
0
    } else {
8407
0
  if (ctxt->context->tmpNsList != NULL)
8408
0
      xmlFree(ctxt->context->tmpNsList);
8409
0
  ctxt->context->tmpNsList = NULL;
8410
0
  return(NULL);
8411
0
    }
8412
0
}
8413
8414
/**
8415
 * xmlXPathNextAttribute:
8416
 * @ctxt:  the XPath Parser context
8417
 * @cur:  the current attribute in the traversal
8418
 *
8419
 * Traversal function for the "attribute" direction
8420
 * TODO: support DTD inherited default attributes
8421
 *
8422
 * Returns the next element following that axis
8423
 */
8424
xmlNodePtr
8425
2.17M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8426
2.17M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8427
2.17M
    if (ctxt->context->node == NULL)
8428
0
  return(NULL);
8429
2.17M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8430
972k
  return(NULL);
8431
1.19M
    if (cur == NULL) {
8432
773k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8433
0
      return(NULL);
8434
773k
        return((xmlNodePtr)ctxt->context->node->properties);
8435
773k
    }
8436
424k
    return((xmlNodePtr)cur->next);
8437
1.19M
}
8438
8439
/************************************************************************
8440
 *                  *
8441
 *    NodeTest Functions          *
8442
 *                  *
8443
 ************************************************************************/
8444
8445
#define IS_FUNCTION     200
8446
8447
8448
/************************************************************************
8449
 *                  *
8450
 *    Implicit tree core function library     *
8451
 *                  *
8452
 ************************************************************************/
8453
8454
/**
8455
 * xmlXPathRoot:
8456
 * @ctxt:  the XPath Parser context
8457
 *
8458
 * Initialize the context to the root of the document
8459
 */
8460
void
8461
240k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8462
240k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8463
0
  return;
8464
240k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8465
240k
  (xmlNodePtr) ctxt->context->doc));
8466
240k
}
8467
8468
/************************************************************************
8469
 *                  *
8470
 *    The explicit core function library      *
8471
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8472
 *                  *
8473
 ************************************************************************/
8474
8475
8476
/**
8477
 * xmlXPathLastFunction:
8478
 * @ctxt:  the XPath Parser context
8479
 * @nargs:  the number of arguments
8480
 *
8481
 * Implement the last() XPath function
8482
 *    number last()
8483
 * The last function returns the number of nodes in the context node list.
8484
 */
8485
void
8486
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8487
0
    CHECK_ARITY(0);
8488
0
    if (ctxt->context->contextSize >= 0) {
8489
0
  valuePush(ctxt,
8490
0
      xmlXPathCacheNewFloat(ctxt->context,
8491
0
    (double) ctxt->context->contextSize));
8492
#ifdef DEBUG_EXPR
8493
  xmlGenericError(xmlGenericErrorContext,
8494
    "last() : %d\n", ctxt->context->contextSize);
8495
#endif
8496
0
    } else {
8497
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8498
0
    }
8499
0
}
8500
8501
/**
8502
 * xmlXPathPositionFunction:
8503
 * @ctxt:  the XPath Parser context
8504
 * @nargs:  the number of arguments
8505
 *
8506
 * Implement the position() XPath function
8507
 *    number position()
8508
 * The position function returns the position of the context node in the
8509
 * context node list. The first position is 1, and so the last position
8510
 * will be equal to last().
8511
 */
8512
void
8513
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514
0
    CHECK_ARITY(0);
8515
0
    if (ctxt->context->proximityPosition >= 0) {
8516
0
  valuePush(ctxt,
8517
0
        xmlXPathCacheNewFloat(ctxt->context,
8518
0
    (double) ctxt->context->proximityPosition));
8519
#ifdef DEBUG_EXPR
8520
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8521
    ctxt->context->proximityPosition);
8522
#endif
8523
0
    } else {
8524
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8525
0
    }
8526
0
}
8527
8528
/**
8529
 * xmlXPathCountFunction:
8530
 * @ctxt:  the XPath Parser context
8531
 * @nargs:  the number of arguments
8532
 *
8533
 * Implement the count() XPath function
8534
 *    number count(node-set)
8535
 */
8536
void
8537
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538
0
    xmlXPathObjectPtr cur;
8539
8540
0
    CHECK_ARITY(1);
8541
0
    if ((ctxt->value == NULL) ||
8542
0
  ((ctxt->value->type != XPATH_NODESET) &&
8543
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8544
0
  XP_ERROR(XPATH_INVALID_TYPE);
8545
0
    cur = valuePop(ctxt);
8546
8547
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
8548
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8549
0
    else
8550
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8551
0
      (double) cur->nodesetval->nodeNr));
8552
0
    xmlXPathReleaseObject(ctxt->context, cur);
8553
0
}
8554
8555
/**
8556
 * xmlXPathGetElementsByIds:
8557
 * @doc:  the document
8558
 * @ids:  a whitespace separated list of IDs
8559
 *
8560
 * Selects elements by their unique ID.
8561
 *
8562
 * Returns a node-set of selected elements.
8563
 */
8564
static xmlNodeSetPtr
8565
40.2k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8566
40.2k
    xmlNodeSetPtr ret;
8567
40.2k
    const xmlChar *cur = ids;
8568
40.2k
    xmlChar *ID;
8569
40.2k
    xmlAttrPtr attr;
8570
40.2k
    xmlNodePtr elem = NULL;
8571
8572
40.2k
    if (ids == NULL) return(NULL);
8573
8574
40.2k
    ret = xmlXPathNodeSetCreate(NULL);
8575
40.2k
    if (ret == NULL)
8576
0
        return(ret);
8577
8578
40.2k
    while (IS_BLANK_CH(*cur)) cur++;
8579
80.5k
    while (*cur != 0) {
8580
3.87M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8581
3.83M
      cur++;
8582
8583
40.2k
        ID = xmlStrndup(ids, cur - ids);
8584
40.2k
  if (ID != NULL) {
8585
      /*
8586
       * We used to check the fact that the value passed
8587
       * was an NCName, but this generated much troubles for
8588
       * me and Aleksey Sanin, people blatantly violated that
8589
       * constraint, like Visa3D spec.
8590
       * if (xmlValidateNCName(ID, 1) == 0)
8591
       */
8592
40.2k
      attr = xmlGetID(doc, ID);
8593
40.2k
      if (attr != NULL) {
8594
2.13k
    if (attr->type == XML_ATTRIBUTE_NODE)
8595
1.91k
        elem = attr->parent;
8596
222
    else if (attr->type == XML_ELEMENT_NODE)
8597
0
        elem = (xmlNodePtr) attr;
8598
222
    else
8599
222
        elem = NULL;
8600
                /* TODO: Check memory error. */
8601
2.13k
    if (elem != NULL)
8602
1.91k
        xmlXPathNodeSetAdd(ret, elem);
8603
2.13k
      }
8604
40.2k
      xmlFree(ID);
8605
40.2k
  }
8606
8607
40.2k
  while (IS_BLANK_CH(*cur)) cur++;
8608
40.2k
  ids = cur;
8609
40.2k
    }
8610
40.2k
    return(ret);
8611
40.2k
}
8612
8613
/**
8614
 * xmlXPathIdFunction:
8615
 * @ctxt:  the XPath Parser context
8616
 * @nargs:  the number of arguments
8617
 *
8618
 * Implement the id() XPath function
8619
 *    node-set id(object)
8620
 * The id function selects elements by their unique ID
8621
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8622
 * then the result is the union of the result of applying id to the
8623
 * string value of each of the nodes in the argument node-set. When the
8624
 * argument to id is of any other type, the argument is converted to a
8625
 * string as if by a call to the string function; the string is split
8626
 * into a whitespace-separated list of tokens (whitespace is any sequence
8627
 * of characters matching the production S); the result is a node-set
8628
 * containing the elements in the same document as the context node that
8629
 * have a unique ID equal to any of the tokens in the list.
8630
 */
8631
void
8632
40.2k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8633
40.2k
    xmlChar *tokens;
8634
40.2k
    xmlNodeSetPtr ret;
8635
40.2k
    xmlXPathObjectPtr obj;
8636
8637
120k
    CHECK_ARITY(1);
8638
120k
    obj = valuePop(ctxt);
8639
120k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8640
40.2k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8641
0
  xmlNodeSetPtr ns;
8642
0
  int i;
8643
8644
        /* TODO: Check memory error. */
8645
0
  ret = xmlXPathNodeSetCreate(NULL);
8646
8647
0
  if (obj->nodesetval != NULL) {
8648
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8649
0
    tokens =
8650
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8651
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8652
                /* TODO: Check memory error. */
8653
0
    ret = xmlXPathNodeSetMerge(ret, ns);
8654
0
    xmlXPathFreeNodeSet(ns);
8655
0
    if (tokens != NULL)
8656
0
        xmlFree(tokens);
8657
0
      }
8658
0
  }
8659
0
  xmlXPathReleaseObject(ctxt->context, obj);
8660
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8661
0
  return;
8662
0
    }
8663
40.2k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8664
40.2k
    if (obj == NULL) return;
8665
40.2k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8666
40.2k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8667
40.2k
    xmlXPathReleaseObject(ctxt->context, obj);
8668
40.2k
    return;
8669
40.2k
}
8670
8671
/**
8672
 * xmlXPathLocalNameFunction:
8673
 * @ctxt:  the XPath Parser context
8674
 * @nargs:  the number of arguments
8675
 *
8676
 * Implement the local-name() XPath function
8677
 *    string local-name(node-set?)
8678
 * The local-name function returns a string containing the local part
8679
 * of the name of the node in the argument node-set that is first in
8680
 * document order. If the node-set is empty or the first node has no
8681
 * name, an empty string is returned. If the argument is omitted it
8682
 * defaults to the context node.
8683
 */
8684
void
8685
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8686
0
    xmlXPathObjectPtr cur;
8687
8688
0
    if (ctxt == NULL) return;
8689
8690
0
    if (nargs == 0) {
8691
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8692
0
      ctxt->context->node));
8693
0
  nargs = 1;
8694
0
    }
8695
8696
0
    CHECK_ARITY(1);
8697
0
    if ((ctxt->value == NULL) ||
8698
0
  ((ctxt->value->type != XPATH_NODESET) &&
8699
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8700
0
  XP_ERROR(XPATH_INVALID_TYPE);
8701
0
    cur = valuePop(ctxt);
8702
8703
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8704
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705
0
    } else {
8706
0
  int i = 0; /* Should be first in document order !!!!! */
8707
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8708
0
  case XML_ELEMENT_NODE:
8709
0
  case XML_ATTRIBUTE_NODE:
8710
0
  case XML_PI_NODE:
8711
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8712
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
0
      else
8714
0
    valuePush(ctxt,
8715
0
          xmlXPathCacheNewString(ctxt->context,
8716
0
      cur->nodesetval->nodeTab[i]->name));
8717
0
      break;
8718
0
  case XML_NAMESPACE_DECL:
8719
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8720
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8721
0
      break;
8722
0
  default:
8723
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8724
0
  }
8725
0
    }
8726
0
    xmlXPathReleaseObject(ctxt->context, cur);
8727
0
}
8728
8729
/**
8730
 * xmlXPathNamespaceURIFunction:
8731
 * @ctxt:  the XPath Parser context
8732
 * @nargs:  the number of arguments
8733
 *
8734
 * Implement the namespace-uri() XPath function
8735
 *    string namespace-uri(node-set?)
8736
 * The namespace-uri function returns a string containing the
8737
 * namespace URI of the expanded name of the node in the argument
8738
 * node-set that is first in document order. If the node-set is empty,
8739
 * the first node has no name, or the expanded name has no namespace
8740
 * URI, an empty string is returned. If the argument is omitted it
8741
 * defaults to the context node.
8742
 */
8743
void
8744
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8745
0
    xmlXPathObjectPtr cur;
8746
8747
0
    if (ctxt == NULL) return;
8748
8749
0
    if (nargs == 0) {
8750
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8751
0
      ctxt->context->node));
8752
0
  nargs = 1;
8753
0
    }
8754
0
    CHECK_ARITY(1);
8755
0
    if ((ctxt->value == NULL) ||
8756
0
  ((ctxt->value->type != XPATH_NODESET) &&
8757
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8758
0
  XP_ERROR(XPATH_INVALID_TYPE);
8759
0
    cur = valuePop(ctxt);
8760
8761
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8762
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763
0
    } else {
8764
0
  int i = 0; /* Should be first in document order !!!!! */
8765
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8766
0
  case XML_ELEMENT_NODE:
8767
0
  case XML_ATTRIBUTE_NODE:
8768
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8769
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770
0
      else
8771
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8772
0
        cur->nodesetval->nodeTab[i]->ns->href));
8773
0
      break;
8774
0
  default:
8775
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8776
0
  }
8777
0
    }
8778
0
    xmlXPathReleaseObject(ctxt->context, cur);
8779
0
}
8780
8781
/**
8782
 * xmlXPathNameFunction:
8783
 * @ctxt:  the XPath Parser context
8784
 * @nargs:  the number of arguments
8785
 *
8786
 * Implement the name() XPath function
8787
 *    string name(node-set?)
8788
 * The name function returns a string containing a QName representing
8789
 * the name of the node in the argument node-set that is first in document
8790
 * order. The QName must represent the name with respect to the namespace
8791
 * declarations in effect on the node whose name is being represented.
8792
 * Typically, this will be the form in which the name occurred in the XML
8793
 * source. This need not be the case if there are namespace declarations
8794
 * in effect on the node that associate multiple prefixes with the same
8795
 * namespace. However, an implementation may include information about
8796
 * the original prefix in its representation of nodes; in this case, an
8797
 * implementation can ensure that the returned string is always the same
8798
 * as the QName used in the XML source. If the argument it omitted it
8799
 * defaults to the context node.
8800
 * Libxml keep the original prefix so the "real qualified name" used is
8801
 * returned.
8802
 */
8803
static void
8804
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8805
0
{
8806
0
    xmlXPathObjectPtr cur;
8807
8808
0
    if (nargs == 0) {
8809
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8810
0
      ctxt->context->node));
8811
0
        nargs = 1;
8812
0
    }
8813
8814
0
    CHECK_ARITY(1);
8815
0
    if ((ctxt->value == NULL) ||
8816
0
        ((ctxt->value->type != XPATH_NODESET) &&
8817
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
8818
0
        XP_ERROR(XPATH_INVALID_TYPE);
8819
0
    cur = valuePop(ctxt);
8820
8821
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8822
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8823
0
    } else {
8824
0
        int i = 0;              /* Should be first in document order !!!!! */
8825
8826
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8827
0
            case XML_ELEMENT_NODE:
8828
0
            case XML_ATTRIBUTE_NODE:
8829
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8830
0
        valuePush(ctxt,
8831
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8832
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8833
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8834
0
        valuePush(ctxt,
8835
0
            xmlXPathCacheNewString(ctxt->context,
8836
0
          cur->nodesetval->nodeTab[i]->name));
8837
0
    } else {
8838
0
        xmlChar *fullname;
8839
8840
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8841
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8842
0
             NULL, 0);
8843
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8844
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8845
0
        if (fullname == NULL) {
8846
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8847
0
        }
8848
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8849
0
      ctxt->context, fullname));
8850
0
                }
8851
0
                break;
8852
0
            default:
8853
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8854
0
        cur->nodesetval->nodeTab[i]));
8855
0
                xmlXPathLocalNameFunction(ctxt, 1);
8856
0
        }
8857
0
    }
8858
0
    xmlXPathReleaseObject(ctxt->context, cur);
8859
0
}
8860
8861
8862
/**
8863
 * xmlXPathStringFunction:
8864
 * @ctxt:  the XPath Parser context
8865
 * @nargs:  the number of arguments
8866
 *
8867
 * Implement the string() XPath function
8868
 *    string string(object?)
8869
 * The string function converts an object to a string as follows:
8870
 *    - A node-set is converted to a string by returning the value of
8871
 *      the node in the node-set that is first in document order.
8872
 *      If the node-set is empty, an empty string is returned.
8873
 *    - A number is converted to a string as follows
8874
 *      + NaN is converted to the string NaN
8875
 *      + positive zero is converted to the string 0
8876
 *      + negative zero is converted to the string 0
8877
 *      + positive infinity is converted to the string Infinity
8878
 *      + negative infinity is converted to the string -Infinity
8879
 *      + if the number is an integer, the number is represented in
8880
 *        decimal form as a Number with no decimal point and no leading
8881
 *        zeros, preceded by a minus sign (-) if the number is negative
8882
 *      + otherwise, the number is represented in decimal form as a
8883
 *        Number including a decimal point with at least one digit
8884
 *        before the decimal point and at least one digit after the
8885
 *        decimal point, preceded by a minus sign (-) if the number
8886
 *        is negative; there must be no leading zeros before the decimal
8887
 *        point apart possibly from the one required digit immediately
8888
 *        before the decimal point; beyond the one required digit
8889
 *        after the decimal point there must be as many, but only as
8890
 *        many, more digits as are needed to uniquely distinguish the
8891
 *        number from all other IEEE 754 numeric values.
8892
 *    - The boolean false value is converted to the string false.
8893
 *      The boolean true value is converted to the string true.
8894
 *
8895
 * If the argument is omitted, it defaults to a node-set with the
8896
 * context node as its only member.
8897
 */
8898
void
8899
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900
0
    xmlXPathObjectPtr cur;
8901
8902
0
    if (ctxt == NULL) return;
8903
0
    if (nargs == 0) {
8904
0
    valuePush(ctxt,
8905
0
  xmlXPathCacheWrapString(ctxt->context,
8906
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8907
0
  return;
8908
0
    }
8909
8910
0
    CHECK_ARITY(1);
8911
0
    cur = valuePop(ctxt);
8912
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8913
0
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8914
0
}
8915
8916
/**
8917
 * xmlXPathStringLengthFunction:
8918
 * @ctxt:  the XPath Parser context
8919
 * @nargs:  the number of arguments
8920
 *
8921
 * Implement the string-length() XPath function
8922
 *    number string-length(string?)
8923
 * The string-length returns the number of characters in the string
8924
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8925
 * the context node converted to a string, in other words the value
8926
 * of the context node.
8927
 */
8928
void
8929
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8930
0
    xmlXPathObjectPtr cur;
8931
8932
0
    if (nargs == 0) {
8933
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8934
0
      return;
8935
0
  if (ctxt->context->node == NULL) {
8936
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8937
0
  } else {
8938
0
      xmlChar *content;
8939
8940
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8941
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8942
0
    xmlUTF8Strlen(content)));
8943
0
      xmlFree(content);
8944
0
  }
8945
0
  return;
8946
0
    }
8947
0
    CHECK_ARITY(1);
8948
0
    CAST_TO_STRING;
8949
0
    CHECK_TYPE(XPATH_STRING);
8950
0
    cur = valuePop(ctxt);
8951
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8952
0
  xmlUTF8Strlen(cur->stringval)));
8953
0
    xmlXPathReleaseObject(ctxt->context, cur);
8954
0
}
8955
8956
/**
8957
 * xmlXPathConcatFunction:
8958
 * @ctxt:  the XPath Parser context
8959
 * @nargs:  the number of arguments
8960
 *
8961
 * Implement the concat() XPath function
8962
 *    string concat(string, string, string*)
8963
 * The concat function returns the concatenation of its arguments.
8964
 */
8965
void
8966
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8967
0
    xmlXPathObjectPtr cur, newobj;
8968
0
    xmlChar *tmp;
8969
8970
0
    if (ctxt == NULL) return;
8971
0
    if (nargs < 2) {
8972
0
  CHECK_ARITY(2);
8973
0
    }
8974
8975
0
    CAST_TO_STRING;
8976
0
    cur = valuePop(ctxt);
8977
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8978
0
  xmlXPathReleaseObject(ctxt->context, cur);
8979
0
  return;
8980
0
    }
8981
0
    nargs--;
8982
8983
0
    while (nargs > 0) {
8984
0
  CAST_TO_STRING;
8985
0
  newobj = valuePop(ctxt);
8986
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8987
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8988
0
      xmlXPathReleaseObject(ctxt->context, cur);
8989
0
      XP_ERROR(XPATH_INVALID_TYPE);
8990
0
  }
8991
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8992
0
  newobj->stringval = cur->stringval;
8993
0
  cur->stringval = tmp;
8994
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8995
0
  nargs--;
8996
0
    }
8997
0
    valuePush(ctxt, cur);
8998
0
}
8999
9000
/**
9001
 * xmlXPathContainsFunction:
9002
 * @ctxt:  the XPath Parser context
9003
 * @nargs:  the number of arguments
9004
 *
9005
 * Implement the contains() XPath function
9006
 *    boolean contains(string, string)
9007
 * The contains function returns true if the first argument string
9008
 * contains the second argument string, and otherwise returns false.
9009
 */
9010
void
9011
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012
0
    xmlXPathObjectPtr hay, needle;
9013
9014
0
    CHECK_ARITY(2);
9015
0
    CAST_TO_STRING;
9016
0
    CHECK_TYPE(XPATH_STRING);
9017
0
    needle = valuePop(ctxt);
9018
0
    CAST_TO_STRING;
9019
0
    hay = valuePop(ctxt);
9020
9021
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9022
0
  xmlXPathReleaseObject(ctxt->context, hay);
9023
0
  xmlXPathReleaseObject(ctxt->context, needle);
9024
0
  XP_ERROR(XPATH_INVALID_TYPE);
9025
0
    }
9026
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9027
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9028
0
    else
9029
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9030
0
    xmlXPathReleaseObject(ctxt->context, hay);
9031
0
    xmlXPathReleaseObject(ctxt->context, needle);
9032
0
}
9033
9034
/**
9035
 * xmlXPathStartsWithFunction:
9036
 * @ctxt:  the XPath Parser context
9037
 * @nargs:  the number of arguments
9038
 *
9039
 * Implement the starts-with() XPath function
9040
 *    boolean starts-with(string, string)
9041
 * The starts-with function returns true if the first argument string
9042
 * starts with the second argument string, and otherwise returns false.
9043
 */
9044
void
9045
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046
0
    xmlXPathObjectPtr hay, needle;
9047
0
    int n;
9048
9049
0
    CHECK_ARITY(2);
9050
0
    CAST_TO_STRING;
9051
0
    CHECK_TYPE(XPATH_STRING);
9052
0
    needle = valuePop(ctxt);
9053
0
    CAST_TO_STRING;
9054
0
    hay = valuePop(ctxt);
9055
9056
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9057
0
  xmlXPathReleaseObject(ctxt->context, hay);
9058
0
  xmlXPathReleaseObject(ctxt->context, needle);
9059
0
  XP_ERROR(XPATH_INVALID_TYPE);
9060
0
    }
9061
0
    n = xmlStrlen(needle->stringval);
9062
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9063
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9064
0
    else
9065
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9066
0
    xmlXPathReleaseObject(ctxt->context, hay);
9067
0
    xmlXPathReleaseObject(ctxt->context, needle);
9068
0
}
9069
9070
/**
9071
 * xmlXPathSubstringFunction:
9072
 * @ctxt:  the XPath Parser context
9073
 * @nargs:  the number of arguments
9074
 *
9075
 * Implement the substring() XPath function
9076
 *    string substring(string, number, number?)
9077
 * The substring function returns the substring of the first argument
9078
 * starting at the position specified in the second argument with
9079
 * length specified in the third argument. For example,
9080
 * substring("12345",2,3) returns "234". If the third argument is not
9081
 * specified, it returns the substring starting at the position specified
9082
 * in the second argument and continuing to the end of the string. For
9083
 * example, substring("12345",2) returns "2345".  More precisely, each
9084
 * character in the string (see [3.6 Strings]) is considered to have a
9085
 * numeric position: the position of the first character is 1, the position
9086
 * of the second character is 2 and so on. The returned substring contains
9087
 * those characters for which the position of the character is greater than
9088
 * or equal to the second argument and, if the third argument is specified,
9089
 * less than the sum of the second and third arguments; the comparisons
9090
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9091
 *  - substring("12345", 1.5, 2.6) returns "234"
9092
 *  - substring("12345", 0, 3) returns "12"
9093
 *  - substring("12345", 0 div 0, 3) returns ""
9094
 *  - substring("12345", 1, 0 div 0) returns ""
9095
 *  - substring("12345", -42, 1 div 0) returns "12345"
9096
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9097
 */
9098
void
9099
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9100
0
    xmlXPathObjectPtr str, start, len;
9101
0
    double le=0, in;
9102
0
    int i = 1, j = INT_MAX;
9103
9104
0
    if (nargs < 2) {
9105
0
  CHECK_ARITY(2);
9106
0
    }
9107
0
    if (nargs > 3) {
9108
0
  CHECK_ARITY(3);
9109
0
    }
9110
    /*
9111
     * take care of possible last (position) argument
9112
    */
9113
0
    if (nargs == 3) {
9114
0
  CAST_TO_NUMBER;
9115
0
  CHECK_TYPE(XPATH_NUMBER);
9116
0
  len = valuePop(ctxt);
9117
0
  le = len->floatval;
9118
0
  xmlXPathReleaseObject(ctxt->context, len);
9119
0
    }
9120
9121
0
    CAST_TO_NUMBER;
9122
0
    CHECK_TYPE(XPATH_NUMBER);
9123
0
    start = valuePop(ctxt);
9124
0
    in = start->floatval;
9125
0
    xmlXPathReleaseObject(ctxt->context, start);
9126
0
    CAST_TO_STRING;
9127
0
    CHECK_TYPE(XPATH_STRING);
9128
0
    str = valuePop(ctxt);
9129
9130
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9131
0
        i = INT_MAX;
9132
0
    } else if (in >= 1.0) {
9133
0
        i = (int)in;
9134
0
        if (in - floor(in) >= 0.5)
9135
0
            i += 1;
9136
0
    }
9137
9138
0
    if (nargs == 3) {
9139
0
        double rin, rle, end;
9140
9141
0
        rin = floor(in);
9142
0
        if (in - rin >= 0.5)
9143
0
            rin += 1.0;
9144
9145
0
        rle = floor(le);
9146
0
        if (le - rle >= 0.5)
9147
0
            rle += 1.0;
9148
9149
0
        end = rin + rle;
9150
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9151
0
            j = 1;
9152
0
        } else if (end < INT_MAX) {
9153
0
            j = (int)end;
9154
0
        }
9155
0
    }
9156
9157
0
    if (i < j) {
9158
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9159
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9160
0
  xmlFree(ret);
9161
0
    } else {
9162
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9163
0
    }
9164
9165
0
    xmlXPathReleaseObject(ctxt->context, str);
9166
0
}
9167
9168
/**
9169
 * xmlXPathSubstringBeforeFunction:
9170
 * @ctxt:  the XPath Parser context
9171
 * @nargs:  the number of arguments
9172
 *
9173
 * Implement the substring-before() XPath function
9174
 *    string substring-before(string, string)
9175
 * The substring-before function returns the substring of the first
9176
 * argument string that precedes the first occurrence of the second
9177
 * argument string in the first argument string, or the empty string
9178
 * if the first argument string does not contain the second argument
9179
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9180
 */
9181
void
9182
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9183
0
  xmlXPathObjectPtr str;
9184
0
  xmlXPathObjectPtr find;
9185
0
  xmlBufPtr target;
9186
0
  const xmlChar *point;
9187
0
  int offset;
9188
9189
0
  CHECK_ARITY(2);
9190
0
  CAST_TO_STRING;
9191
0
  find = valuePop(ctxt);
9192
0
  CAST_TO_STRING;
9193
0
  str = valuePop(ctxt);
9194
9195
0
  target = xmlBufCreate();
9196
0
  if (target) {
9197
0
    point = xmlStrstr(str->stringval, find->stringval);
9198
0
    if (point) {
9199
0
      offset = point - str->stringval;
9200
0
      xmlBufAdd(target, str->stringval, offset);
9201
0
    }
9202
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9203
0
  xmlBufContent(target)));
9204
0
    xmlBufFree(target);
9205
0
  }
9206
0
  xmlXPathReleaseObject(ctxt->context, str);
9207
0
  xmlXPathReleaseObject(ctxt->context, find);
9208
0
}
9209
9210
/**
9211
 * xmlXPathSubstringAfterFunction:
9212
 * @ctxt:  the XPath Parser context
9213
 * @nargs:  the number of arguments
9214
 *
9215
 * Implement the substring-after() XPath function
9216
 *    string substring-after(string, string)
9217
 * The substring-after function returns the substring of the first
9218
 * argument string that follows the first occurrence of the second
9219
 * argument string in the first argument string, or the empty stringi
9220
 * if the first argument string does not contain the second argument
9221
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9222
 * and substring-after("1999/04/01","19") returns 99/04/01.
9223
 */
9224
void
9225
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9226
0
  xmlXPathObjectPtr str;
9227
0
  xmlXPathObjectPtr find;
9228
0
  xmlBufPtr target;
9229
0
  const xmlChar *point;
9230
0
  int offset;
9231
9232
0
  CHECK_ARITY(2);
9233
0
  CAST_TO_STRING;
9234
0
  find = valuePop(ctxt);
9235
0
  CAST_TO_STRING;
9236
0
  str = valuePop(ctxt);
9237
9238
0
  target = xmlBufCreate();
9239
0
  if (target) {
9240
0
    point = xmlStrstr(str->stringval, find->stringval);
9241
0
    if (point) {
9242
0
      offset = point - str->stringval + xmlStrlen(find->stringval);
9243
0
      xmlBufAdd(target, &str->stringval[offset],
9244
0
       xmlStrlen(str->stringval) - offset);
9245
0
    }
9246
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247
0
  xmlBufContent(target)));
9248
0
    xmlBufFree(target);
9249
0
  }
9250
0
  xmlXPathReleaseObject(ctxt->context, str);
9251
0
  xmlXPathReleaseObject(ctxt->context, find);
9252
0
}
9253
9254
/**
9255
 * xmlXPathNormalizeFunction:
9256
 * @ctxt:  the XPath Parser context
9257
 * @nargs:  the number of arguments
9258
 *
9259
 * Implement the normalize-space() XPath function
9260
 *    string normalize-space(string?)
9261
 * The normalize-space function returns the argument string with white
9262
 * space normalized by stripping leading and trailing whitespace
9263
 * and replacing sequences of whitespace characters by a single
9264
 * space. Whitespace characters are the same allowed by the S production
9265
 * in XML. If the argument is omitted, it defaults to the context
9266
 * node converted to a string, in other words the value of the context node.
9267
 */
9268
void
9269
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270
0
    xmlChar *source, *target;
9271
0
    int blank;
9272
9273
0
    if (ctxt == NULL) return;
9274
0
    if (nargs == 0) {
9275
        /* Use current context node */
9276
0
        valuePush(ctxt,
9277
0
            xmlXPathCacheWrapString(ctxt->context,
9278
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9279
0
        nargs = 1;
9280
0
    }
9281
9282
0
    CHECK_ARITY(1);
9283
0
    CAST_TO_STRING;
9284
0
    CHECK_TYPE(XPATH_STRING);
9285
0
    source = ctxt->value->stringval;
9286
0
    if (source == NULL)
9287
0
        return;
9288
0
    target = source;
9289
9290
    /* Skip leading whitespaces */
9291
0
    while (IS_BLANK_CH(*source))
9292
0
        source++;
9293
9294
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9295
0
    blank = 0;
9296
0
    while (*source) {
9297
0
        if (IS_BLANK_CH(*source)) {
9298
0
      blank = 1;
9299
0
        } else {
9300
0
            if (blank) {
9301
0
                *target++ = 0x20;
9302
0
                blank = 0;
9303
0
            }
9304
0
            *target++ = *source;
9305
0
        }
9306
0
        source++;
9307
0
    }
9308
0
    *target = 0;
9309
0
}
9310
9311
/**
9312
 * xmlXPathTranslateFunction:
9313
 * @ctxt:  the XPath Parser context
9314
 * @nargs:  the number of arguments
9315
 *
9316
 * Implement the translate() XPath function
9317
 *    string translate(string, string, string)
9318
 * The translate function returns the first argument string with
9319
 * occurrences of characters in the second argument string replaced
9320
 * by the character at the corresponding position in the third argument
9321
 * string. For example, translate("bar","abc","ABC") returns the string
9322
 * BAr. If there is a character in the second argument string with no
9323
 * character at a corresponding position in the third argument string
9324
 * (because the second argument string is longer than the third argument
9325
 * string), then occurrences of that character in the first argument
9326
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9327
 * returns "AAA". If a character occurs more than once in second
9328
 * argument string, then the first occurrence determines the replacement
9329
 * character. If the third argument string is longer than the second
9330
 * argument string, then excess characters are ignored.
9331
 */
9332
void
9333
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334
0
    xmlXPathObjectPtr str;
9335
0
    xmlXPathObjectPtr from;
9336
0
    xmlXPathObjectPtr to;
9337
0
    xmlBufPtr target;
9338
0
    int offset, max;
9339
0
    xmlChar ch;
9340
0
    const xmlChar *point;
9341
0
    xmlChar *cptr;
9342
9343
0
    CHECK_ARITY(3);
9344
9345
0
    CAST_TO_STRING;
9346
0
    to = valuePop(ctxt);
9347
0
    CAST_TO_STRING;
9348
0
    from = valuePop(ctxt);
9349
0
    CAST_TO_STRING;
9350
0
    str = valuePop(ctxt);
9351
9352
0
    target = xmlBufCreate();
9353
0
    if (target) {
9354
0
  max = xmlUTF8Strlen(to->stringval);
9355
0
  for (cptr = str->stringval; (ch=*cptr); ) {
9356
0
      offset = xmlUTF8Strloc(from->stringval, cptr);
9357
0
      if (offset >= 0) {
9358
0
    if (offset < max) {
9359
0
        point = xmlUTF8Strpos(to->stringval, offset);
9360
0
        if (point)
9361
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9362
0
    }
9363
0
      } else
9364
0
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9365
9366
      /* Step to next character in input */
9367
0
      cptr++;
9368
0
      if ( ch & 0x80 ) {
9369
    /* if not simple ascii, verify proper format */
9370
0
    if ( (ch & 0xc0) != 0xc0 ) {
9371
0
        xmlGenericError(xmlGenericErrorContext,
9372
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373
                    /* not asserting an XPath error is probably better */
9374
0
        break;
9375
0
    }
9376
    /* then skip over remaining bytes for this char */
9377
0
    while ( (ch <<= 1) & 0x80 )
9378
0
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9379
0
      xmlGenericError(xmlGenericErrorContext,
9380
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                        /* not asserting an XPath error is probably better */
9382
0
      break;
9383
0
        }
9384
0
    if (ch & 0x80) /* must have had error encountered */
9385
0
        break;
9386
0
      }
9387
0
  }
9388
0
    }
9389
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9390
0
  xmlBufContent(target)));
9391
0
    xmlBufFree(target);
9392
0
    xmlXPathReleaseObject(ctxt->context, str);
9393
0
    xmlXPathReleaseObject(ctxt->context, from);
9394
0
    xmlXPathReleaseObject(ctxt->context, to);
9395
0
}
9396
9397
/**
9398
 * xmlXPathBooleanFunction:
9399
 * @ctxt:  the XPath Parser context
9400
 * @nargs:  the number of arguments
9401
 *
9402
 * Implement the boolean() XPath function
9403
 *    boolean boolean(object)
9404
 * The boolean function converts its argument to a boolean as follows:
9405
 *    - a number is true if and only if it is neither positive or
9406
 *      negative zero nor NaN
9407
 *    - a node-set is true if and only if it is non-empty
9408
 *    - a string is true if and only if its length is non-zero
9409
 */
9410
void
9411
19.6k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412
19.6k
    xmlXPathObjectPtr cur;
9413
9414
59.0k
    CHECK_ARITY(1);
9415
59.0k
    cur = valuePop(ctxt);
9416
59.0k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9417
19.6k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9418
19.6k
    valuePush(ctxt, cur);
9419
19.6k
}
9420
9421
/**
9422
 * xmlXPathNotFunction:
9423
 * @ctxt:  the XPath Parser context
9424
 * @nargs:  the number of arguments
9425
 *
9426
 * Implement the not() XPath function
9427
 *    boolean not(boolean)
9428
 * The not function returns true if its argument is false,
9429
 * and false otherwise.
9430
 */
9431
void
9432
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433
0
    CHECK_ARITY(1);
9434
0
    CAST_TO_BOOLEAN;
9435
0
    CHECK_TYPE(XPATH_BOOLEAN);
9436
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9437
0
}
9438
9439
/**
9440
 * xmlXPathTrueFunction:
9441
 * @ctxt:  the XPath Parser context
9442
 * @nargs:  the number of arguments
9443
 *
9444
 * Implement the true() XPath function
9445
 *    boolean true()
9446
 */
9447
void
9448
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449
0
    CHECK_ARITY(0);
9450
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9451
0
}
9452
9453
/**
9454
 * xmlXPathFalseFunction:
9455
 * @ctxt:  the XPath Parser context
9456
 * @nargs:  the number of arguments
9457
 *
9458
 * Implement the false() XPath function
9459
 *    boolean false()
9460
 */
9461
void
9462
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463
0
    CHECK_ARITY(0);
9464
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9465
0
}
9466
9467
/**
9468
 * xmlXPathLangFunction:
9469
 * @ctxt:  the XPath Parser context
9470
 * @nargs:  the number of arguments
9471
 *
9472
 * Implement the lang() XPath function
9473
 *    boolean lang(string)
9474
 * The lang function returns true or false depending on whether the
9475
 * language of the context node as specified by xml:lang attributes
9476
 * is the same as or is a sublanguage of the language specified by
9477
 * the argument string. The language of the context node is determined
9478
 * by the value of the xml:lang attribute on the context node, or, if
9479
 * the context node has no xml:lang attribute, by the value of the
9480
 * xml:lang attribute on the nearest ancestor of the context node that
9481
 * has an xml:lang attribute. If there is no such attribute, then lang
9482
 * returns false. If there is such an attribute, then lang returns
9483
 * true if the attribute value is equal to the argument ignoring case,
9484
 * or if there is some suffix starting with - such that the attribute
9485
 * value is equal to the argument ignoring that suffix of the attribute
9486
 * value and ignoring case.
9487
 */
9488
void
9489
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490
0
    xmlXPathObjectPtr val = NULL;
9491
0
    const xmlChar *theLang = NULL;
9492
0
    const xmlChar *lang;
9493
0
    int ret = 0;
9494
0
    int i;
9495
9496
0
    CHECK_ARITY(1);
9497
0
    CAST_TO_STRING;
9498
0
    CHECK_TYPE(XPATH_STRING);
9499
0
    val = valuePop(ctxt);
9500
0
    lang = val->stringval;
9501
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9502
0
    if ((theLang != NULL) && (lang != NULL)) {
9503
0
        for (i = 0;lang[i] != 0;i++)
9504
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9505
0
          goto not_equal;
9506
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9507
0
      ret = 1;
9508
0
    }
9509
0
not_equal:
9510
0
    if (theLang != NULL)
9511
0
  xmlFree((void *)theLang);
9512
9513
0
    xmlXPathReleaseObject(ctxt->context, val);
9514
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9515
0
}
9516
9517
/**
9518
 * xmlXPathNumberFunction:
9519
 * @ctxt:  the XPath Parser context
9520
 * @nargs:  the number of arguments
9521
 *
9522
 * Implement the number() XPath function
9523
 *    number number(object?)
9524
 */
9525
void
9526
656k
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527
656k
    xmlXPathObjectPtr cur;
9528
656k
    double res;
9529
9530
656k
    if (ctxt == NULL) return;
9531
656k
    if (nargs == 0) {
9532
0
  if (ctxt->context->node == NULL) {
9533
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9534
0
  } else {
9535
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536
9537
0
      res = xmlXPathStringEvalNumber(content);
9538
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9539
0
      xmlFree(content);
9540
0
  }
9541
0
  return;
9542
0
    }
9543
9544
2.62M
    CHECK_ARITY(1);
9545
2.62M
    cur = valuePop(ctxt);
9546
2.62M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9547
2.62M
}
9548
9549
/**
9550
 * xmlXPathSumFunction:
9551
 * @ctxt:  the XPath Parser context
9552
 * @nargs:  the number of arguments
9553
 *
9554
 * Implement the sum() XPath function
9555
 *    number sum(node-set)
9556
 * The sum function returns the sum of the values of the nodes in
9557
 * the argument node-set.
9558
 */
9559
void
9560
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561
0
    xmlXPathObjectPtr cur;
9562
0
    int i;
9563
0
    double res = 0.0;
9564
9565
0
    CHECK_ARITY(1);
9566
0
    if ((ctxt->value == NULL) ||
9567
0
  ((ctxt->value->type != XPATH_NODESET) &&
9568
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
9569
0
  XP_ERROR(XPATH_INVALID_TYPE);
9570
0
    cur = valuePop(ctxt);
9571
9572
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9573
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9575
0
  }
9576
0
    }
9577
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578
0
    xmlXPathReleaseObject(ctxt->context, cur);
9579
0
}
9580
9581
/**
9582
 * xmlXPathFloorFunction:
9583
 * @ctxt:  the XPath Parser context
9584
 * @nargs:  the number of arguments
9585
 *
9586
 * Implement the floor() XPath function
9587
 *    number floor(number)
9588
 * The floor function returns the largest (closest to positive infinity)
9589
 * number that is not greater than the argument and that is an integer.
9590
 */
9591
void
9592
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593
0
    CHECK_ARITY(1);
9594
0
    CAST_TO_NUMBER;
9595
0
    CHECK_TYPE(XPATH_NUMBER);
9596
9597
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9598
0
}
9599
9600
/**
9601
 * xmlXPathCeilingFunction:
9602
 * @ctxt:  the XPath Parser context
9603
 * @nargs:  the number of arguments
9604
 *
9605
 * Implement the ceiling() XPath function
9606
 *    number ceiling(number)
9607
 * The ceiling function returns the smallest (closest to negative infinity)
9608
 * number that is not less than the argument and that is an integer.
9609
 */
9610
void
9611
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612
0
    CHECK_ARITY(1);
9613
0
    CAST_TO_NUMBER;
9614
0
    CHECK_TYPE(XPATH_NUMBER);
9615
9616
#ifdef _AIX
9617
    /* Work around buggy ceil() function on AIX */
9618
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619
#else
9620
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9621
0
#endif
9622
0
}
9623
9624
/**
9625
 * xmlXPathRoundFunction:
9626
 * @ctxt:  the XPath Parser context
9627
 * @nargs:  the number of arguments
9628
 *
9629
 * Implement the round() XPath function
9630
 *    number round(number)
9631
 * The round function returns the number that is closest to the
9632
 * argument and that is an integer. If there are two such numbers,
9633
 * then the one that is closest to positive infinity is returned.
9634
 */
9635
void
9636
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637
0
    double f;
9638
9639
0
    CHECK_ARITY(1);
9640
0
    CAST_TO_NUMBER;
9641
0
    CHECK_TYPE(XPATH_NUMBER);
9642
9643
0
    f = ctxt->value->floatval;
9644
9645
0
    if ((f >= -0.5) && (f < 0.5)) {
9646
        /* Handles negative zero. */
9647
0
        ctxt->value->floatval *= 0.0;
9648
0
    }
9649
0
    else {
9650
0
        double rounded = floor(f);
9651
0
        if (f - rounded >= 0.5)
9652
0
            rounded += 1.0;
9653
0
        ctxt->value->floatval = rounded;
9654
0
    }
9655
0
}
9656
9657
/************************************************************************
9658
 *                  *
9659
 *      The Parser          *
9660
 *                  *
9661
 ************************************************************************/
9662
9663
/*
9664
 * a few forward declarations since we use a recursive call based
9665
 * implementation.
9666
 */
9667
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9668
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9669
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9670
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9671
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672
                                    int qualified);
9673
9674
/**
9675
 * xmlXPathCurrentChar:
9676
 * @ctxt:  the XPath parser context
9677
 * @cur:  pointer to the beginning of the char
9678
 * @len:  pointer to the length of the char read
9679
 *
9680
 * The current char value, if using UTF-8 this may actually span multiple
9681
 * bytes in the input buffer.
9682
 *
9683
 * Returns the current char value and its length
9684
 */
9685
9686
static int
9687
10.0M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688
10.0M
    unsigned char c;
9689
10.0M
    unsigned int val;
9690
10.0M
    const xmlChar *cur;
9691
9692
10.0M
    if (ctxt == NULL)
9693
0
  return(0);
9694
10.0M
    cur = ctxt->cur;
9695
9696
    /*
9697
     * We are supposed to handle UTF8, check it's valid
9698
     * From rfc2044: encoding of the Unicode values on UTF-8:
9699
     *
9700
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9701
     * 0000 0000-0000 007F   0xxxxxxx
9702
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9703
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9704
     *
9705
     * Check for the 0x110000 limit too
9706
     */
9707
10.0M
    c = *cur;
9708
10.0M
    if (c & 0x80) {
9709
1.42M
  if ((cur[1] & 0xc0) != 0x80)
9710
14.2k
      goto encoding_error;
9711
1.40M
  if ((c & 0xe0) == 0xe0) {
9712
9713
61.1k
      if ((cur[2] & 0xc0) != 0x80)
9714
653
    goto encoding_error;
9715
60.5k
      if ((c & 0xf0) == 0xf0) {
9716
1.21k
    if (((c & 0xf8) != 0xf0) ||
9717
1.21k
        ((cur[3] & 0xc0) != 0x80))
9718
705
        goto encoding_error;
9719
    /* 4-byte code */
9720
509
    *len = 4;
9721
509
    val = (cur[0] & 0x7) << 18;
9722
509
    val |= (cur[1] & 0x3f) << 12;
9723
509
    val |= (cur[2] & 0x3f) << 6;
9724
509
    val |= cur[3] & 0x3f;
9725
59.3k
      } else {
9726
        /* 3-byte code */
9727
59.3k
    *len = 3;
9728
59.3k
    val = (cur[0] & 0xf) << 12;
9729
59.3k
    val |= (cur[1] & 0x3f) << 6;
9730
59.3k
    val |= cur[2] & 0x3f;
9731
59.3k
      }
9732
1.34M
  } else {
9733
    /* 2-byte code */
9734
1.34M
      *len = 2;
9735
1.34M
      val = (cur[0] & 0x1f) << 6;
9736
1.34M
      val |= cur[1] & 0x3f;
9737
1.34M
  }
9738
1.40M
  if (!IS_CHAR(val)) {
9739
696
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9740
0
  }
9741
1.40M
  return(val);
9742
8.59M
    } else {
9743
  /* 1-byte code */
9744
8.59M
  *len = 1;
9745
8.59M
  return(*cur);
9746
8.59M
    }
9747
15.6k
encoding_error:
9748
    /*
9749
     * If we detect an UTF8 error that probably means that the
9750
     * input encoding didn't get properly advertised in the
9751
     * declaration header. Report the error and switch the encoding
9752
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9753
     * encoding !)
9754
     */
9755
15.6k
    *len = 0;
9756
15.6k
    XP_ERROR0(XPATH_ENCODING_ERROR);
9757
0
}
9758
9759
/**
9760
 * xmlXPathParseNCName:
9761
 * @ctxt:  the XPath Parser context
9762
 *
9763
 * parse an XML namespace non qualified name.
9764
 *
9765
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9766
 *
9767
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768
 *                       CombiningChar | Extender
9769
 *
9770
 * Returns the namespace name or NULL
9771
 */
9772
9773
xmlChar *
9774
500k
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9775
500k
    const xmlChar *in;
9776
500k
    xmlChar *ret;
9777
500k
    int count = 0;
9778
9779
500k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9780
    /*
9781
     * Accelerator for simple ASCII names
9782
     */
9783
500k
    in = ctxt->cur;
9784
500k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785
500k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9786
500k
  (*in == '_')) {
9787
364k
  in++;
9788
4.54M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789
4.54M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9790
4.54M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9791
4.54M
         (*in == '_') || (*in == '.') ||
9792
4.54M
         (*in == '-'))
9793
4.17M
      in++;
9794
364k
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795
364k
            (*in == '[') || (*in == ']') || (*in == ':') ||
9796
364k
            (*in == '@') || (*in == '*')) {
9797
144k
      count = in - ctxt->cur;
9798
144k
      if (count == 0)
9799
0
    return(NULL);
9800
144k
      ret = xmlStrndup(ctxt->cur, count);
9801
144k
      ctxt->cur = in;
9802
144k
      return(ret);
9803
144k
  }
9804
364k
    }
9805
355k
    return(xmlXPathParseNameComplex(ctxt, 0));
9806
500k
}
9807
9808
9809
/**
9810
 * xmlXPathParseQName:
9811
 * @ctxt:  the XPath Parser context
9812
 * @prefix:  a xmlChar **
9813
 *
9814
 * parse an XML qualified name
9815
 *
9816
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9817
 *
9818
 * [NS 6] Prefix ::= NCName
9819
 *
9820
 * [NS 7] LocalPart ::= NCName
9821
 *
9822
 * Returns the function returns the local part, and prefix is updated
9823
 *   to get the Prefix if any.
9824
 */
9825
9826
static xmlChar *
9827
14.4k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828
14.4k
    xmlChar *ret = NULL;
9829
9830
14.4k
    *prefix = NULL;
9831
14.4k
    ret = xmlXPathParseNCName(ctxt);
9832
14.4k
    if (ret && CUR == ':') {
9833
2.42k
        *prefix = ret;
9834
2.42k
  NEXT;
9835
2.42k
  ret = xmlXPathParseNCName(ctxt);
9836
2.42k
    }
9837
14.4k
    return(ret);
9838
14.4k
}
9839
9840
/**
9841
 * xmlXPathParseName:
9842
 * @ctxt:  the XPath Parser context
9843
 *
9844
 * parse an XML name
9845
 *
9846
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847
 *                  CombiningChar | Extender
9848
 *
9849
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9850
 *
9851
 * Returns the namespace name or NULL
9852
 */
9853
9854
xmlChar *
9855
373k
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9856
373k
    const xmlChar *in;
9857
373k
    xmlChar *ret;
9858
373k
    size_t count = 0;
9859
9860
373k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9861
    /*
9862
     * Accelerator for simple ASCII names
9863
     */
9864
373k
    in = ctxt->cur;
9865
373k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866
373k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9867
373k
  (*in == '_') || (*in == ':')) {
9868
288k
  in++;
9869
5.01M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870
5.01M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9871
5.01M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9872
5.01M
         (*in == '_') || (*in == '-') ||
9873
5.01M
         (*in == ':') || (*in == '.'))
9874
4.72M
      in++;
9875
288k
  if ((*in > 0) && (*in < 0x80)) {
9876
266k
      count = in - ctxt->cur;
9877
266k
            if (count > XML_MAX_NAME_LENGTH) {
9878
0
                ctxt->cur = in;
9879
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9880
0
            }
9881
266k
      ret = xmlStrndup(ctxt->cur, count);
9882
266k
      ctxt->cur = in;
9883
266k
      return(ret);
9884
266k
  }
9885
288k
    }
9886
106k
    return(xmlXPathParseNameComplex(ctxt, 1));
9887
373k
}
9888
9889
static xmlChar *
9890
462k
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9891
462k
    xmlChar buf[XML_MAX_NAMELEN + 5];
9892
462k
    int len = 0, l;
9893
462k
    int c;
9894
9895
    /*
9896
     * Handler for more complex cases
9897
     */
9898
462k
    c = CUR_CHAR(l);
9899
462k
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9900
462k
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901
462k
        (c == '*') || /* accelerators */
9902
462k
  (!IS_LETTER(c) && (c != '_') &&
9903
325k
         ((!qualified) || (c != ':')))) {
9904
211k
  return(NULL);
9905
211k
    }
9906
9907
2.17M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908
2.17M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909
2.17M
            (c == '.') || (c == '-') ||
9910
2.17M
      (c == '_') || ((qualified) && (c == ':')) ||
9911
2.17M
      (IS_COMBINING(c)) ||
9912
2.17M
      (IS_EXTENDER(c)))) {
9913
1.93M
  COPY_BUF(l,buf,len,c);
9914
1.93M
  NEXTL(l);
9915
1.93M
  c = CUR_CHAR(l);
9916
1.93M
  if (len >= XML_MAX_NAMELEN) {
9917
      /*
9918
       * Okay someone managed to make a huge name, so he's ready to pay
9919
       * for the processing speed.
9920
       */
9921
9.87k
      xmlChar *buffer;
9922
9.87k
      int max = len * 2;
9923
9924
9.87k
            if (len > XML_MAX_NAME_LENGTH) {
9925
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9926
0
            }
9927
9.87k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9928
9.87k
      if (buffer == NULL) {
9929
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9930
0
      }
9931
9.87k
      memcpy(buffer, buf, len);
9932
4.43M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933
4.43M
       (c == '.') || (c == '-') ||
9934
4.43M
       (c == '_') || ((qualified) && (c == ':')) ||
9935
4.43M
       (IS_COMBINING(c)) ||
9936
4.43M
       (IS_EXTENDER(c))) {
9937
4.42M
    if (len + 10 > max) {
9938
9.36k
                    xmlChar *tmp;
9939
9.36k
                    if (max > XML_MAX_NAME_LENGTH) {
9940
1
                        xmlFree(buffer);
9941
1
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9942
0
                    }
9943
9.36k
        max *= 2;
9944
9.36k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9945
9.36k
        if (tmp == NULL) {
9946
0
                        xmlFree(buffer);
9947
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9948
0
        }
9949
9.36k
                    buffer = tmp;
9950
9.36k
    }
9951
4.42M
    COPY_BUF(l,buffer,len,c);
9952
4.42M
    NEXTL(l);
9953
4.42M
    c = CUR_CHAR(l);
9954
4.42M
      }
9955
9.87k
      buffer[len] = 0;
9956
9.87k
      return(buffer);
9957
9.87k
  }
9958
1.93M
    }
9959
240k
    if (len == 0)
9960
0
  return(NULL);
9961
240k
    return(xmlStrndup(buf, len));
9962
240k
}
9963
9964
20.9k
#define MAX_FRAC 20
9965
9966
/**
9967
 * xmlXPathStringEvalNumber:
9968
 * @str:  A string to scan
9969
 *
9970
 *  [30a]  Float  ::= Number ('e' Digits?)?
9971
 *
9972
 *  [30]   Number ::=   Digits ('.' Digits?)?
9973
 *                    | '.' Digits
9974
 *  [31]   Digits ::=   [0-9]+
9975
 *
9976
 * Compile a Number in the string
9977
 * In complement of the Number expression, this function also handles
9978
 * negative values : '-' Number.
9979
 *
9980
 * Returns the double value.
9981
 */
9982
double
9983
1.26M
xmlXPathStringEvalNumber(const xmlChar *str) {
9984
1.26M
    const xmlChar *cur = str;
9985
1.26M
    double ret;
9986
1.26M
    int ok = 0;
9987
1.26M
    int isneg = 0;
9988
1.26M
    int exponent = 0;
9989
1.26M
    int is_exponent_negative = 0;
9990
1.26M
#ifdef __GNUC__
9991
1.26M
    unsigned long tmp = 0;
9992
1.26M
    double temp;
9993
1.26M
#endif
9994
1.26M
    if (cur == NULL) return(0);
9995
3.33M
    while (IS_BLANK_CH(*cur)) cur++;
9996
1.26M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9997
1.11M
        return(xmlXPathNAN);
9998
1.11M
    }
9999
155k
    if (*cur == '-') {
10000
13.6k
  isneg = 1;
10001
13.6k
  cur++;
10002
13.6k
    }
10003
10004
155k
#ifdef __GNUC__
10005
    /*
10006
     * tmp/temp is a workaround against a gcc compiler bug
10007
     * http://veillard.com/gcc.bug
10008
     */
10009
155k
    ret = 0;
10010
1.01M
    while ((*cur >= '0') && (*cur <= '9')) {
10011
855k
  ret = ret * 10;
10012
855k
  tmp = (*cur - '0');
10013
855k
  ok = 1;
10014
855k
  cur++;
10015
855k
  temp = (double) tmp;
10016
855k
  ret = ret + temp;
10017
855k
    }
10018
#else
10019
    ret = 0;
10020
    while ((*cur >= '0') && (*cur <= '9')) {
10021
  ret = ret * 10 + (*cur - '0');
10022
  ok = 1;
10023
  cur++;
10024
    }
10025
#endif
10026
10027
155k
    if (*cur == '.') {
10028
26.2k
  int v, frac = 0, max;
10029
26.2k
  double fraction = 0;
10030
10031
26.2k
        cur++;
10032
26.2k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10033
10.1k
      return(xmlXPathNAN);
10034
10.1k
  }
10035
24.8k
        while (*cur == '0') {
10036
8.76k
      frac = frac + 1;
10037
8.76k
      cur++;
10038
8.76k
        }
10039
16.0k
        max = frac + MAX_FRAC;
10040
69.2k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10041
53.1k
      v = (*cur - '0');
10042
53.1k
      fraction = fraction * 10 + v;
10043
53.1k
      frac = frac + 1;
10044
53.1k
      cur++;
10045
53.1k
  }
10046
16.0k
  fraction /= pow(10.0, frac);
10047
16.0k
  ret = ret + fraction;
10048
173k
  while ((*cur >= '0') && (*cur <= '9'))
10049
157k
      cur++;
10050
16.0k
    }
10051
144k
    if ((*cur == 'e') || (*cur == 'E')) {
10052
33.3k
      cur++;
10053
33.3k
      if (*cur == '-') {
10054
2.01k
  is_exponent_negative = 1;
10055
2.01k
  cur++;
10056
31.3k
      } else if (*cur == '+') {
10057
956
        cur++;
10058
956
      }
10059
414k
      while ((*cur >= '0') && (*cur <= '9')) {
10060
381k
        if (exponent < 1000000)
10061
156k
    exponent = exponent * 10 + (*cur - '0');
10062
381k
  cur++;
10063
381k
      }
10064
33.3k
    }
10065
437k
    while (IS_BLANK_CH(*cur)) cur++;
10066
144k
    if (*cur != 0) return(xmlXPathNAN);
10067
18.6k
    if (isneg) ret = -ret;
10068
18.6k
    if (is_exponent_negative) exponent = -exponent;
10069
18.6k
    ret *= pow(10.0, (double)exponent);
10070
18.6k
    return(ret);
10071
144k
}
10072
10073
/**
10074
 * xmlXPathCompNumber:
10075
 * @ctxt:  the XPath Parser context
10076
 *
10077
 *  [30]   Number ::=   Digits ('.' Digits?)?
10078
 *                    | '.' Digits
10079
 *  [31]   Digits ::=   [0-9]+
10080
 *
10081
 * Compile a Number, then push it on the stack
10082
 *
10083
 */
10084
static void
10085
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10086
63.8k
{
10087
63.8k
    double ret = 0.0;
10088
63.8k
    int ok = 0;
10089
63.8k
    int exponent = 0;
10090
63.8k
    int is_exponent_negative = 0;
10091
63.8k
    xmlXPathObjectPtr num;
10092
63.8k
#ifdef __GNUC__
10093
63.8k
    unsigned long tmp = 0;
10094
63.8k
    double temp;
10095
63.8k
#endif
10096
10097
63.8k
    CHECK_ERROR;
10098
63.7k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10099
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10100
0
    }
10101
63.7k
#ifdef __GNUC__
10102
    /*
10103
     * tmp/temp is a workaround against a gcc compiler bug
10104
     * http://veillard.com/gcc.bug
10105
     */
10106
63.7k
    ret = 0;
10107
651k
    while ((CUR >= '0') && (CUR <= '9')) {
10108
588k
  ret = ret * 10;
10109
588k
  tmp = (CUR - '0');
10110
588k
        ok = 1;
10111
588k
        NEXT;
10112
588k
  temp = (double) tmp;
10113
588k
  ret = ret + temp;
10114
588k
    }
10115
#else
10116
    ret = 0;
10117
    while ((CUR >= '0') && (CUR <= '9')) {
10118
  ret = ret * 10 + (CUR - '0');
10119
  ok = 1;
10120
  NEXT;
10121
    }
10122
#endif
10123
63.7k
    if (CUR == '.') {
10124
4.90k
  int v, frac = 0, max;
10125
4.90k
  double fraction = 0;
10126
10127
4.90k
        NEXT;
10128
4.90k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10129
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10130
0
        }
10131
11.4k
        while (CUR == '0') {
10132
6.54k
            frac = frac + 1;
10133
6.54k
            NEXT;
10134
6.54k
        }
10135
4.90k
        max = frac + MAX_FRAC;
10136
39.5k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10137
34.6k
      v = (CUR - '0');
10138
34.6k
      fraction = fraction * 10 + v;
10139
34.6k
      frac = frac + 1;
10140
34.6k
            NEXT;
10141
34.6k
        }
10142
4.90k
        fraction /= pow(10.0, frac);
10143
4.90k
        ret = ret + fraction;
10144
119k
        while ((CUR >= '0') && (CUR <= '9'))
10145
114k
            NEXT;
10146
4.90k
    }
10147
63.7k
    if ((CUR == 'e') || (CUR == 'E')) {
10148
7.78k
        NEXT;
10149
7.78k
        if (CUR == '-') {
10150
1.51k
            is_exponent_negative = 1;
10151
1.51k
            NEXT;
10152
6.26k
        } else if (CUR == '+') {
10153
1.42k
      NEXT;
10154
1.42k
  }
10155
84.6k
        while ((CUR >= '0') && (CUR <= '9')) {
10156
76.8k
            if (exponent < 1000000)
10157
34.9k
                exponent = exponent * 10 + (CUR - '0');
10158
76.8k
            NEXT;
10159
76.8k
        }
10160
7.78k
        if (is_exponent_negative)
10161
1.51k
            exponent = -exponent;
10162
7.78k
        ret *= pow(10.0, (double) exponent);
10163
7.78k
    }
10164
63.7k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10165
63.7k
    if (num == NULL) {
10166
0
  ctxt->error = XPATH_MEMORY_ERROR;
10167
63.7k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10168
63.7k
                              NULL) == -1) {
10169
0
        xmlXPathReleaseObject(ctxt->context, num);
10170
0
    }
10171
63.7k
}
10172
10173
/**
10174
 * xmlXPathParseLiteral:
10175
 * @ctxt:  the XPath Parser context
10176
 *
10177
 * Parse a Literal
10178
 *
10179
 *  [29]   Literal ::=   '"' [^"]* '"'
10180
 *                    | "'" [^']* "'"
10181
 *
10182
 * Returns the value found or NULL in case of error
10183
 */
10184
static xmlChar *
10185
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10186
0
    const xmlChar *q;
10187
0
    xmlChar *ret = NULL;
10188
10189
0
    if (CUR == '"') {
10190
0
        NEXT;
10191
0
  q = CUR_PTR;
10192
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10193
0
      NEXT;
10194
0
  if (!IS_CHAR_CH(CUR)) {
10195
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10196
0
  } else {
10197
0
      ret = xmlStrndup(q, CUR_PTR - q);
10198
0
      NEXT;
10199
0
        }
10200
0
    } else if (CUR == '\'') {
10201
0
        NEXT;
10202
0
  q = CUR_PTR;
10203
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10204
0
      NEXT;
10205
0
  if (!IS_CHAR_CH(CUR)) {
10206
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10207
0
  } else {
10208
0
      ret = xmlStrndup(q, CUR_PTR - q);
10209
0
      NEXT;
10210
0
        }
10211
0
    } else {
10212
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10213
0
    }
10214
0
    return(ret);
10215
0
}
10216
10217
/**
10218
 * xmlXPathCompLiteral:
10219
 * @ctxt:  the XPath Parser context
10220
 *
10221
 * Parse a Literal and push it on the stack.
10222
 *
10223
 *  [29]   Literal ::=   '"' [^"]* '"'
10224
 *                    | "'" [^']* "'"
10225
 *
10226
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10227
 */
10228
static void
10229
12.1k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10230
12.1k
    const xmlChar *q;
10231
12.1k
    xmlChar *ret = NULL;
10232
12.1k
    xmlXPathObjectPtr lit;
10233
10234
12.1k
    if (CUR == '"') {
10235
576
        NEXT;
10236
576
  q = CUR_PTR;
10237
50.4k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10238
49.8k
      NEXT;
10239
576
  if (!IS_CHAR_CH(CUR)) {
10240
429
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10241
147
  } else {
10242
147
      ret = xmlStrndup(q, CUR_PTR - q);
10243
147
      NEXT;
10244
147
        }
10245
11.6k
    } else if (CUR == '\'') {
10246
11.6k
        NEXT;
10247
11.6k
  q = CUR_PTR;
10248
80.5k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10249
68.8k
      NEXT;
10250
11.6k
  if (!IS_CHAR_CH(CUR)) {
10251
797
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10252
10.8k
  } else {
10253
10.8k
      ret = xmlStrndup(q, CUR_PTR - q);
10254
10.8k
      NEXT;
10255
10.8k
        }
10256
11.6k
    } else {
10257
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10258
0
    }
10259
10.9k
    if (ret == NULL) return;
10260
10.9k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10261
10.9k
    if (lit == NULL) {
10262
0
  ctxt->error = XPATH_MEMORY_ERROR;
10263
10.9k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10264
10.9k
                              NULL) == -1) {
10265
0
        xmlXPathReleaseObject(ctxt->context, lit);
10266
0
    }
10267
10.9k
    xmlFree(ret);
10268
10.9k
}
10269
10270
/**
10271
 * xmlXPathCompVariableReference:
10272
 * @ctxt:  the XPath Parser context
10273
 *
10274
 * Parse a VariableReference, evaluate it and push it on the stack.
10275
 *
10276
 * The variable bindings consist of a mapping from variable names
10277
 * to variable values. The value of a variable is an object, which can be
10278
 * of any of the types that are possible for the value of an expression,
10279
 * and may also be of additional types not specified here.
10280
 *
10281
 * Early evaluation is possible since:
10282
 * The variable bindings [...] used to evaluate a subexpression are
10283
 * always the same as those used to evaluate the containing expression.
10284
 *
10285
 *  [36]   VariableReference ::=   '$' QName
10286
 */
10287
static void
10288
4.55k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10289
4.55k
    xmlChar *name;
10290
4.55k
    xmlChar *prefix;
10291
10292
4.55k
    SKIP_BLANKS;
10293
4.55k
    if (CUR != '$') {
10294
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10295
0
    }
10296
4.55k
    NEXT;
10297
4.55k
    name = xmlXPathParseQName(ctxt, &prefix);
10298
4.55k
    if (name == NULL) {
10299
453
        xmlFree(prefix);
10300
453
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10301
0
    }
10302
4.09k
    ctxt->comp->last = -1;
10303
4.09k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10304
0
        xmlFree(prefix);
10305
0
        xmlFree(name);
10306
0
    }
10307
4.09k
    SKIP_BLANKS;
10308
4.09k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10309
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10310
0
    }
10311
4.09k
}
10312
10313
/**
10314
 * xmlXPathIsNodeType:
10315
 * @name:  a name string
10316
 *
10317
 * Is the name given a NodeType one.
10318
 *
10319
 *  [38]   NodeType ::=   'comment'
10320
 *                    | 'text'
10321
 *                    | 'processing-instruction'
10322
 *                    | 'node'
10323
 *
10324
 * Returns 1 if true 0 otherwise
10325
 */
10326
int
10327
12.4k
xmlXPathIsNodeType(const xmlChar *name) {
10328
12.4k
    if (name == NULL)
10329
0
  return(0);
10330
10331
12.4k
    if (xmlStrEqual(name, BAD_CAST "node"))
10332
0
  return(1);
10333
12.4k
    if (xmlStrEqual(name, BAD_CAST "text"))
10334
2.47k
  return(1);
10335
9.93k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10336
0
  return(1);
10337
9.93k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10338
0
  return(1);
10339
9.93k
    return(0);
10340
9.93k
}
10341
10342
/**
10343
 * xmlXPathCompFunctionCall:
10344
 * @ctxt:  the XPath Parser context
10345
 *
10346
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10347
 *  [17]   Argument ::=   Expr
10348
 *
10349
 * Compile a function call, the evaluation of all arguments are
10350
 * pushed on the stack
10351
 */
10352
static void
10353
9.93k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10354
9.93k
    xmlChar *name;
10355
9.93k
    xmlChar *prefix;
10356
9.93k
    int nbargs = 0;
10357
9.93k
    int sort = 1;
10358
10359
9.93k
    name = xmlXPathParseQName(ctxt, &prefix);
10360
9.93k
    if (name == NULL) {
10361
216
  xmlFree(prefix);
10362
216
  XP_ERROR(XPATH_EXPR_ERROR);
10363
0
    }
10364
9.72k
    SKIP_BLANKS;
10365
#ifdef DEBUG_EXPR
10366
    if (prefix == NULL)
10367
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10368
      name);
10369
    else
10370
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10371
      prefix, name);
10372
#endif
10373
10374
9.72k
    if (CUR != '(') {
10375
48
  xmlFree(name);
10376
48
  xmlFree(prefix);
10377
48
  XP_ERROR(XPATH_EXPR_ERROR);
10378
0
    }
10379
9.67k
    NEXT;
10380
9.67k
    SKIP_BLANKS;
10381
10382
    /*
10383
    * Optimization for count(): we don't need the node-set to be sorted.
10384
    */
10385
9.67k
    if ((prefix == NULL) && (name[0] == 'c') &&
10386
9.67k
  xmlStrEqual(name, BAD_CAST "count"))
10387
0
    {
10388
0
  sort = 0;
10389
0
    }
10390
9.67k
    ctxt->comp->last = -1;
10391
9.67k
    if (CUR != ')') {
10392
8.67k
  while (CUR != 0) {
10393
8.48k
      int op1 = ctxt->comp->last;
10394
8.48k
      ctxt->comp->last = -1;
10395
8.48k
      xmlXPathCompileExpr(ctxt, sort);
10396
8.48k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10397
727
    xmlFree(name);
10398
727
    xmlFree(prefix);
10399
727
    return;
10400
727
      }
10401
7.75k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10402
7.75k
      nbargs++;
10403
7.75k
      if (CUR == ')') break;
10404
2.65k
      if (CUR != ',') {
10405
911
    xmlFree(name);
10406
911
    xmlFree(prefix);
10407
911
    XP_ERROR(XPATH_EXPR_ERROR);
10408
0
      }
10409
1.74k
      NEXT;
10410
1.74k
      SKIP_BLANKS;
10411
1.74k
  }
10412
6.93k
    }
10413
8.03k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10414
0
        xmlFree(prefix);
10415
0
        xmlFree(name);
10416
0
    }
10417
8.03k
    NEXT;
10418
8.03k
    SKIP_BLANKS;
10419
8.03k
}
10420
10421
/**
10422
 * xmlXPathCompPrimaryExpr:
10423
 * @ctxt:  the XPath Parser context
10424
 *
10425
 *  [15]   PrimaryExpr ::=   VariableReference
10426
 *                | '(' Expr ')'
10427
 *                | Literal
10428
 *                | Number
10429
 *                | FunctionCall
10430
 *
10431
 * Compile a primary expression.
10432
 */
10433
static void
10434
112k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10435
112k
    SKIP_BLANKS;
10436
112k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10437
108k
    else if (CUR == '(') {
10438
22.2k
  NEXT;
10439
22.2k
  SKIP_BLANKS;
10440
22.2k
  xmlXPathCompileExpr(ctxt, 1);
10441
22.2k
  CHECK_ERROR;
10442
21.3k
  if (CUR != ')') {
10443
394
      XP_ERROR(XPATH_EXPR_ERROR);
10444
0
  }
10445
20.9k
  NEXT;
10446
20.9k
  SKIP_BLANKS;
10447
85.9k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10448
63.8k
  xmlXPathCompNumber(ctxt);
10449
63.8k
    } else if ((CUR == '\'') || (CUR == '"')) {
10450
12.1k
  xmlXPathCompLiteral(ctxt);
10451
12.1k
    } else {
10452
9.93k
  xmlXPathCompFunctionCall(ctxt);
10453
9.93k
    }
10454
111k
    SKIP_BLANKS;
10455
111k
}
10456
10457
/**
10458
 * xmlXPathCompFilterExpr:
10459
 * @ctxt:  the XPath Parser context
10460
 *
10461
 *  [20]   FilterExpr ::=   PrimaryExpr
10462
 *               | FilterExpr Predicate
10463
 *
10464
 * Compile a filter expression.
10465
 * Square brackets are used to filter expressions in the same way that
10466
 * they are used in location paths. It is an error if the expression to
10467
 * be filtered does not evaluate to a node-set. The context node list
10468
 * used for evaluating the expression in square brackets is the node-set
10469
 * to be filtered listed in document order.
10470
 */
10471
10472
static void
10473
112k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10474
112k
    xmlXPathCompPrimaryExpr(ctxt);
10475
112k
    CHECK_ERROR;
10476
107k
    SKIP_BLANKS;
10477
10478
147k
    while (CUR == '[') {
10479
39.7k
  xmlXPathCompPredicate(ctxt, 1);
10480
39.7k
  SKIP_BLANKS;
10481
39.7k
    }
10482
10483
10484
107k
}
10485
10486
/**
10487
 * xmlXPathScanName:
10488
 * @ctxt:  the XPath Parser context
10489
 *
10490
 * Trickery: parse an XML name but without consuming the input flow
10491
 * Needed to avoid insanity in the parser state.
10492
 *
10493
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10494
 *                  CombiningChar | Extender
10495
 *
10496
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10497
 *
10498
 * [6] Names ::= Name (S Name)*
10499
 *
10500
 * Returns the Name parsed or NULL
10501
 */
10502
10503
static xmlChar *
10504
519k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10505
519k
    int l;
10506
519k
    int c;
10507
519k
    const xmlChar *cur;
10508
519k
    xmlChar *ret;
10509
10510
519k
    cur = ctxt->cur;
10511
10512
519k
    c = CUR_CHAR(l);
10513
519k
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10514
519k
  (!IS_LETTER(c) && (c != '_') &&
10515
518k
         (c != ':'))) {
10516
348k
  return(NULL);
10517
348k
    }
10518
10519
2.84M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10520
2.84M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10521
2.80M
            (c == '.') || (c == '-') ||
10522
2.80M
      (c == '_') || (c == ':') ||
10523
2.80M
      (IS_COMBINING(c)) ||
10524
2.80M
      (IS_EXTENDER(c)))) {
10525
2.67M
  NEXTL(l);
10526
2.67M
  c = CUR_CHAR(l);
10527
2.67M
    }
10528
170k
    ret = xmlStrndup(cur, ctxt->cur - cur);
10529
170k
    ctxt->cur = cur;
10530
170k
    return(ret);
10531
519k
}
10532
10533
/**
10534
 * xmlXPathCompPathExpr:
10535
 * @ctxt:  the XPath Parser context
10536
 *
10537
 *  [19]   PathExpr ::=   LocationPath
10538
 *               | FilterExpr
10539
 *               | FilterExpr '/' RelativeLocationPath
10540
 *               | FilterExpr '//' RelativeLocationPath
10541
 *
10542
 * Compile a path expression.
10543
 * The / operator and // operators combine an arbitrary expression
10544
 * and a relative location path. It is an error if the expression
10545
 * does not evaluate to a node-set.
10546
 * The / operator does composition in the same way as when / is
10547
 * used in a location path. As in location paths, // is short for
10548
 * /descendant-or-self::node()/.
10549
 */
10550
10551
static void
10552
1.24M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10553
1.24M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10554
1.24M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10555
10556
1.24M
    SKIP_BLANKS;
10557
1.24M
    if ((CUR == '$') || (CUR == '(') ||
10558
1.24M
  (IS_ASCII_DIGIT(CUR)) ||
10559
1.24M
        (CUR == '\'') || (CUR == '"') ||
10560
1.24M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10561
102k
  lc = 0;
10562
1.14M
    } else if (CUR == '*') {
10563
  /* relative or absolute location path */
10564
452k
  lc = 1;
10565
689k
    } else if (CUR == '/') {
10566
  /* relative or absolute location path */
10567
152k
  lc = 1;
10568
536k
    } else if (CUR == '@') {
10569
  /* relative abbreviated attribute location path */
10570
7.40k
  lc = 1;
10571
529k
    } else if (CUR == '.') {
10572
  /* relative abbreviated attribute location path */
10573
10.1k
  lc = 1;
10574
519k
    } else {
10575
  /*
10576
   * Problem is finding if we have a name here whether it's:
10577
   *   - a nodetype
10578
   *   - a function call in which case it's followed by '('
10579
   *   - an axis in which case it's followed by ':'
10580
   *   - a element name
10581
   * We do an a priori analysis here rather than having to
10582
   * maintain parsed token content through the recursive function
10583
   * calls. This looks uglier but makes the code easier to
10584
   * read/write/debug.
10585
   */
10586
519k
  SKIP_BLANKS;
10587
519k
  name = xmlXPathScanName(ctxt);
10588
519k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10589
#ifdef DEBUG_STEP
10590
      xmlGenericError(xmlGenericErrorContext,
10591
        "PathExpr: Axis\n");
10592
#endif
10593
237
      lc = 1;
10594
237
      xmlFree(name);
10595
518k
  } else if (name != NULL) {
10596
170k
      int len =xmlStrlen(name);
10597
10598
10599
297k
      while (NXT(len) != 0) {
10600
269k
    if (NXT(len) == '/') {
10601
        /* element name */
10602
#ifdef DEBUG_STEP
10603
        xmlGenericError(xmlGenericErrorContext,
10604
          "PathExpr: AbbrRelLocation\n");
10605
#endif
10606
20.8k
        lc = 1;
10607
20.8k
        break;
10608
248k
    } else if (IS_BLANK_CH(NXT(len))) {
10609
        /* ignore blanks */
10610
127k
        ;
10611
127k
    } else if (NXT(len) == ':') {
10612
#ifdef DEBUG_STEP
10613
        xmlGenericError(xmlGenericErrorContext,
10614
          "PathExpr: AbbrRelLocation\n");
10615
#endif
10616
25
        lc = 1;
10617
25
        break;
10618
120k
    } else if ((NXT(len) == '(')) {
10619
        /* Node Type or Function */
10620
12.4k
        if (xmlXPathIsNodeType(name)) {
10621
#ifdef DEBUG_STEP
10622
            xmlGenericError(xmlGenericErrorContext,
10623
        "PathExpr: Type search\n");
10624
#endif
10625
2.47k
      lc = 1;
10626
#ifdef LIBXML_XPTR_LOCS_ENABLED
10627
                    } else if (ctxt->xptr &&
10628
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10629
                        lc = 1;
10630
#endif
10631
9.93k
        } else {
10632
#ifdef DEBUG_STEP
10633
            xmlGenericError(xmlGenericErrorContext,
10634
        "PathExpr: function call\n");
10635
#endif
10636
9.93k
      lc = 0;
10637
9.93k
        }
10638
12.4k
                    break;
10639
108k
    } else if ((NXT(len) == '[')) {
10640
        /* element name */
10641
#ifdef DEBUG_STEP
10642
        xmlGenericError(xmlGenericErrorContext,
10643
          "PathExpr: AbbrRelLocation\n");
10644
#endif
10645
2.51k
        lc = 1;
10646
2.51k
        break;
10647
105k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10648
105k
         (NXT(len) == '=')) {
10649
22.7k
        lc = 1;
10650
22.7k
        break;
10651
83.1k
    } else {
10652
83.1k
        lc = 1;
10653
83.1k
        break;
10654
83.1k
    }
10655
127k
    len++;
10656
127k
      }
10657
170k
      if (NXT(len) == 0) {
10658
#ifdef DEBUG_STEP
10659
    xmlGenericError(xmlGenericErrorContext,
10660
      "PathExpr: AbbrRelLocation\n");
10661
#endif
10662
    /* element name */
10663
28.6k
    lc = 1;
10664
28.6k
      }
10665
170k
      xmlFree(name);
10666
348k
  } else {
10667
      /* make sure all cases are covered explicitly */
10668
348k
      XP_ERROR(XPATH_EXPR_ERROR);
10669
0
  }
10670
519k
    }
10671
10672
895k
    if (lc) {
10673
782k
  if (CUR == '/') {
10674
152k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10675
630k
  } else {
10676
630k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10677
630k
  }
10678
782k
  xmlXPathCompLocationPath(ctxt);
10679
782k
    } else {
10680
112k
  xmlXPathCompFilterExpr(ctxt);
10681
112k
  CHECK_ERROR;
10682
106k
  if ((CUR == '/') && (NXT(1) == '/')) {
10683
10.0k
      SKIP(2);
10684
10.0k
      SKIP_BLANKS;
10685
10686
10.0k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10687
10.0k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10688
10689
10.0k
      xmlXPathCompRelativeLocationPath(ctxt);
10690
96.7k
  } else if (CUR == '/') {
10691
7.35k
      xmlXPathCompRelativeLocationPath(ctxt);
10692
7.35k
  }
10693
106k
    }
10694
889k
    SKIP_BLANKS;
10695
889k
}
10696
10697
/**
10698
 * xmlXPathCompUnionExpr:
10699
 * @ctxt:  the XPath Parser context
10700
 *
10701
 *  [18]   UnionExpr ::=   PathExpr
10702
 *               | UnionExpr '|' PathExpr
10703
 *
10704
 * Compile an union expression.
10705
 */
10706
10707
static void
10708
864k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10709
864k
    xmlXPathCompPathExpr(ctxt);
10710
864k
    CHECK_ERROR;
10711
803k
    SKIP_BLANKS;
10712
1.18M
    while (CUR == '|') {
10713
379k
  int op1 = ctxt->comp->last;
10714
379k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10715
10716
379k
  NEXT;
10717
379k
  SKIP_BLANKS;
10718
379k
  xmlXPathCompPathExpr(ctxt);
10719
10720
379k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10721
10722
379k
  SKIP_BLANKS;
10723
379k
    }
10724
803k
}
10725
10726
/**
10727
 * xmlXPathCompUnaryExpr:
10728
 * @ctxt:  the XPath Parser context
10729
 *
10730
 *  [27]   UnaryExpr ::=   UnionExpr
10731
 *                   | '-' UnaryExpr
10732
 *
10733
 * Compile an unary expression.
10734
 */
10735
10736
static void
10737
864k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10738
864k
    int minus = 0;
10739
864k
    int found = 0;
10740
10741
864k
    SKIP_BLANKS;
10742
1.97M
    while (CUR == '-') {
10743
1.10M
        minus = 1 - minus;
10744
1.10M
  found = 1;
10745
1.10M
  NEXT;
10746
1.10M
  SKIP_BLANKS;
10747
1.10M
    }
10748
10749
864k
    xmlXPathCompUnionExpr(ctxt);
10750
864k
    CHECK_ERROR;
10751
801k
    if (found) {
10752
19.3k
  if (minus)
10753
14.8k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10754
4.52k
  else
10755
4.52k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10756
19.3k
    }
10757
801k
}
10758
10759
/**
10760
 * xmlXPathCompMultiplicativeExpr:
10761
 * @ctxt:  the XPath Parser context
10762
 *
10763
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10764
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10765
 *                   | MultiplicativeExpr 'div' UnaryExpr
10766
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10767
 *  [34]   MultiplyOperator ::=   '*'
10768
 *
10769
 * Compile an Additive expression.
10770
 */
10771
10772
static void
10773
423k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10774
423k
    xmlXPathCompUnaryExpr(ctxt);
10775
423k
    CHECK_ERROR;
10776
362k
    SKIP_BLANKS;
10777
801k
    while ((CUR == '*') ||
10778
801k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10779
801k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10780
441k
  int op = -1;
10781
441k
  int op1 = ctxt->comp->last;
10782
10783
441k
        if (CUR == '*') {
10784
439k
      op = 0;
10785
439k
      NEXT;
10786
439k
  } else if (CUR == 'd') {
10787
677
      op = 1;
10788
677
      SKIP(3);
10789
677
  } else if (CUR == 'm') {
10790
619
      op = 2;
10791
619
      SKIP(3);
10792
619
  }
10793
441k
  SKIP_BLANKS;
10794
441k
        xmlXPathCompUnaryExpr(ctxt);
10795
441k
  CHECK_ERROR;
10796
438k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10797
438k
  SKIP_BLANKS;
10798
438k
    }
10799
362k
}
10800
10801
/**
10802
 * xmlXPathCompAdditiveExpr:
10803
 * @ctxt:  the XPath Parser context
10804
 *
10805
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10806
 *                   | AdditiveExpr '+' MultiplicativeExpr
10807
 *                   | AdditiveExpr '-' MultiplicativeExpr
10808
 *
10809
 * Compile an Additive expression.
10810
 */
10811
10812
static void
10813
381k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10814
10815
381k
    xmlXPathCompMultiplicativeExpr(ctxt);
10816
381k
    CHECK_ERROR;
10817
320k
    SKIP_BLANKS;
10818
359k
    while ((CUR == '+') || (CUR == '-')) {
10819
41.6k
  int plus;
10820
41.6k
  int op1 = ctxt->comp->last;
10821
10822
41.6k
        if (CUR == '+') plus = 1;
10823
20.0k
  else plus = 0;
10824
41.6k
  NEXT;
10825
41.6k
  SKIP_BLANKS;
10826
41.6k
        xmlXPathCompMultiplicativeExpr(ctxt);
10827
41.6k
  CHECK_ERROR;
10828
39.5k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10829
39.5k
  SKIP_BLANKS;
10830
39.5k
    }
10831
320k
}
10832
10833
/**
10834
 * xmlXPathCompRelationalExpr:
10835
 * @ctxt:  the XPath Parser context
10836
 *
10837
 *  [24]   RelationalExpr ::=   AdditiveExpr
10838
 *                 | RelationalExpr '<' AdditiveExpr
10839
 *                 | RelationalExpr '>' AdditiveExpr
10840
 *                 | RelationalExpr '<=' AdditiveExpr
10841
 *                 | RelationalExpr '>=' AdditiveExpr
10842
 *
10843
 *  A <= B > C is allowed ? Answer from James, yes with
10844
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10845
 *  which is basically what got implemented.
10846
 *
10847
 * Compile a Relational expression, then push the result
10848
 * on the stack
10849
 */
10850
10851
static void
10852
347k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10853
347k
    xmlXPathCompAdditiveExpr(ctxt);
10854
347k
    CHECK_ERROR;
10855
286k
    SKIP_BLANKS;
10856
318k
    while ((CUR == '<') || (CUR == '>')) {
10857
33.9k
  int inf, strict;
10858
33.9k
  int op1 = ctxt->comp->last;
10859
10860
33.9k
        if (CUR == '<') inf = 1;
10861
17.8k
  else inf = 0;
10862
33.9k
  if (NXT(1) == '=') strict = 0;
10863
31.4k
  else strict = 1;
10864
33.9k
  NEXT;
10865
33.9k
  if (!strict) NEXT;
10866
33.9k
  SKIP_BLANKS;
10867
33.9k
        xmlXPathCompAdditiveExpr(ctxt);
10868
33.9k
  CHECK_ERROR;
10869
31.7k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10870
31.7k
  SKIP_BLANKS;
10871
31.7k
    }
10872
286k
}
10873
10874
/**
10875
 * xmlXPathCompEqualityExpr:
10876
 * @ctxt:  the XPath Parser context
10877
 *
10878
 *  [23]   EqualityExpr ::=   RelationalExpr
10879
 *                 | EqualityExpr '=' RelationalExpr
10880
 *                 | EqualityExpr '!=' RelationalExpr
10881
 *
10882
 *  A != B != C is allowed ? Answer from James, yes with
10883
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10884
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10885
 *  which is basically what got implemented.
10886
 *
10887
 * Compile an Equality expression.
10888
 *
10889
 */
10890
static void
10891
293k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10892
293k
    xmlXPathCompRelationalExpr(ctxt);
10893
293k
    CHECK_ERROR;
10894
233k
    SKIP_BLANKS;
10895
284k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10896
53.4k
  int eq;
10897
53.4k
  int op1 = ctxt->comp->last;
10898
10899
53.4k
        if (CUR == '=') eq = 1;
10900
10.0k
  else eq = 0;
10901
53.4k
  NEXT;
10902
53.4k
  if (!eq) NEXT;
10903
53.4k
  SKIP_BLANKS;
10904
53.4k
        xmlXPathCompRelationalExpr(ctxt);
10905
53.4k
  CHECK_ERROR;
10906
50.2k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10907
50.2k
  SKIP_BLANKS;
10908
50.2k
    }
10909
233k
}
10910
10911
/**
10912
 * xmlXPathCompAndExpr:
10913
 * @ctxt:  the XPath Parser context
10914
 *
10915
 *  [22]   AndExpr ::=   EqualityExpr
10916
 *                 | AndExpr 'and' EqualityExpr
10917
 *
10918
 * Compile an AND expression.
10919
 *
10920
 */
10921
static void
10922
291k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10923
291k
    xmlXPathCompEqualityExpr(ctxt);
10924
291k
    CHECK_ERROR;
10925
228k
    SKIP_BLANKS;
10926
230k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10927
2.54k
  int op1 = ctxt->comp->last;
10928
2.54k
        SKIP(3);
10929
2.54k
  SKIP_BLANKS;
10930
2.54k
        xmlXPathCompEqualityExpr(ctxt);
10931
2.54k
  CHECK_ERROR;
10932
2.09k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10933
2.09k
  SKIP_BLANKS;
10934
2.09k
    }
10935
228k
}
10936
10937
/**
10938
 * xmlXPathCompileExpr:
10939
 * @ctxt:  the XPath Parser context
10940
 *
10941
 *  [14]   Expr ::=   OrExpr
10942
 *  [21]   OrExpr ::=   AndExpr
10943
 *                 | OrExpr 'or' AndExpr
10944
 *
10945
 * Parse and compile an expression
10946
 */
10947
static void
10948
528k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10949
528k
    xmlXPathContextPtr xpctxt = ctxt->context;
10950
10951
528k
    if (xpctxt != NULL) {
10952
528k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10953
280k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10954
        /*
10955
         * Parsing a single '(' pushes about 10 functions on the call stack
10956
         * before recursing!
10957
         */
10958
280k
        xpctxt->depth += 10;
10959
280k
    }
10960
10961
280k
    xmlXPathCompAndExpr(ctxt);
10962
280k
    CHECK_ERROR;
10963
218k
    SKIP_BLANKS;
10964
228k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10965
10.8k
  int op1 = ctxt->comp->last;
10966
10.8k
        SKIP(2);
10967
10.8k
  SKIP_BLANKS;
10968
10.8k
        xmlXPathCompAndExpr(ctxt);
10969
10.8k
  CHECK_ERROR;
10970
10.0k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10971
10.0k
  SKIP_BLANKS;
10972
10.0k
    }
10973
217k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10974
  /* more ops could be optimized too */
10975
  /*
10976
  * This is the main place to eliminate sorting for
10977
  * operations which don't require a sorted node-set.
10978
  * E.g. count().
10979
  */
10980
180k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10981
180k
    }
10982
10983
217k
    if (xpctxt != NULL)
10984
217k
        xpctxt->depth -= 10;
10985
217k
}
10986
10987
/**
10988
 * xmlXPathCompPredicate:
10989
 * @ctxt:  the XPath Parser context
10990
 * @filter:  act as a filter
10991
 *
10992
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10993
 *  [9]   PredicateExpr ::=   Expr
10994
 *
10995
 * Compile a predicate expression
10996
 */
10997
static void
10998
324k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10999
324k
    int op1 = ctxt->comp->last;
11000
11001
324k
    SKIP_BLANKS;
11002
324k
    if (CUR != '[') {
11003
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11004
0
    }
11005
324k
    NEXT;
11006
324k
    SKIP_BLANKS;
11007
11008
324k
    ctxt->comp->last = -1;
11009
    /*
11010
    * This call to xmlXPathCompileExpr() will deactivate sorting
11011
    * of the predicate result.
11012
    * TODO: Sorting is still activated for filters, since I'm not
11013
    *  sure if needed. Normally sorting should not be needed, since
11014
    *  a filter can only diminish the number of items in a sequence,
11015
    *  but won't change its order; so if the initial sequence is sorted,
11016
    *  subsequent sorting is not needed.
11017
    */
11018
324k
    if (! filter)
11019
284k
  xmlXPathCompileExpr(ctxt, 0);
11020
39.7k
    else
11021
39.7k
  xmlXPathCompileExpr(ctxt, 1);
11022
324k
    CHECK_ERROR;
11023
11024
37.6k
    if (CUR != ']') {
11025
2.55k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11026
0
    }
11027
11028
35.0k
    if (filter)
11029
7.44k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11030
27.6k
    else
11031
27.6k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11032
11033
35.0k
    NEXT;
11034
35.0k
    SKIP_BLANKS;
11035
35.0k
}
11036
11037
/**
11038
 * xmlXPathCompNodeTest:
11039
 * @ctxt:  the XPath Parser context
11040
 * @test:  pointer to a xmlXPathTestVal
11041
 * @type:  pointer to a xmlXPathTypeVal
11042
 * @prefix:  placeholder for a possible name prefix
11043
 *
11044
 * [7] NodeTest ::=   NameTest
11045
 *        | NodeType '(' ')'
11046
 *        | 'processing-instruction' '(' Literal ')'
11047
 *
11048
 * [37] NameTest ::=  '*'
11049
 *        | NCName ':' '*'
11050
 *        | QName
11051
 * [38] NodeType ::= 'comment'
11052
 *       | 'text'
11053
 *       | 'processing-instruction'
11054
 *       | 'node'
11055
 *
11056
 * Returns the name found and updates @test, @type and @prefix appropriately
11057
 */
11058
static xmlChar *
11059
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11060
               xmlXPathTypeVal *type, xmlChar **prefix,
11061
828k
         xmlChar *name) {
11062
828k
    int blanks;
11063
11064
828k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11065
0
  STRANGE;
11066
0
  return(NULL);
11067
0
    }
11068
828k
    *type = (xmlXPathTypeVal) 0;
11069
828k
    *test = (xmlXPathTestVal) 0;
11070
828k
    *prefix = NULL;
11071
828k
    SKIP_BLANKS;
11072
11073
828k
    if ((name == NULL) && (CUR == '*')) {
11074
  /*
11075
   * All elements
11076
   */
11077
484k
  NEXT;
11078
484k
  *test = NODE_TEST_ALL;
11079
484k
  return(NULL);
11080
484k
    }
11081
11082
344k
    if (name == NULL)
11083
21.0k
  name = xmlXPathParseNCName(ctxt);
11084
344k
    if (name == NULL) {
11085
6.08k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11086
0
    }
11087
11088
338k
    blanks = IS_BLANK_CH(CUR);
11089
338k
    SKIP_BLANKS;
11090
338k
    if (CUR == '(') {
11091
22.7k
  NEXT;
11092
  /*
11093
   * NodeType or PI search
11094
   */
11095
22.7k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11096
0
      *type = NODE_TYPE_COMMENT;
11097
22.7k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11098
0
      *type = NODE_TYPE_NODE;
11099
22.7k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11100
0
      *type = NODE_TYPE_PI;
11101
22.7k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11102
21.5k
      *type = NODE_TYPE_TEXT;
11103
1.13k
  else {
11104
1.13k
      if (name != NULL)
11105
1.13k
    xmlFree(name);
11106
1.13k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11107
0
  }
11108
11109
21.5k
  *test = NODE_TEST_TYPE;
11110
11111
21.5k
  SKIP_BLANKS;
11112
21.5k
  if (*type == NODE_TYPE_PI) {
11113
      /*
11114
       * Specific case: search a PI by name.
11115
       */
11116
0
      if (name != NULL)
11117
0
    xmlFree(name);
11118
0
      name = NULL;
11119
0
      if (CUR != ')') {
11120
0
    name = xmlXPathParseLiteral(ctxt);
11121
0
                if (name == NULL) {
11122
0
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11123
0
                }
11124
0
    *test = NODE_TEST_PI;
11125
0
    SKIP_BLANKS;
11126
0
      }
11127
0
  }
11128
21.5k
  if (CUR != ')') {
11129
118
      if (name != NULL)
11130
118
    xmlFree(name);
11131
118
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11132
0
  }
11133
21.4k
  NEXT;
11134
21.4k
  return(name);
11135
21.5k
    }
11136
315k
    *test = NODE_TEST_NAME;
11137
315k
    if ((!blanks) && (CUR == ':')) {
11138
9.33k
  NEXT;
11139
11140
  /*
11141
   * Since currently the parser context don't have a
11142
   * namespace list associated:
11143
   * The namespace name for this prefix can be computed
11144
   * only at evaluation time. The compilation is done
11145
   * outside of any context.
11146
   */
11147
#if 0
11148
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11149
  if (name != NULL)
11150
      xmlFree(name);
11151
  if (*prefix == NULL) {
11152
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11153
  }
11154
#else
11155
9.33k
  *prefix = name;
11156
9.33k
#endif
11157
11158
9.33k
  if (CUR == '*') {
11159
      /*
11160
       * All elements
11161
       */
11162
295
      NEXT;
11163
295
      *test = NODE_TEST_ALL;
11164
295
      return(NULL);
11165
295
  }
11166
11167
9.04k
  name = xmlXPathParseNCName(ctxt);
11168
9.04k
  if (name == NULL) {
11169
709
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11170
0
  }
11171
9.04k
    }
11172
314k
    return(name);
11173
315k
}
11174
11175
/**
11176
 * xmlXPathIsAxisName:
11177
 * @name:  a preparsed name token
11178
 *
11179
 * [6] AxisName ::=   'ancestor'
11180
 *                  | 'ancestor-or-self'
11181
 *                  | 'attribute'
11182
 *                  | 'child'
11183
 *                  | 'descendant'
11184
 *                  | 'descendant-or-self'
11185
 *                  | 'following'
11186
 *                  | 'following-sibling'
11187
 *                  | 'namespace'
11188
 *                  | 'parent'
11189
 *                  | 'preceding'
11190
 *                  | 'preceding-sibling'
11191
 *                  | 'self'
11192
 *
11193
 * Returns the axis or 0
11194
 */
11195
static xmlXPathAxisVal
11196
328k
xmlXPathIsAxisName(const xmlChar *name) {
11197
328k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11198
328k
    switch (name[0]) {
11199
46.7k
  case 'a':
11200
46.7k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11201
0
    ret = AXIS_ANCESTOR;
11202
46.7k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11203
0
    ret = AXIS_ANCESTOR_OR_SELF;
11204
46.7k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11205
353
    ret = AXIS_ATTRIBUTE;
11206
46.7k
      break;
11207
4.14k
  case 'c':
11208
4.14k
      if (xmlStrEqual(name, BAD_CAST "child"))
11209
23
    ret = AXIS_CHILD;
11210
4.14k
      break;
11211
12.5k
  case 'd':
11212
12.5k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11213
0
    ret = AXIS_DESCENDANT;
11214
12.5k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11215
0
    ret = AXIS_DESCENDANT_OR_SELF;
11216
12.5k
      break;
11217
1.10k
  case 'f':
11218
1.10k
      if (xmlStrEqual(name, BAD_CAST "following"))
11219
0
    ret = AXIS_FOLLOWING;
11220
1.10k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11221
0
    ret = AXIS_FOLLOWING_SIBLING;
11222
1.10k
      break;
11223
10.1k
  case 'n':
11224
10.1k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11225
1.16k
    ret = AXIS_NAMESPACE;
11226
10.1k
      break;
11227
46.8k
  case 'p':
11228
46.8k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11229
0
    ret = AXIS_PARENT;
11230
46.8k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11231
0
    ret = AXIS_PRECEDING;
11232
46.8k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11233
0
    ret = AXIS_PRECEDING_SIBLING;
11234
46.8k
      break;
11235
6.06k
  case 's':
11236
6.06k
      if (xmlStrEqual(name, BAD_CAST "self"))
11237
0
    ret = AXIS_SELF;
11238
6.06k
      break;
11239
328k
    }
11240
328k
    return(ret);
11241
328k
}
11242
11243
/**
11244
 * xmlXPathCompStep:
11245
 * @ctxt:  the XPath Parser context
11246
 *
11247
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11248
 *                  | AbbreviatedStep
11249
 *
11250
 * [12] AbbreviatedStep ::=   '.' | '..'
11251
 *
11252
 * [5] AxisSpecifier ::= AxisName '::'
11253
 *                  | AbbreviatedAxisSpecifier
11254
 *
11255
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11256
 *
11257
 * Modified for XPtr range support as:
11258
 *
11259
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11260
 *                     | AbbreviatedStep
11261
 *                     | 'range-to' '(' Expr ')' Predicate*
11262
 *
11263
 * Compile one step in a Location Path
11264
 * A location step of . is short for self::node(). This is
11265
 * particularly useful in conjunction with //. For example, the
11266
 * location path .//para is short for
11267
 * self::node()/descendant-or-self::node()/child::para
11268
 * and so will select all para descendant elements of the context
11269
 * node.
11270
 * Similarly, a location step of .. is short for parent::node().
11271
 * For example, ../title is short for parent::node()/child::title
11272
 * and so will select the title children of the parent of the context
11273
 * node.
11274
 */
11275
static void
11276
975k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11277
#ifdef LIBXML_XPTR_LOCS_ENABLED
11278
    int rangeto = 0;
11279
    int op2 = -1;
11280
#endif
11281
11282
975k
    SKIP_BLANKS;
11283
975k
    if ((CUR == '.') && (NXT(1) == '.')) {
11284
5.89k
  SKIP(2);
11285
5.89k
  SKIP_BLANKS;
11286
5.89k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11287
5.89k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11288
969k
    } else if (CUR == '.') {
11289
39.7k
  NEXT;
11290
39.7k
  SKIP_BLANKS;
11291
929k
    } else {
11292
929k
  xmlChar *name = NULL;
11293
929k
  xmlChar *prefix = NULL;
11294
929k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11295
929k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11296
929k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11297
929k
  int op1;
11298
11299
  /*
11300
   * The modification needed for XPointer change to the production
11301
   */
11302
#ifdef LIBXML_XPTR_LOCS_ENABLED
11303
  if (ctxt->xptr) {
11304
      name = xmlXPathParseNCName(ctxt);
11305
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11306
                op2 = ctxt->comp->last;
11307
    xmlFree(name);
11308
    SKIP_BLANKS;
11309
    if (CUR != '(') {
11310
        XP_ERROR(XPATH_EXPR_ERROR);
11311
    }
11312
    NEXT;
11313
    SKIP_BLANKS;
11314
11315
    xmlXPathCompileExpr(ctxt, 1);
11316
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11317
    CHECK_ERROR;
11318
11319
    SKIP_BLANKS;
11320
    if (CUR != ')') {
11321
        XP_ERROR(XPATH_EXPR_ERROR);
11322
    }
11323
    NEXT;
11324
    rangeto = 1;
11325
    goto eval_predicates;
11326
      }
11327
  }
11328
#endif
11329
929k
  if (CUR == '*') {
11330
476k
      axis = AXIS_CHILD;
11331
476k
  } else {
11332
453k
      if (name == NULL)
11333
453k
    name = xmlXPathParseNCName(ctxt);
11334
453k
      if (name != NULL) {
11335
328k
    axis = xmlXPathIsAxisName(name);
11336
328k
    if (axis != 0) {
11337
1.54k
        SKIP_BLANKS;
11338
1.54k
        if ((CUR == ':') && (NXT(1) == ':')) {
11339
24
      SKIP(2);
11340
24
      xmlFree(name);
11341
24
      name = NULL;
11342
1.52k
        } else {
11343
      /* an element name can conflict with an axis one :-\ */
11344
1.52k
      axis = AXIS_CHILD;
11345
1.52k
        }
11346
326k
    } else {
11347
326k
        axis = AXIS_CHILD;
11348
326k
    }
11349
328k
      } else if (CUR == '@') {
11350
23.8k
    NEXT;
11351
23.8k
    axis = AXIS_ATTRIBUTE;
11352
101k
      } else {
11353
101k
    axis = AXIS_CHILD;
11354
101k
      }
11355
453k
  }
11356
11357
929k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11358
100k
            xmlFree(name);
11359
100k
            return;
11360
100k
        }
11361
11362
828k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11363
828k
  if (test == 0)
11364
7.21k
      return;
11365
11366
821k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11367
821k
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11368
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11369
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11370
0
      }
11371
0
  }
11372
#ifdef DEBUG_STEP
11373
  xmlGenericError(xmlGenericErrorContext,
11374
    "Basis : computing new set\n");
11375
#endif
11376
11377
#ifdef DEBUG_STEP
11378
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11379
  if (ctxt->value == NULL)
11380
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11381
  else if (ctxt->value->nodesetval == NULL)
11382
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11383
  else
11384
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11385
#endif
11386
11387
#ifdef LIBXML_XPTR_LOCS_ENABLED
11388
eval_predicates:
11389
#endif
11390
821k
  op1 = ctxt->comp->last;
11391
821k
  ctxt->comp->last = -1;
11392
11393
821k
  SKIP_BLANKS;
11394
1.10M
  while (CUR == '[') {
11395
284k
      xmlXPathCompPredicate(ctxt, 0);
11396
284k
  }
11397
11398
#ifdef LIBXML_XPTR_LOCS_ENABLED
11399
  if (rangeto) {
11400
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11401
  } else
11402
#endif
11403
821k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11404
821k
                           test, type, (void *)prefix, (void *)name) == -1) {
11405
0
            xmlFree(prefix);
11406
0
            xmlFree(name);
11407
0
        }
11408
821k
    }
11409
#ifdef DEBUG_STEP
11410
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11411
    if (ctxt->value == NULL)
11412
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11413
    else if (ctxt->value->nodesetval == NULL)
11414
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415
    else
11416
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11417
    ctxt->value->nodesetval);
11418
#endif
11419
975k
}
11420
11421
/**
11422
 * xmlXPathCompRelativeLocationPath:
11423
 * @ctxt:  the XPath Parser context
11424
 *
11425
 *  [3]   RelativeLocationPath ::=   Step
11426
 *                     | RelativeLocationPath '/' Step
11427
 *                     | AbbreviatedRelativeLocationPath
11428
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11429
 *
11430
 * Compile a relative location path.
11431
 */
11432
static void
11433
xmlXPathCompRelativeLocationPath
11434
776k
(xmlXPathParserContextPtr ctxt) {
11435
776k
    SKIP_BLANKS;
11436
776k
    if ((CUR == '/') && (NXT(1) == '/')) {
11437
2.11k
  SKIP(2);
11438
2.11k
  SKIP_BLANKS;
11439
2.11k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11440
2.11k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11441
774k
    } else if (CUR == '/') {
11442
20.3k
      NEXT;
11443
20.3k
  SKIP_BLANKS;
11444
20.3k
    }
11445
776k
    xmlXPathCompStep(ctxt);
11446
776k
    CHECK_ERROR;
11447
765k
    SKIP_BLANKS;
11448
964k
    while (CUR == '/') {
11449
199k
  if ((CUR == '/') && (NXT(1) == '/')) {
11450
116k
      SKIP(2);
11451
116k
      SKIP_BLANKS;
11452
116k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11453
116k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11454
116k
      xmlXPathCompStep(ctxt);
11455
116k
  } else if (CUR == '/') {
11456
82.4k
      NEXT;
11457
82.4k
      SKIP_BLANKS;
11458
82.4k
      xmlXPathCompStep(ctxt);
11459
82.4k
  }
11460
199k
  SKIP_BLANKS;
11461
199k
    }
11462
765k
}
11463
11464
/**
11465
 * xmlXPathCompLocationPath:
11466
 * @ctxt:  the XPath Parser context
11467
 *
11468
 *  [1]   LocationPath ::=   RelativeLocationPath
11469
 *                     | AbsoluteLocationPath
11470
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11471
 *                     | AbbreviatedAbsoluteLocationPath
11472
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11473
 *                           '//' RelativeLocationPath
11474
 *
11475
 * Compile a location path
11476
 *
11477
 * // is short for /descendant-or-self::node()/. For example,
11478
 * //para is short for /descendant-or-self::node()/child::para and
11479
 * so will select any para element in the document (even a para element
11480
 * that is a document element will be selected by //para since the
11481
 * document element node is a child of the root node); div//para is
11482
 * short for div/descendant-or-self::node()/child::para and so will
11483
 * select all para descendants of div children.
11484
 */
11485
static void
11486
782k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11487
782k
    SKIP_BLANKS;
11488
782k
    if (CUR != '/') {
11489
630k
        xmlXPathCompRelativeLocationPath(ctxt);
11490
630k
    } else {
11491
298k
  while (CUR == '/') {
11492
152k
      if ((CUR == '/') && (NXT(1) == '/')) {
11493
68.5k
    SKIP(2);
11494
68.5k
    SKIP_BLANKS;
11495
68.5k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11496
68.5k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11497
68.5k
    xmlXPathCompRelativeLocationPath(ctxt);
11498
83.9k
      } else if (CUR == '/') {
11499
83.9k
    NEXT;
11500
83.9k
    SKIP_BLANKS;
11501
83.9k
    if ((CUR != 0 ) &&
11502
83.9k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11503
81.0k
         (CUR == '@') || (CUR == '*')))
11504
59.6k
        xmlXPathCompRelativeLocationPath(ctxt);
11505
83.9k
      }
11506
152k
      CHECK_ERROR;
11507
152k
  }
11508
152k
    }
11509
782k
}
11510
11511
/************************************************************************
11512
 *                  *
11513
 *    XPath precompiled expression evaluation     *
11514
 *                  *
11515
 ************************************************************************/
11516
11517
static int
11518
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11519
11520
#ifdef DEBUG_STEP
11521
static void
11522
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11523
        int nbNodes)
11524
{
11525
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11526
    switch (op->value) {
11527
        case AXIS_ANCESTOR:
11528
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11529
            break;
11530
        case AXIS_ANCESTOR_OR_SELF:
11531
            xmlGenericError(xmlGenericErrorContext,
11532
                            "axis 'ancestors-or-self' ");
11533
            break;
11534
        case AXIS_ATTRIBUTE:
11535
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11536
            break;
11537
        case AXIS_CHILD:
11538
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11539
            break;
11540
        case AXIS_DESCENDANT:
11541
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11542
            break;
11543
        case AXIS_DESCENDANT_OR_SELF:
11544
            xmlGenericError(xmlGenericErrorContext,
11545
                            "axis 'descendant-or-self' ");
11546
            break;
11547
        case AXIS_FOLLOWING:
11548
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11549
            break;
11550
        case AXIS_FOLLOWING_SIBLING:
11551
            xmlGenericError(xmlGenericErrorContext,
11552
                            "axis 'following-siblings' ");
11553
            break;
11554
        case AXIS_NAMESPACE:
11555
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11556
            break;
11557
        case AXIS_PARENT:
11558
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11559
            break;
11560
        case AXIS_PRECEDING:
11561
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11562
            break;
11563
        case AXIS_PRECEDING_SIBLING:
11564
            xmlGenericError(xmlGenericErrorContext,
11565
                            "axis 'preceding-sibling' ");
11566
            break;
11567
        case AXIS_SELF:
11568
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11569
            break;
11570
    }
11571
    xmlGenericError(xmlGenericErrorContext,
11572
  " context contains %d nodes\n", nbNodes);
11573
    switch (op->value2) {
11574
        case NODE_TEST_NONE:
11575
            xmlGenericError(xmlGenericErrorContext,
11576
                            "           searching for none !!!\n");
11577
            break;
11578
        case NODE_TEST_TYPE:
11579
            xmlGenericError(xmlGenericErrorContext,
11580
                            "           searching for type %d\n", op->value3);
11581
            break;
11582
        case NODE_TEST_PI:
11583
            xmlGenericError(xmlGenericErrorContext,
11584
                            "           searching for PI !!!\n");
11585
            break;
11586
        case NODE_TEST_ALL:
11587
            xmlGenericError(xmlGenericErrorContext,
11588
                            "           searching for *\n");
11589
            break;
11590
        case NODE_TEST_NS:
11591
            xmlGenericError(xmlGenericErrorContext,
11592
                            "           searching for namespace %s\n",
11593
                            op->value5);
11594
            break;
11595
        case NODE_TEST_NAME:
11596
            xmlGenericError(xmlGenericErrorContext,
11597
                            "           searching for name %s\n", op->value5);
11598
            if (op->value4)
11599
                xmlGenericError(xmlGenericErrorContext,
11600
                                "           with namespace %s\n", op->value4);
11601
            break;
11602
    }
11603
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11604
}
11605
#endif /* DEBUG_STEP */
11606
11607
/**
11608
 * xmlXPathNodeSetFilter:
11609
 * @ctxt:  the XPath Parser context
11610
 * @set: the node set to filter
11611
 * @filterOpIndex: the index of the predicate/filter op
11612
 * @minPos: minimum position in the filtered set (1-based)
11613
 * @maxPos: maximum position in the filtered set (1-based)
11614
 * @hasNsNodes: true if the node set may contain namespace nodes
11615
 *
11616
 * Filter a node set, keeping only nodes for which the predicate expression
11617
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11618
 * filtered result.
11619
 */
11620
static void
11621
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11622
          xmlNodeSetPtr set,
11623
          int filterOpIndex,
11624
                      int minPos, int maxPos,
11625
          int hasNsNodes)
11626
218k
{
11627
218k
    xmlXPathContextPtr xpctxt;
11628
218k
    xmlNodePtr oldnode;
11629
218k
    xmlDocPtr olddoc;
11630
218k
    xmlXPathStepOpPtr filterOp;
11631
218k
    int oldcs, oldpp;
11632
218k
    int i, j, pos;
11633
11634
218k
    if ((set == NULL) || (set->nodeNr == 0))
11635
1.35k
        return;
11636
11637
    /*
11638
    * Check if the node set contains a sufficient number of nodes for
11639
    * the requested range.
11640
    */
11641
217k
    if (set->nodeNr < minPos) {
11642
775
        xmlXPathNodeSetClear(set, hasNsNodes);
11643
775
        return;
11644
775
    }
11645
11646
216k
    xpctxt = ctxt->context;
11647
216k
    oldnode = xpctxt->node;
11648
216k
    olddoc = xpctxt->doc;
11649
216k
    oldcs = xpctxt->contextSize;
11650
216k
    oldpp = xpctxt->proximityPosition;
11651
216k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11652
11653
216k
    xpctxt->contextSize = set->nodeNr;
11654
11655
608k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11656
574k
        xmlNodePtr node = set->nodeTab[i];
11657
574k
        int res;
11658
11659
574k
        xpctxt->node = node;
11660
574k
        xpctxt->proximityPosition = i + 1;
11661
11662
        /*
11663
        * Also set the xpath document in case things like
11664
        * key() are evaluated in the predicate.
11665
        *
11666
        * TODO: Get real doc for namespace nodes.
11667
        */
11668
574k
        if ((node->type != XML_NAMESPACE_DECL) &&
11669
574k
            (node->doc != NULL))
11670
574k
            xpctxt->doc = node->doc;
11671
11672
574k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11673
11674
574k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11675
981
            break;
11676
573k
        if (res < 0) {
11677
            /* Shouldn't happen */
11678
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11679
0
            break;
11680
0
        }
11681
11682
573k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11683
443k
            if (i != j) {
11684
14.4k
                set->nodeTab[j] = node;
11685
14.4k
                set->nodeTab[i] = NULL;
11686
14.4k
            }
11687
11688
443k
            j += 1;
11689
443k
        } else {
11690
            /* Remove the entry from the initial node set. */
11691
130k
            set->nodeTab[i] = NULL;
11692
130k
            if (node->type == XML_NAMESPACE_DECL)
11693
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11694
130k
        }
11695
11696
573k
        if (res != 0) {
11697
443k
            if (pos == maxPos) {
11698
182k
                i += 1;
11699
182k
                break;
11700
182k
            }
11701
11702
261k
            pos += 1;
11703
261k
        }
11704
573k
    }
11705
11706
    /* Free remaining nodes. */
11707
216k
    if (hasNsNodes) {
11708
561
        for (; i < set->nodeNr; i++) {
11709
89
            xmlNodePtr node = set->nodeTab[i];
11710
89
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11711
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11712
89
        }
11713
472
    }
11714
11715
216k
    set->nodeNr = j;
11716
11717
    /* If too many elements were removed, shrink table to preserve memory. */
11718
216k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11719
216k
        (set->nodeNr < set->nodeMax / 2)) {
11720
3.65k
        xmlNodePtr *tmp;
11721
3.65k
        int nodeMax = set->nodeNr;
11722
11723
3.65k
        if (nodeMax < XML_NODESET_DEFAULT)
11724
3.62k
            nodeMax = XML_NODESET_DEFAULT;
11725
3.65k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11726
3.65k
                nodeMax * sizeof(xmlNodePtr));
11727
3.65k
        if (tmp == NULL) {
11728
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11729
3.65k
        } else {
11730
3.65k
            set->nodeTab = tmp;
11731
3.65k
            set->nodeMax = nodeMax;
11732
3.65k
        }
11733
3.65k
    }
11734
11735
216k
    xpctxt->node = oldnode;
11736
216k
    xpctxt->doc = olddoc;
11737
216k
    xpctxt->contextSize = oldcs;
11738
216k
    xpctxt->proximityPosition = oldpp;
11739
216k
}
11740
11741
#ifdef LIBXML_XPTR_LOCS_ENABLED
11742
/**
11743
 * xmlXPathLocationSetFilter:
11744
 * @ctxt:  the XPath Parser context
11745
 * @locset: the location set to filter
11746
 * @filterOpIndex: the index of the predicate/filter op
11747
 * @minPos: minimum position in the filtered set (1-based)
11748
 * @maxPos: maximum position in the filtered set (1-based)
11749
 *
11750
 * Filter a location set, keeping only nodes for which the predicate
11751
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11752
 * in the filtered result.
11753
 */
11754
static void
11755
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11756
              xmlLocationSetPtr locset,
11757
              int filterOpIndex,
11758
                          int minPos, int maxPos)
11759
{
11760
    xmlXPathContextPtr xpctxt;
11761
    xmlNodePtr oldnode;
11762
    xmlDocPtr olddoc;
11763
    xmlXPathStepOpPtr filterOp;
11764
    int oldcs, oldpp;
11765
    int i, j, pos;
11766
11767
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11768
        return;
11769
11770
    xpctxt = ctxt->context;
11771
    oldnode = xpctxt->node;
11772
    olddoc = xpctxt->doc;
11773
    oldcs = xpctxt->contextSize;
11774
    oldpp = xpctxt->proximityPosition;
11775
    filterOp = &ctxt->comp->steps[filterOpIndex];
11776
11777
    xpctxt->contextSize = locset->locNr;
11778
11779
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11780
        xmlNodePtr contextNode = locset->locTab[i]->user;
11781
        int res;
11782
11783
        xpctxt->node = contextNode;
11784
        xpctxt->proximityPosition = i + 1;
11785
11786
        /*
11787
        * Also set the xpath document in case things like
11788
        * key() are evaluated in the predicate.
11789
        *
11790
        * TODO: Get real doc for namespace nodes.
11791
        */
11792
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11793
            (contextNode->doc != NULL))
11794
            xpctxt->doc = contextNode->doc;
11795
11796
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11797
11798
        if (ctxt->error != XPATH_EXPRESSION_OK)
11799
            break;
11800
        if (res < 0) {
11801
            /* Shouldn't happen */
11802
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11803
            break;
11804
        }
11805
11806
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11807
            if (i != j) {
11808
                locset->locTab[j] = locset->locTab[i];
11809
                locset->locTab[i] = NULL;
11810
            }
11811
11812
            j += 1;
11813
        } else {
11814
            /* Remove the entry from the initial location set. */
11815
            xmlXPathFreeObject(locset->locTab[i]);
11816
            locset->locTab[i] = NULL;
11817
        }
11818
11819
        if (res != 0) {
11820
            if (pos == maxPos) {
11821
                i += 1;
11822
                break;
11823
            }
11824
11825
            pos += 1;
11826
        }
11827
    }
11828
11829
    /* Free remaining nodes. */
11830
    for (; i < locset->locNr; i++)
11831
        xmlXPathFreeObject(locset->locTab[i]);
11832
11833
    locset->locNr = j;
11834
11835
    /* If too many elements were removed, shrink table to preserve memory. */
11836
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11837
        (locset->locNr < locset->locMax / 2)) {
11838
        xmlXPathObjectPtr *tmp;
11839
        int locMax = locset->locNr;
11840
11841
        if (locMax < XML_NODESET_DEFAULT)
11842
            locMax = XML_NODESET_DEFAULT;
11843
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11844
                locMax * sizeof(xmlXPathObjectPtr));
11845
        if (tmp == NULL) {
11846
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11847
        } else {
11848
            locset->locTab = tmp;
11849
            locset->locMax = locMax;
11850
        }
11851
    }
11852
11853
    xpctxt->node = oldnode;
11854
    xpctxt->doc = olddoc;
11855
    xpctxt->contextSize = oldcs;
11856
    xpctxt->proximityPosition = oldpp;
11857
}
11858
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11859
11860
/**
11861
 * xmlXPathCompOpEvalPredicate:
11862
 * @ctxt:  the XPath Parser context
11863
 * @op: the predicate op
11864
 * @set: the node set to filter
11865
 * @minPos: minimum position in the filtered set (1-based)
11866
 * @maxPos: maximum position in the filtered set (1-based)
11867
 * @hasNsNodes: true if the node set may contain namespace nodes
11868
 *
11869
 * Filter a node set, keeping only nodes for which the sequence of predicate
11870
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11871
 * in the filtered result.
11872
 */
11873
static void
11874
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11875
          xmlXPathStepOpPtr op,
11876
          xmlNodeSetPtr set,
11877
                            int minPos, int maxPos,
11878
          int hasNsNodes)
11879
217k
{
11880
217k
    if (op->ch1 != -1) {
11881
1.11k
  xmlXPathCompExprPtr comp = ctxt->comp;
11882
  /*
11883
  * Process inner predicates first.
11884
  */
11885
1.11k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11886
0
            xmlGenericError(xmlGenericErrorContext,
11887
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11888
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11889
0
  }
11890
1.11k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11891
1.11k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11892
1.11k
        ctxt->context->depth += 1;
11893
1.11k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11894
1.11k
                                    1, set->nodeNr, hasNsNodes);
11895
1.11k
        ctxt->context->depth -= 1;
11896
1.11k
  CHECK_ERROR;
11897
1.11k
    }
11898
11899
217k
    if (op->ch2 != -1)
11900
217k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11901
217k
}
11902
11903
static int
11904
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11905
          xmlXPathStepOpPtr op,
11906
          int *maxPos)
11907
24.0k
{
11908
11909
24.0k
    xmlXPathStepOpPtr exprOp;
11910
11911
    /*
11912
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11913
    */
11914
11915
    /*
11916
    * If not -1, then ch1 will point to:
11917
    * 1) For predicates (XPATH_OP_PREDICATE):
11918
    *    - an inner predicate operator
11919
    * 2) For filters (XPATH_OP_FILTER):
11920
    *    - an inner filter operator OR
11921
    *    - an expression selecting the node set.
11922
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11923
    */
11924
24.0k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11925
0
  return(0);
11926
11927
24.0k
    if (op->ch2 != -1) {
11928
24.0k
  exprOp = &ctxt->comp->steps[op->ch2];
11929
24.0k
    } else
11930
0
  return(0);
11931
11932
24.0k
    if ((exprOp != NULL) &&
11933
24.0k
  (exprOp->op == XPATH_OP_VALUE) &&
11934
24.0k
  (exprOp->value4 != NULL) &&
11935
24.0k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11936
10.8k
    {
11937
10.8k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11938
11939
  /*
11940
  * We have a "[n]" predicate here.
11941
  * TODO: Unfortunately this simplistic test here is not
11942
  * able to detect a position() predicate in compound
11943
  * expressions like "[@attr = 'a" and position() = 1],
11944
  * and even not the usage of position() in
11945
  * "[position() = 1]"; thus - obviously - a position-range,
11946
  * like it "[position() < 5]", is also not detected.
11947
  * Maybe we could rewrite the AST to ease the optimization.
11948
  */
11949
11950
10.8k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11951
10.6k
      *maxPos = (int) floatval;
11952
10.6k
            if (floatval == (double) *maxPos)
11953
10.5k
                return(1);
11954
10.6k
        }
11955
10.8k
    }
11956
13.4k
    return(0);
11957
24.0k
}
11958
11959
static int
11960
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11961
                           xmlXPathStepOpPtr op,
11962
         xmlNodePtr * first, xmlNodePtr * last,
11963
         int toBool)
11964
754k
{
11965
11966
754k
#define XP_TEST_HIT \
11967
18.5M
    if (hasAxisRange != 0) { \
11968
429k
  if (++pos == maxPos) { \
11969
252k
      if (addNode(seq, cur) < 0) \
11970
252k
          ctxt->error = XPATH_MEMORY_ERROR; \
11971
252k
      goto axis_range_end; } \
11972
18.1M
    } else { \
11973
18.1M
  if (addNode(seq, cur) < 0) \
11974
18.1M
      ctxt->error = XPATH_MEMORY_ERROR; \
11975
18.1M
  if (breakOnFirstHit) goto first_hit; }
11976
11977
754k
#define XP_TEST_HIT_NS \
11978
754k
    if (hasAxisRange != 0) { \
11979
0
  if (++pos == maxPos) { \
11980
0
      hasNsNodes = 1; \
11981
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11982
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11983
0
  goto axis_range_end; } \
11984
0
    } else { \
11985
0
  hasNsNodes = 1; \
11986
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11987
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11988
0
  if (breakOnFirstHit) goto first_hit; }
11989
11990
754k
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11991
754k
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11992
754k
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11993
754k
    const xmlChar *prefix = op->value4;
11994
754k
    const xmlChar *name = op->value5;
11995
754k
    const xmlChar *URI = NULL;
11996
11997
#ifdef DEBUG_STEP
11998
    int nbMatches = 0, prevMatches = 0;
11999
#endif
12000
754k
    int total = 0, hasNsNodes = 0;
12001
    /* The popped object holding the context nodes */
12002
754k
    xmlXPathObjectPtr obj;
12003
    /* The set of context nodes for the node tests */
12004
754k
    xmlNodeSetPtr contextSeq;
12005
754k
    int contextIdx;
12006
754k
    xmlNodePtr contextNode;
12007
    /* The final resulting node set wrt to all context nodes */
12008
754k
    xmlNodeSetPtr outSeq;
12009
    /*
12010
    * The temporary resulting node set wrt 1 context node.
12011
    * Used to feed predicate evaluation.
12012
    */
12013
754k
    xmlNodeSetPtr seq;
12014
754k
    xmlNodePtr cur;
12015
    /* First predicate operator */
12016
754k
    xmlXPathStepOpPtr predOp;
12017
754k
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12018
754k
    int hasPredicateRange, hasAxisRange, pos;
12019
754k
    int breakOnFirstHit;
12020
12021
754k
    xmlXPathTraversalFunction next = NULL;
12022
754k
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12023
754k
    xmlXPathNodeSetMergeFunction mergeAndClear;
12024
754k
    xmlNodePtr oldContextNode;
12025
754k
    xmlXPathContextPtr xpctxt = ctxt->context;
12026
12027
12028
754k
    CHECK_TYPE0(XPATH_NODESET);
12029
749k
    obj = valuePop(ctxt);
12030
    /*
12031
    * Setup namespaces.
12032
    */
12033
749k
    if (prefix != NULL) {
12034
3.36k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12035
3.36k
        if (URI == NULL) {
12036
3.08k
      xmlXPathReleaseObject(xpctxt, obj);
12037
3.08k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12038
0
  }
12039
3.36k
    }
12040
    /*
12041
    * Setup axis.
12042
    *
12043
    * MAYBE FUTURE TODO: merging optimizations:
12044
    * - If the nodes to be traversed wrt to the initial nodes and
12045
    *   the current axis cannot overlap, then we could avoid searching
12046
    *   for duplicates during the merge.
12047
    *   But the question is how/when to evaluate if they cannot overlap.
12048
    *   Example: if we know that for two initial nodes, the one is
12049
    *   not in the ancestor-or-self axis of the other, then we could safely
12050
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12051
    *   the descendant-or-self axis.
12052
    */
12053
746k
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12054
746k
    switch (axis) {
12055
0
        case AXIS_ANCESTOR:
12056
0
            first = NULL;
12057
0
            next = xmlXPathNextAncestor;
12058
0
            break;
12059
0
        case AXIS_ANCESTOR_OR_SELF:
12060
0
            first = NULL;
12061
0
            next = xmlXPathNextAncestorOrSelf;
12062
0
            break;
12063
20.0k
        case AXIS_ATTRIBUTE:
12064
20.0k
            first = NULL;
12065
20.0k
      last = NULL;
12066
20.0k
            next = xmlXPathNextAttribute;
12067
20.0k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12068
20.0k
            break;
12069
619k
        case AXIS_CHILD:
12070
619k
      last = NULL;
12071
619k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12072
619k
    (type == NODE_TYPE_NODE))
12073
601k
      {
12074
    /*
12075
    * Optimization if an element node type is 'element'.
12076
    */
12077
601k
    next = xmlXPathNextChildElement;
12078
601k
      } else
12079
18.1k
    next = xmlXPathNextChild;
12080
619k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081
619k
            break;
12082
43.2k
        case AXIS_DESCENDANT:
12083
43.2k
      last = NULL;
12084
43.2k
            next = xmlXPathNextDescendant;
12085
43.2k
            break;
12086
46.0k
        case AXIS_DESCENDANT_OR_SELF:
12087
46.0k
      last = NULL;
12088
46.0k
            next = xmlXPathNextDescendantOrSelf;
12089
46.0k
            break;
12090
0
        case AXIS_FOLLOWING:
12091
0
      last = NULL;
12092
0
            next = xmlXPathNextFollowing;
12093
0
            break;
12094
0
        case AXIS_FOLLOWING_SIBLING:
12095
0
      last = NULL;
12096
0
            next = xmlXPathNextFollowingSibling;
12097
0
            break;
12098
0
        case AXIS_NAMESPACE:
12099
0
            first = NULL;
12100
0
      last = NULL;
12101
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12102
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12103
0
            break;
12104
17.9k
        case AXIS_PARENT:
12105
17.9k
            first = NULL;
12106
17.9k
            next = xmlXPathNextParent;
12107
17.9k
            break;
12108
0
        case AXIS_PRECEDING:
12109
0
            first = NULL;
12110
0
            next = xmlXPathNextPrecedingInternal;
12111
0
            break;
12112
0
        case AXIS_PRECEDING_SIBLING:
12113
0
            first = NULL;
12114
0
            next = xmlXPathNextPrecedingSibling;
12115
0
            break;
12116
0
        case AXIS_SELF:
12117
0
            first = NULL;
12118
0
      last = NULL;
12119
0
            next = xmlXPathNextSelf;
12120
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12121
0
            break;
12122
746k
    }
12123
12124
#ifdef DEBUG_STEP
12125
    xmlXPathDebugDumpStepAxis(op,
12126
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12127
#endif
12128
12129
746k
    if (next == NULL) {
12130
0
  xmlXPathReleaseObject(xpctxt, obj);
12131
0
        return(0);
12132
0
    }
12133
746k
    contextSeq = obj->nodesetval;
12134
746k
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12135
43.8k
  xmlXPathReleaseObject(xpctxt, obj);
12136
43.8k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12137
43.8k
        return(0);
12138
43.8k
    }
12139
    /*
12140
    * Predicate optimization ---------------------------------------------
12141
    * If this step has a last predicate, which contains a position(),
12142
    * then we'll optimize (although not exactly "position()", but only
12143
    * the  short-hand form, i.e., "[n]".
12144
    *
12145
    * Example - expression "/foo[parent::bar][1]":
12146
    *
12147
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12148
    *   ROOT                               -- op->ch1
12149
    *   PREDICATE                          -- op->ch2 (predOp)
12150
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12151
    *       SORT
12152
    *         COLLECT  'parent' 'name' 'node' bar
12153
    *           NODE
12154
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12155
    *
12156
    */
12157
702k
    maxPos = 0;
12158
702k
    predOp = NULL;
12159
702k
    hasPredicateRange = 0;
12160
702k
    hasAxisRange = 0;
12161
702k
    if (op->ch2 != -1) {
12162
  /*
12163
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12164
  */
12165
24.0k
  predOp = &ctxt->comp->steps[op->ch2];
12166
24.0k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12167
10.5k
      if (predOp->ch1 != -1) {
12168
    /*
12169
    * Use the next inner predicate operator.
12170
    */
12171
334
    predOp = &ctxt->comp->steps[predOp->ch1];
12172
334
    hasPredicateRange = 1;
12173
10.2k
      } else {
12174
    /*
12175
    * There's no other predicate than the [n] predicate.
12176
    */
12177
10.2k
    predOp = NULL;
12178
10.2k
    hasAxisRange = 1;
12179
10.2k
      }
12180
10.5k
  }
12181
24.0k
    }
12182
702k
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12183
    /*
12184
    * Axis traversal -----------------------------------------------------
12185
    */
12186
    /*
12187
     * 2.3 Node Tests
12188
     *  - For the attribute axis, the principal node type is attribute.
12189
     *  - For the namespace axis, the principal node type is namespace.
12190
     *  - For other axes, the principal node type is element.
12191
     *
12192
     * A node test * is true for any node of the
12193
     * principal node type. For example, child::* will
12194
     * select all element children of the context node
12195
     */
12196
702k
    oldContextNode = xpctxt->node;
12197
702k
    addNode = xmlXPathNodeSetAddUnique;
12198
702k
    outSeq = NULL;
12199
702k
    seq = NULL;
12200
702k
    contextNode = NULL;
12201
702k
    contextIdx = 0;
12202
12203
12204
8.77M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12205
8.77M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12206
8.09M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12207
12208
8.09M
  if (seq == NULL) {
12209
734k
      seq = xmlXPathNodeSetCreate(NULL);
12210
734k
      if (seq == NULL) {
12211
                /* TODO: Propagate memory error. */
12212
0
    total = 0;
12213
0
    goto error;
12214
0
      }
12215
734k
  }
12216
  /*
12217
  * Traverse the axis and test the nodes.
12218
  */
12219
8.09M
  pos = 0;
12220
8.09M
  cur = NULL;
12221
8.09M
  hasNsNodes = 0;
12222
35.6M
        do {
12223
35.6M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12224
0
                goto error;
12225
12226
35.6M
            cur = next(ctxt, cur);
12227
35.6M
            if (cur == NULL)
12228
7.82M
                break;
12229
12230
      /*
12231
      * QUESTION TODO: What does the "first" and "last" stuff do?
12232
      */
12233
27.8M
            if ((first != NULL) && (*first != NULL)) {
12234
735
    if (*first == cur)
12235
63
        break;
12236
672
    if (((total % 256) == 0) &&
12237
672
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12238
672
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12239
#else
12240
        (xmlXPathCmpNodes(*first, cur) >= 0))
12241
#endif
12242
156
    {
12243
156
        break;
12244
156
    }
12245
672
      }
12246
27.8M
      if ((last != NULL) && (*last != NULL)) {
12247
0
    if (*last == cur)
12248
0
        break;
12249
0
    if (((total % 256) == 0) &&
12250
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12251
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12252
#else
12253
        (xmlXPathCmpNodes(cur, *last) >= 0))
12254
#endif
12255
0
    {
12256
0
        break;
12257
0
    }
12258
0
      }
12259
12260
27.8M
            total++;
12261
12262
#ifdef DEBUG_STEP
12263
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12264
#endif
12265
12266
27.8M
      switch (test) {
12267
0
                case NODE_TEST_NONE:
12268
0
        total = 0;
12269
0
                    STRANGE
12270
0
        goto error;
12271
14.4M
                case NODE_TEST_TYPE:
12272
14.4M
        if (type == NODE_TYPE_NODE) {
12273
12.7M
      switch (cur->type) {
12274
37.9k
          case XML_DOCUMENT_NODE:
12275
37.9k
          case XML_HTML_DOCUMENT_NODE:
12276
6.32M
          case XML_ELEMENT_NODE:
12277
6.32M
          case XML_ATTRIBUTE_NODE:
12278
6.41M
          case XML_PI_NODE:
12279
6.84M
          case XML_COMMENT_NODE:
12280
6.87M
          case XML_CDATA_SECTION_NODE:
12281
12.7M
          case XML_TEXT_NODE:
12282
12.7M
        XP_TEST_HIT
12283
12.7M
        break;
12284
12.7M
          case XML_NAMESPACE_DECL: {
12285
0
        if (axis == AXIS_NAMESPACE) {
12286
0
            XP_TEST_HIT_NS
12287
0
        } else {
12288
0
                              hasNsNodes = 1;
12289
0
            XP_TEST_HIT
12290
0
        }
12291
0
        break;
12292
0
                            }
12293
16.5k
          default:
12294
16.5k
        break;
12295
12.7M
      }
12296
12.7M
        } else if (cur->type == (xmlElementType) type) {
12297
909k
      if (cur->type == XML_NAMESPACE_DECL)
12298
0
          XP_TEST_HIT_NS
12299
909k
      else
12300
909k
          XP_TEST_HIT
12301
909k
        } else if ((type == NODE_TYPE_TEXT) &&
12302
809k
       (cur->type == XML_CDATA_SECTION_NODE))
12303
11.7k
        {
12304
11.7k
      XP_TEST_HIT
12305
11.7k
        }
12306
14.2M
        break;
12307
14.2M
                case NODE_TEST_PI:
12308
0
                    if ((cur->type == XML_PI_NODE) &&
12309
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12310
0
        {
12311
0
      XP_TEST_HIT
12312
0
                    }
12313
0
                    break;
12314
6.95M
                case NODE_TEST_ALL:
12315
6.95M
                    if (axis == AXIS_ATTRIBUTE) {
12316
238k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12317
238k
      {
12318
238k
                            if (prefix == NULL)
12319
238k
          {
12320
238k
        XP_TEST_HIT
12321
238k
                            } else if ((cur->ns != NULL) &&
12322
0
        (xmlStrEqual(URI, cur->ns->href)))
12323
0
          {
12324
0
        XP_TEST_HIT
12325
0
                            }
12326
238k
                        }
12327
6.71M
                    } else if (axis == AXIS_NAMESPACE) {
12328
0
                        if (cur->type == XML_NAMESPACE_DECL)
12329
0
      {
12330
0
          XP_TEST_HIT_NS
12331
0
                        }
12332
6.71M
                    } else {
12333
6.71M
                        if (cur->type == XML_ELEMENT_NODE) {
12334
3.88M
                            if (prefix == NULL)
12335
3.88M
          {
12336
3.88M
        XP_TEST_HIT
12337
12338
3.88M
                            } else if ((cur->ns != NULL) &&
12339
20
        (xmlStrEqual(URI, cur->ns->href)))
12340
0
          {
12341
0
        XP_TEST_HIT
12342
0
                            }
12343
3.88M
                        }
12344
6.71M
                    }
12345
6.92M
                    break;
12346
6.92M
                case NODE_TEST_NS:{
12347
0
                        TODO;
12348
0
                        break;
12349
6.95M
                    }
12350
6.39M
                case NODE_TEST_NAME:
12351
6.39M
                    if (axis == AXIS_ATTRIBUTE) {
12352
193k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12353
0
          break;
12354
6.20M
        } else if (axis == AXIS_NAMESPACE) {
12355
0
                        if (cur->type != XML_NAMESPACE_DECL)
12356
0
          break;
12357
6.20M
        } else {
12358
6.20M
            if (cur->type != XML_ELEMENT_NODE)
12359
2.13M
          break;
12360
6.20M
        }
12361
4.25M
                    switch (cur->type) {
12362
4.06M
                        case XML_ELEMENT_NODE:
12363
4.06M
                            if (xmlStrEqual(name, cur->name)) {
12364
779k
                                if (prefix == NULL) {
12365
779k
                                    if (cur->ns == NULL)
12366
769k
            {
12367
769k
          XP_TEST_HIT
12368
769k
                                    }
12369
779k
                                } else {
12370
464
                                    if ((cur->ns != NULL) &&
12371
464
                                        (xmlStrEqual(URI, cur->ns->href)))
12372
160
            {
12373
160
          XP_TEST_HIT
12374
160
                                    }
12375
464
                                }
12376
779k
                            }
12377
4.06M
                            break;
12378
4.06M
                        case XML_ATTRIBUTE_NODE:{
12379
193k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12380
12381
193k
                                if (xmlStrEqual(name, attr->name)) {
12382
9.44k
                                    if (prefix == NULL) {
12383
9.44k
                                        if ((attr->ns == NULL) ||
12384
9.44k
                                            (attr->ns->prefix == NULL))
12385
9.44k
          {
12386
9.44k
              XP_TEST_HIT
12387
9.44k
                                        }
12388
9.44k
                                    } else {
12389
0
                                        if ((attr->ns != NULL) &&
12390
0
                                            (xmlStrEqual(URI,
12391
0
                attr->ns->href)))
12392
0
          {
12393
0
              XP_TEST_HIT
12394
0
                                        }
12395
0
                                    }
12396
9.44k
                                }
12397
188k
                                break;
12398
193k
                            }
12399
188k
                        case XML_NAMESPACE_DECL:
12400
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12401
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12402
12403
0
                                if ((ns->prefix != NULL) && (name != NULL)
12404
0
                                    && (xmlStrEqual(ns->prefix, name)))
12405
0
        {
12406
0
            XP_TEST_HIT_NS
12407
0
                                }
12408
0
                            }
12409
0
                            break;
12410
0
                        default:
12411
0
                            break;
12412
4.25M
                    }
12413
4.25M
                    break;
12414
27.8M
      } /* switch(test) */
12415
27.8M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12416
12417
7.82M
  goto apply_predicates;
12418
12419
7.82M
axis_range_end: /* ----------------------------------------------------- */
12420
  /*
12421
  * We have a "/foo[n]", and position() = n was reached.
12422
  * Note that we can have as well "/foo/::parent::foo[1]", so
12423
  * a duplicate-aware merge is still needed.
12424
  * Merge with the result.
12425
  */
12426
252k
  if (outSeq == NULL) {
12427
6.98k
      outSeq = seq;
12428
6.98k
      seq = NULL;
12429
6.98k
  } else
12430
            /* TODO: Check memory error. */
12431
245k
      outSeq = mergeAndClear(outSeq, seq);
12432
  /*
12433
  * Break if only a true/false result was requested.
12434
  */
12435
252k
  if (toBool)
12436
0
      break;
12437
252k
  continue;
12438
12439
252k
first_hit: /* ---------------------------------------------------------- */
12440
  /*
12441
  * Break if only a true/false result was requested and
12442
  * no predicates existed and a node test succeeded.
12443
  */
12444
22.7k
  if (outSeq == NULL) {
12445
22.7k
      outSeq = seq;
12446
22.7k
      seq = NULL;
12447
22.7k
  } else
12448
            /* TODO: Check memory error. */
12449
0
      outSeq = mergeAndClear(outSeq, seq);
12450
22.7k
  break;
12451
12452
#ifdef DEBUG_STEP
12453
  if (seq != NULL)
12454
      nbMatches += seq->nodeNr;
12455
#endif
12456
12457
7.82M
apply_predicates: /* --------------------------------------------------- */
12458
7.82M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12459
0
      goto error;
12460
12461
        /*
12462
  * Apply predicates.
12463
  */
12464
7.82M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12465
      /*
12466
      * E.g. when we have a "/foo[some expression][n]".
12467
      */
12468
      /*
12469
      * QUESTION TODO: The old predicate evaluation took into
12470
      *  account location-sets.
12471
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12472
      *  Do we expect such a set here?
12473
      *  All what I learned now from the evaluation semantics
12474
      *  does not indicate that a location-set will be processed
12475
      *  here, so this looks OK.
12476
      */
12477
      /*
12478
      * Iterate over all predicates, starting with the outermost
12479
      * predicate.
12480
      * TODO: Problem: we cannot execute the inner predicates first
12481
      *  since we cannot go back *up* the operator tree!
12482
      *  Options we have:
12483
      *  1) Use of recursive functions (like is it currently done
12484
      *     via xmlXPathCompOpEval())
12485
      *  2) Add a predicate evaluation information stack to the
12486
      *     context struct
12487
      *  3) Change the way the operators are linked; we need a
12488
      *     "parent" field on xmlXPathStepOp
12489
      *
12490
      * For the moment, I'll try to solve this with a recursive
12491
      * function: xmlXPathCompOpEvalPredicate().
12492
      */
12493
216k
      if (hasPredicateRange != 0)
12494
1.43k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12495
1.43k
              hasNsNodes);
12496
215k
      else
12497
215k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12498
215k
              hasNsNodes);
12499
12500
216k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12501
940
    total = 0;
12502
940
    goto error;
12503
940
      }
12504
216k
        }
12505
12506
7.82M
        if (seq->nodeNr > 0) {
12507
      /*
12508
      * Add to result set.
12509
      */
12510
2.52M
      if (outSeq == NULL) {
12511
387k
    outSeq = seq;
12512
387k
    seq = NULL;
12513
2.13M
      } else {
12514
                /* TODO: Check memory error. */
12515
2.13M
    outSeq = mergeAndClear(outSeq, seq);
12516
2.13M
      }
12517
12518
2.52M
            if (toBool)
12519
0
                break;
12520
2.52M
  }
12521
7.82M
    }
12522
12523
702k
error:
12524
702k
    if ((obj->boolval) && (obj->user != NULL)) {
12525
  /*
12526
  * QUESTION TODO: What does this do and why?
12527
  * TODO: Do we have to do this also for the "error"
12528
  * cleanup further down?
12529
  */
12530
0
  ctxt->value->boolval = 1;
12531
0
  ctxt->value->user = obj->user;
12532
0
  obj->user = NULL;
12533
0
  obj->boolval = 0;
12534
0
    }
12535
702k
    xmlXPathReleaseObject(xpctxt, obj);
12536
12537
    /*
12538
    * Ensure we return at least an empty set.
12539
    */
12540
702k
    if (outSeq == NULL) {
12541
285k
  if ((seq != NULL) && (seq->nodeNr == 0))
12542
285k
      outSeq = seq;
12543
0
  else
12544
            /* TODO: Check memory error. */
12545
0
      outSeq = xmlXPathNodeSetCreate(NULL);
12546
285k
    }
12547
702k
    if ((seq != NULL) && (seq != outSeq)) {
12548
31.1k
   xmlXPathFreeNodeSet(seq);
12549
31.1k
    }
12550
    /*
12551
    * Hand over the result. Better to push the set also in
12552
    * case of errors.
12553
    */
12554
702k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12555
    /*
12556
    * Reset the context node.
12557
    */
12558
702k
    xpctxt->node = oldContextNode;
12559
    /*
12560
    * When traversing the namespace axis in "toBool" mode, it's
12561
    * possible that tmpNsList wasn't freed.
12562
    */
12563
702k
    if (xpctxt->tmpNsList != NULL) {
12564
0
        xmlFree(xpctxt->tmpNsList);
12565
0
        xpctxt->tmpNsList = NULL;
12566
0
    }
12567
12568
#ifdef DEBUG_STEP
12569
    xmlGenericError(xmlGenericErrorContext,
12570
  "\nExamined %d nodes, found %d nodes at that step\n",
12571
  total, nbMatches);
12572
#endif
12573
12574
702k
    return(total);
12575
702k
}
12576
12577
static int
12578
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12579
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12580
12581
/**
12582
 * xmlXPathCompOpEvalFirst:
12583
 * @ctxt:  the XPath parser context with the compiled expression
12584
 * @op:  an XPath compiled operation
12585
 * @first:  the first elem found so far
12586
 *
12587
 * Evaluate the Precompiled XPath operation searching only the first
12588
 * element in document order
12589
 *
12590
 * Returns the number of examined objects.
12591
 */
12592
static int
12593
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12594
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12595
8.97k
{
12596
8.97k
    int total = 0, cur;
12597
8.97k
    xmlXPathCompExprPtr comp;
12598
8.97k
    xmlXPathObjectPtr arg1, arg2;
12599
12600
8.97k
    CHECK_ERROR0;
12601
8.97k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12602
0
        return(0);
12603
8.97k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12604
8.97k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12605
8.97k
    ctxt->context->depth += 1;
12606
8.97k
    comp = ctxt->comp;
12607
8.97k
    switch (op->op) {
12608
0
        case XPATH_OP_END:
12609
0
            break;
12610
1.86k
        case XPATH_OP_UNION:
12611
1.86k
            total =
12612
1.86k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12613
1.86k
                                        first);
12614
1.86k
      CHECK_ERROR0;
12615
1.77k
            if ((ctxt->value != NULL)
12616
1.77k
                && (ctxt->value->type == XPATH_NODESET)
12617
1.77k
                && (ctxt->value->nodesetval != NULL)
12618
1.77k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12619
                /*
12620
                 * limit tree traversing to first node in the result
12621
                 */
12622
    /*
12623
    * OPTIMIZE TODO: This implicitly sorts
12624
    *  the result, even if not needed. E.g. if the argument
12625
    *  of the count() function, no sorting is needed.
12626
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12627
    *  already sorted?
12628
    */
12629
255
    if (ctxt->value->nodesetval->nodeNr > 1)
12630
20
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12631
255
                *first = ctxt->value->nodesetval->nodeTab[0];
12632
255
            }
12633
1.77k
            cur =
12634
1.77k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12635
1.77k
                                        first);
12636
1.77k
      CHECK_ERROR0;
12637
12638
1.38k
            arg2 = valuePop(ctxt);
12639
1.38k
            arg1 = valuePop(ctxt);
12640
1.38k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12641
1.38k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12642
27
          xmlXPathReleaseObject(ctxt->context, arg1);
12643
27
          xmlXPathReleaseObject(ctxt->context, arg2);
12644
27
                XP_ERROR0(XPATH_INVALID_TYPE);
12645
0
            }
12646
1.35k
            if ((ctxt->context->opLimit != 0) &&
12647
1.35k
                (((arg1->nodesetval != NULL) &&
12648
0
                  (xmlXPathCheckOpLimit(ctxt,
12649
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12650
0
                 ((arg2->nodesetval != NULL) &&
12651
0
                  (xmlXPathCheckOpLimit(ctxt,
12652
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12653
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12654
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12655
0
                break;
12656
0
            }
12657
12658
            /* TODO: Check memory error. */
12659
1.35k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12660
1.35k
                                                    arg2->nodesetval);
12661
1.35k
            valuePush(ctxt, arg1);
12662
1.35k
      xmlXPathReleaseObject(ctxt->context, arg2);
12663
            /* optimizer */
12664
1.35k
      if (total > cur)
12665
895
    xmlXPathCompSwap(op);
12666
1.35k
            total += cur;
12667
1.35k
            break;
12668
708
        case XPATH_OP_ROOT:
12669
708
            xmlXPathRoot(ctxt);
12670
708
            break;
12671
116
        case XPATH_OP_NODE:
12672
116
            if (op->ch1 != -1)
12673
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12674
116
      CHECK_ERROR0;
12675
116
            if (op->ch2 != -1)
12676
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12677
116
      CHECK_ERROR0;
12678
116
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12679
116
    ctxt->context->node));
12680
116
            break;
12681
3.12k
        case XPATH_OP_COLLECT:{
12682
3.12k
                if (op->ch1 == -1)
12683
0
                    break;
12684
12685
3.12k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12686
3.12k
    CHECK_ERROR0;
12687
12688
3.09k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12689
3.09k
                break;
12690
3.12k
            }
12691
27
        case XPATH_OP_VALUE:
12692
27
            valuePush(ctxt,
12693
27
                      xmlXPathCacheObjectCopy(ctxt->context,
12694
27
      (xmlXPathObjectPtr) op->value4));
12695
27
            break;
12696
2.48k
        case XPATH_OP_SORT:
12697
2.48k
            if (op->ch1 != -1)
12698
2.48k
                total +=
12699
2.48k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12700
2.48k
                                            first);
12701
2.48k
      CHECK_ERROR0;
12702
1.94k
            if ((ctxt->value != NULL)
12703
1.94k
                && (ctxt->value->type == XPATH_NODESET)
12704
1.94k
                && (ctxt->value->nodesetval != NULL)
12705
1.94k
    && (ctxt->value->nodesetval->nodeNr > 1))
12706
69
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12707
1.94k
            break;
12708
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12709
363
  case XPATH_OP_FILTER:
12710
363
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12711
363
            break;
12712
0
#endif
12713
281
        default:
12714
281
            total += xmlXPathCompOpEval(ctxt, op);
12715
281
            break;
12716
8.97k
    }
12717
12718
7.88k
    ctxt->context->depth -= 1;
12719
7.88k
    return(total);
12720
8.97k
}
12721
12722
/**
12723
 * xmlXPathCompOpEvalLast:
12724
 * @ctxt:  the XPath parser context with the compiled expression
12725
 * @op:  an XPath compiled operation
12726
 * @last:  the last elem found so far
12727
 *
12728
 * Evaluate the Precompiled XPath operation searching only the last
12729
 * element in document order
12730
 *
12731
 * Returns the number of nodes traversed
12732
 */
12733
static int
12734
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12735
                       xmlNodePtr * last)
12736
0
{
12737
0
    int total = 0, cur;
12738
0
    xmlXPathCompExprPtr comp;
12739
0
    xmlXPathObjectPtr arg1, arg2;
12740
12741
0
    CHECK_ERROR0;
12742
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12743
0
        return(0);
12744
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12745
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12746
0
    ctxt->context->depth += 1;
12747
0
    comp = ctxt->comp;
12748
0
    switch (op->op) {
12749
0
        case XPATH_OP_END:
12750
0
            break;
12751
0
        case XPATH_OP_UNION:
12752
0
            total =
12753
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12754
0
      CHECK_ERROR0;
12755
0
            if ((ctxt->value != NULL)
12756
0
                && (ctxt->value->type == XPATH_NODESET)
12757
0
                && (ctxt->value->nodesetval != NULL)
12758
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12759
                /*
12760
                 * limit tree traversing to first node in the result
12761
                 */
12762
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12763
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12764
0
                *last =
12765
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12766
0
                                                     nodesetval->nodeNr -
12767
0
                                                     1];
12768
0
            }
12769
0
            cur =
12770
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12771
0
      CHECK_ERROR0;
12772
0
            if ((ctxt->value != NULL)
12773
0
                && (ctxt->value->type == XPATH_NODESET)
12774
0
                && (ctxt->value->nodesetval != NULL)
12775
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12776
0
            }
12777
12778
0
            arg2 = valuePop(ctxt);
12779
0
            arg1 = valuePop(ctxt);
12780
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12781
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12782
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12783
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12784
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12785
0
            }
12786
0
            if ((ctxt->context->opLimit != 0) &&
12787
0
                (((arg1->nodesetval != NULL) &&
12788
0
                  (xmlXPathCheckOpLimit(ctxt,
12789
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12790
0
                 ((arg2->nodesetval != NULL) &&
12791
0
                  (xmlXPathCheckOpLimit(ctxt,
12792
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12793
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12794
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12795
0
                break;
12796
0
            }
12797
12798
            /* TODO: Check memory error. */
12799
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12800
0
                                                    arg2->nodesetval);
12801
0
            valuePush(ctxt, arg1);
12802
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12803
            /* optimizer */
12804
0
      if (total > cur)
12805
0
    xmlXPathCompSwap(op);
12806
0
            total += cur;
12807
0
            break;
12808
0
        case XPATH_OP_ROOT:
12809
0
            xmlXPathRoot(ctxt);
12810
0
            break;
12811
0
        case XPATH_OP_NODE:
12812
0
            if (op->ch1 != -1)
12813
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12814
0
      CHECK_ERROR0;
12815
0
            if (op->ch2 != -1)
12816
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12817
0
      CHECK_ERROR0;
12818
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12819
0
    ctxt->context->node));
12820
0
            break;
12821
0
        case XPATH_OP_COLLECT:{
12822
0
                if (op->ch1 == -1)
12823
0
                    break;
12824
12825
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12826
0
    CHECK_ERROR0;
12827
12828
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12829
0
                break;
12830
0
            }
12831
0
        case XPATH_OP_VALUE:
12832
0
            valuePush(ctxt,
12833
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12834
0
      (xmlXPathObjectPtr) op->value4));
12835
0
            break;
12836
0
        case XPATH_OP_SORT:
12837
0
            if (op->ch1 != -1)
12838
0
                total +=
12839
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12840
0
                                           last);
12841
0
      CHECK_ERROR0;
12842
0
            if ((ctxt->value != NULL)
12843
0
                && (ctxt->value->type == XPATH_NODESET)
12844
0
                && (ctxt->value->nodesetval != NULL)
12845
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12846
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12847
0
            break;
12848
0
        default:
12849
0
            total += xmlXPathCompOpEval(ctxt, op);
12850
0
            break;
12851
0
    }
12852
12853
0
    ctxt->context->depth -= 1;
12854
0
    return (total);
12855
0
}
12856
12857
#ifdef XP_OPTIMIZED_FILTER_FIRST
12858
static int
12859
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12860
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12861
363
{
12862
363
    int total = 0;
12863
363
    xmlXPathCompExprPtr comp;
12864
363
    xmlNodeSetPtr set;
12865
12866
363
    CHECK_ERROR0;
12867
363
    comp = ctxt->comp;
12868
    /*
12869
    * Optimization for ()[last()] selection i.e. the last elem
12870
    */
12871
363
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12872
363
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12873
363
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12874
123
  int f = comp->steps[op->ch2].ch1;
12875
12876
123
  if ((f != -1) &&
12877
123
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12878
123
      (comp->steps[f].value5 == NULL) &&
12879
123
      (comp->steps[f].value == 0) &&
12880
123
      (comp->steps[f].value4 != NULL) &&
12881
123
      (xmlStrEqual
12882
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
12883
0
      xmlNodePtr last = NULL;
12884
12885
0
      total +=
12886
0
    xmlXPathCompOpEvalLast(ctxt,
12887
0
        &comp->steps[op->ch1],
12888
0
        &last);
12889
0
      CHECK_ERROR0;
12890
      /*
12891
      * The nodeset should be in document order,
12892
      * Keep only the last value
12893
      */
12894
0
      if ((ctxt->value != NULL) &&
12895
0
    (ctxt->value->type == XPATH_NODESET) &&
12896
0
    (ctxt->value->nodesetval != NULL) &&
12897
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12898
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12899
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12900
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12901
0
      }
12902
0
      return (total);
12903
0
  }
12904
123
    }
12905
12906
363
    if (op->ch1 != -1)
12907
363
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12908
363
    CHECK_ERROR0;
12909
223
    if (op->ch2 == -1)
12910
0
  return (total);
12911
223
    if (ctxt->value == NULL)
12912
0
  return (total);
12913
12914
#ifdef LIBXML_XPTR_LOCS_ENABLED
12915
    /*
12916
    * Hum are we filtering the result of an XPointer expression
12917
    */
12918
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12919
        xmlLocationSetPtr locset = ctxt->value->user;
12920
12921
        if (locset != NULL) {
12922
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12923
            if (locset->locNr > 0)
12924
                *first = (xmlNodePtr) locset->locTab[0]->user;
12925
        }
12926
12927
  return (total);
12928
    }
12929
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12930
12931
223
    CHECK_TYPE0(XPATH_NODESET);
12932
196
    set = ctxt->value->nodesetval;
12933
196
    if (set != NULL) {
12934
159
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12935
159
        if (set->nodeNr > 0)
12936
97
            *first = set->nodeTab[0];
12937
159
    }
12938
12939
196
    return (total);
12940
223
}
12941
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12942
12943
/**
12944
 * xmlXPathCompOpEval:
12945
 * @ctxt:  the XPath parser context with the compiled expression
12946
 * @op:  an XPath compiled operation
12947
 *
12948
 * Evaluate the Precompiled XPath operation
12949
 * Returns the number of nodes traversed
12950
 */
12951
static int
12952
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12953
2.72M
{
12954
2.72M
    int total = 0;
12955
2.72M
    int equal, ret;
12956
2.72M
    xmlXPathCompExprPtr comp;
12957
2.72M
    xmlXPathObjectPtr arg1, arg2;
12958
12959
2.72M
    CHECK_ERROR0;
12960
2.72M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12961
0
        return(0);
12962
2.72M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12963
2.72M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12964
2.72M
    ctxt->context->depth += 1;
12965
2.72M
    comp = ctxt->comp;
12966
2.72M
    switch (op->op) {
12967
0
        case XPATH_OP_END:
12968
0
            break;
12969
1.76k
        case XPATH_OP_AND:
12970
1.76k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12971
1.76k
      CHECK_ERROR0;
12972
1.56k
            xmlXPathBooleanFunction(ctxt, 1);
12973
1.56k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12974
830
                break;
12975
731
            arg2 = valuePop(ctxt);
12976
731
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12977
731
      if (ctxt->error) {
12978
234
    xmlXPathFreeObject(arg2);
12979
234
    break;
12980
234
      }
12981
497
            xmlXPathBooleanFunction(ctxt, 1);
12982
497
            if (ctxt->value != NULL)
12983
497
                ctxt->value->boolval &= arg2->boolval;
12984
497
      xmlXPathReleaseObject(ctxt->context, arg2);
12985
497
            break;
12986
9.49k
        case XPATH_OP_OR:
12987
9.49k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12988
9.49k
      CHECK_ERROR0;
12989
9.16k
            xmlXPathBooleanFunction(ctxt, 1);
12990
9.16k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12991
872
                break;
12992
8.29k
            arg2 = valuePop(ctxt);
12993
8.29k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12994
8.29k
      if (ctxt->error) {
12995
2.79k
    xmlXPathFreeObject(arg2);
12996
2.79k
    break;
12997
2.79k
      }
12998
5.50k
            xmlXPathBooleanFunction(ctxt, 1);
12999
5.50k
            if (ctxt->value != NULL)
13000
5.50k
                ctxt->value->boolval |= arg2->boolval;
13001
5.50k
      xmlXPathReleaseObject(ctxt->context, arg2);
13002
5.50k
            break;
13003
117k
        case XPATH_OP_EQUAL:
13004
117k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13005
117k
      CHECK_ERROR0;
13006
116k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13007
116k
      CHECK_ERROR0;
13008
112k
      if (op->value)
13009
67.8k
    equal = xmlXPathEqualValues(ctxt);
13010
44.3k
      else
13011
44.3k
    equal = xmlXPathNotEqualValues(ctxt);
13012
112k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13013
112k
            break;
13014
27.7k
        case XPATH_OP_CMP:
13015
27.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13016
27.7k
      CHECK_ERROR0;
13017
26.9k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13018
26.9k
      CHECK_ERROR0;
13019
26.1k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13020
26.1k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13021
26.1k
            break;
13022
121k
        case XPATH_OP_PLUS:
13023
121k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
121k
      CHECK_ERROR0;
13025
120k
            if (op->ch2 != -1) {
13026
64.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13027
64.1k
      }
13028
120k
      CHECK_ERROR0;
13029
117k
            if (op->value == 0)
13030
35.3k
                xmlXPathSubValues(ctxt);
13031
82.1k
            else if (op->value == 1)
13032
25.9k
                xmlXPathAddValues(ctxt);
13033
56.1k
            else if (op->value == 2)
13034
33.3k
                xmlXPathValueFlipSign(ctxt);
13035
22.7k
            else if (op->value == 3) {
13036
22.7k
                CAST_TO_NUMBER;
13037
22.7k
                CHECK_TYPE0(XPATH_NUMBER);
13038
22.7k
            }
13039
117k
            break;
13040
287k
        case XPATH_OP_MULT:
13041
287k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13042
287k
      CHECK_ERROR0;
13043
253k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13044
253k
      CHECK_ERROR0;
13045
252k
            if (op->value == 0)
13046
251k
                xmlXPathMultValues(ctxt);
13047
716
            else if (op->value == 1)
13048
297
                xmlXPathDivValues(ctxt);
13049
419
            else if (op->value == 2)
13050
419
                xmlXPathModValues(ctxt);
13051
252k
            break;
13052
79.6k
        case XPATH_OP_UNION:
13053
79.6k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13054
79.6k
      CHECK_ERROR0;
13055
77.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13056
77.3k
      CHECK_ERROR0;
13057
13058
75.3k
            arg2 = valuePop(ctxt);
13059
75.3k
            arg1 = valuePop(ctxt);
13060
75.3k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13061
75.3k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13062
1.32k
          xmlXPathReleaseObject(ctxt->context, arg1);
13063
1.32k
          xmlXPathReleaseObject(ctxt->context, arg2);
13064
1.32k
                XP_ERROR0(XPATH_INVALID_TYPE);
13065
0
            }
13066
73.9k
            if ((ctxt->context->opLimit != 0) &&
13067
73.9k
                (((arg1->nodesetval != NULL) &&
13068
0
                  (xmlXPathCheckOpLimit(ctxt,
13069
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
13070
0
                 ((arg2->nodesetval != NULL) &&
13071
0
                  (xmlXPathCheckOpLimit(ctxt,
13072
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
13073
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13074
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13075
0
                break;
13076
0
            }
13077
13078
73.9k
      if ((arg1->nodesetval == NULL) ||
13079
73.9k
    ((arg2->nodesetval != NULL) &&
13080
70.9k
     (arg2->nodesetval->nodeNr != 0)))
13081
33.8k
      {
13082
                /* TODO: Check memory error. */
13083
33.8k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13084
33.8k
              arg2->nodesetval);
13085
33.8k
      }
13086
13087
73.9k
            valuePush(ctxt, arg1);
13088
73.9k
      xmlXPathReleaseObject(ctxt->context, arg2);
13089
73.9k
            break;
13090
237k
        case XPATH_OP_ROOT:
13091
237k
            xmlXPathRoot(ctxt);
13092
237k
            break;
13093
838k
        case XPATH_OP_NODE:
13094
838k
            if (op->ch1 != -1)
13095
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13096
838k
      CHECK_ERROR0;
13097
838k
            if (op->ch2 != -1)
13098
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13099
838k
      CHECK_ERROR0;
13100
838k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13101
838k
    ctxt->context->node));
13102
838k
            break;
13103
664k
        case XPATH_OP_COLLECT:{
13104
664k
                if (op->ch1 == -1)
13105
0
                    break;
13106
13107
664k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13108
664k
    CHECK_ERROR0;
13109
13110
662k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13111
662k
                break;
13112
664k
            }
13113
164k
        case XPATH_OP_VALUE:
13114
164k
            valuePush(ctxt,
13115
164k
                      xmlXPathCacheObjectCopy(ctxt->context,
13116
164k
      (xmlXPathObjectPtr) op->value4));
13117
164k
            break;
13118
2.64k
        case XPATH_OP_VARIABLE:{
13119
2.64k
    xmlXPathObjectPtr val;
13120
13121
2.64k
                if (op->ch1 != -1)
13122
0
                    total +=
13123
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13124
2.64k
                if (op->value5 == NULL) {
13125
2.33k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13126
2.33k
        if (val == NULL)
13127
2.33k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13128
0
                    valuePush(ctxt, val);
13129
307
    } else {
13130
307
                    const xmlChar *URI;
13131
13132
307
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13133
307
                    if (URI == NULL) {
13134
307
                        xmlGenericError(xmlGenericErrorContext,
13135
307
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13136
307
                                    (char *) op->value4, (char *)op->value5);
13137
307
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13138
307
                        break;
13139
307
                    }
13140
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13141
0
                                                       op->value4, URI);
13142
0
        if (val == NULL)
13143
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13144
0
                    valuePush(ctxt, val);
13145
0
                }
13146
0
                break;
13147
2.64k
            }
13148
4.39k
        case XPATH_OP_FUNCTION:{
13149
4.39k
                xmlXPathFunction func;
13150
4.39k
                const xmlChar *oldFunc, *oldFuncURI;
13151
4.39k
    int i;
13152
4.39k
                int frame;
13153
13154
4.39k
                frame = xmlXPathSetFrame(ctxt);
13155
4.39k
                if (op->ch1 != -1) {
13156
2.36k
                    total +=
13157
2.36k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13158
2.36k
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13159
662
                        xmlXPathPopFrame(ctxt, frame);
13160
662
                        break;
13161
662
                    }
13162
2.36k
                }
13163
3.73k
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13164
0
        xmlGenericError(xmlGenericErrorContext,
13165
0
          "xmlXPathCompOpEval: parameter error\n");
13166
0
        ctxt->error = XPATH_INVALID_OPERAND;
13167
0
                    xmlXPathPopFrame(ctxt, frame);
13168
0
        break;
13169
0
    }
13170
6.14k
    for (i = 0; i < op->value; i++) {
13171
2.41k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13172
0
      xmlGenericError(xmlGenericErrorContext,
13173
0
        "xmlXPathCompOpEval: parameter error\n");
13174
0
      ctxt->error = XPATH_INVALID_OPERAND;
13175
0
                        xmlXPathPopFrame(ctxt, frame);
13176
0
      break;
13177
0
        }
13178
2.41k
                }
13179
3.73k
                if (op->cache != NULL)
13180
0
                    func = op->cache;
13181
3.73k
                else {
13182
3.73k
                    const xmlChar *URI = NULL;
13183
13184
3.73k
                    if (op->value5 == NULL)
13185
3.32k
                        func =
13186
3.32k
                            xmlXPathFunctionLookup(ctxt->context,
13187
3.32k
                                                   op->value4);
13188
404
                    else {
13189
404
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13190
404
                        if (URI == NULL) {
13191
404
                            xmlGenericError(xmlGenericErrorContext,
13192
404
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13193
404
                                    (char *)op->value4, (char *)op->value5);
13194
404
                            xmlXPathPopFrame(ctxt, frame);
13195
404
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13196
404
                            break;
13197
404
                        }
13198
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13199
0
                                                        op->value4, URI);
13200
0
                    }
13201
3.32k
                    if (func == NULL) {
13202
3.32k
                        xmlGenericError(xmlGenericErrorContext,
13203
3.32k
                                "xmlXPathCompOpEval: function %s not found\n",
13204
3.32k
                                        (char *)op->value4);
13205
3.32k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13206
0
                    }
13207
0
                    op->cache = func;
13208
0
                    op->cacheURI = (void *) URI;
13209
0
                }
13210
0
                oldFunc = ctxt->context->function;
13211
0
                oldFuncURI = ctxt->context->functionURI;
13212
0
                ctxt->context->function = op->value4;
13213
0
                ctxt->context->functionURI = op->cacheURI;
13214
0
                func(ctxt, op->value);
13215
0
                ctxt->context->function = oldFunc;
13216
0
                ctxt->context->functionURI = oldFuncURI;
13217
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13218
0
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13219
0
                    XP_ERROR0(XPATH_STACK_ERROR);
13220
0
                xmlXPathPopFrame(ctxt, frame);
13221
0
                break;
13222
0
            }
13223
3.55k
        case XPATH_OP_ARG:
13224
3.55k
            if (op->ch1 != -1) {
13225
1.19k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13226
1.19k
          CHECK_ERROR0;
13227
1.19k
            }
13228
3.50k
            if (op->ch2 != -1) {
13229
3.50k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13230
3.50k
          CHECK_ERROR0;
13231
3.50k
      }
13232
2.84k
            break;
13233
2.84k
        case XPATH_OP_PREDICATE:
13234
6.50k
        case XPATH_OP_FILTER:{
13235
6.50k
                xmlNodeSetPtr set;
13236
13237
                /*
13238
                 * Optimization for ()[1] selection i.e. the first elem
13239
                 */
13240
6.50k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13241
6.50k
#ifdef XP_OPTIMIZED_FILTER_FIRST
13242
        /*
13243
        * FILTER TODO: Can we assume that the inner processing
13244
        *  will result in an ordered list if we have an
13245
        *  XPATH_OP_FILTER?
13246
        *  What about an additional field or flag on
13247
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13248
        *  to assume anything, so it would be more robust and
13249
        *  easier to optimize.
13250
        */
13251
6.50k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13252
6.50k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13253
#else
13254
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13255
#endif
13256
6.50k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13257
2.94k
                    xmlXPathObjectPtr val;
13258
13259
2.94k
                    val = comp->steps[op->ch2].value4;
13260
2.94k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13261
2.94k
                        (val->floatval == 1.0)) {
13262
2.83k
                        xmlNodePtr first = NULL;
13263
13264
2.83k
                        total +=
13265
2.83k
                            xmlXPathCompOpEvalFirst(ctxt,
13266
2.83k
                                                    &comp->steps[op->ch1],
13267
2.83k
                                                    &first);
13268
2.83k
      CHECK_ERROR0;
13269
                        /*
13270
                         * The nodeset should be in document order,
13271
                         * Keep only the first value
13272
                         */
13273
2.12k
                        if ((ctxt->value != NULL) &&
13274
2.12k
                            (ctxt->value->type == XPATH_NODESET) &&
13275
2.12k
                            (ctxt->value->nodesetval != NULL) &&
13276
2.12k
                            (ctxt->value->nodesetval->nodeNr > 1))
13277
69
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13278
69
                                                        1, 1);
13279
2.12k
                        break;
13280
2.83k
                    }
13281
2.94k
                }
13282
                /*
13283
                 * Optimization for ()[last()] selection i.e. the last elem
13284
                 */
13285
3.66k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13286
3.66k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13287
3.66k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13288
943
                    int f = comp->steps[op->ch2].ch1;
13289
13290
943
                    if ((f != -1) &&
13291
943
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13292
943
                        (comp->steps[f].value5 == NULL) &&
13293
943
                        (comp->steps[f].value == 0) &&
13294
943
                        (comp->steps[f].value4 != NULL) &&
13295
943
                        (xmlStrEqual
13296
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13297
0
                        xmlNodePtr last = NULL;
13298
13299
0
                        total +=
13300
0
                            xmlXPathCompOpEvalLast(ctxt,
13301
0
                                                   &comp->steps[op->ch1],
13302
0
                                                   &last);
13303
0
      CHECK_ERROR0;
13304
                        /*
13305
                         * The nodeset should be in document order,
13306
                         * Keep only the last value
13307
                         */
13308
0
                        if ((ctxt->value != NULL) &&
13309
0
                            (ctxt->value->type == XPATH_NODESET) &&
13310
0
                            (ctxt->value->nodesetval != NULL) &&
13311
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13312
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13313
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13314
0
                        break;
13315
0
                    }
13316
943
                }
13317
    /*
13318
    * Process inner predicates first.
13319
    * Example "index[parent::book][1]":
13320
    * ...
13321
    *   PREDICATE   <-- we are here "[1]"
13322
    *     PREDICATE <-- process "[parent::book]" first
13323
    *       SORT
13324
    *         COLLECT  'parent' 'name' 'node' book
13325
    *           NODE
13326
    *     ELEM Object is a number : 1
13327
    */
13328
3.66k
                if (op->ch1 != -1)
13329
3.66k
                    total +=
13330
3.66k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13331
3.66k
    CHECK_ERROR0;
13332
1.32k
                if (op->ch2 == -1)
13333
0
                    break;
13334
1.32k
                if (ctxt->value == NULL)
13335
0
                    break;
13336
13337
#ifdef LIBXML_XPTR_LOCS_ENABLED
13338
                /*
13339
                 * Hum are we filtering the result of an XPointer expression
13340
                 */
13341
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13342
                    xmlLocationSetPtr locset = ctxt->value->user;
13343
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13344
                                              1, locset->locNr);
13345
                    break;
13346
                }
13347
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13348
13349
1.32k
                CHECK_TYPE0(XPATH_NODESET);
13350
870
                set = ctxt->value->nodesetval;
13351
870
                if (set != NULL)
13352
748
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13353
748
                                          1, set->nodeNr, 1);
13354
870
                break;
13355
1.32k
            }
13356
153k
        case XPATH_OP_SORT:
13357
153k
            if (op->ch1 != -1)
13358
153k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13359
153k
      CHECK_ERROR0;
13360
137k
            if ((ctxt->value != NULL) &&
13361
137k
                (ctxt->value->type == XPATH_NODESET) &&
13362
137k
                (ctxt->value->nodesetval != NULL) &&
13363
137k
    (ctxt->value->nodesetval->nodeNr > 1))
13364
28.9k
      {
13365
28.9k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13366
28.9k
      }
13367
137k
            break;
13368
#ifdef LIBXML_XPTR_LOCS_ENABLED
13369
        case XPATH_OP_RANGETO:{
13370
                xmlXPathObjectPtr range;
13371
                xmlXPathObjectPtr res, obj;
13372
                xmlXPathObjectPtr tmp;
13373
                xmlLocationSetPtr newlocset = NULL;
13374
        xmlLocationSetPtr oldlocset;
13375
                xmlNodeSetPtr oldset;
13376
                xmlNodePtr oldnode = ctxt->context->node;
13377
                int oldcs = ctxt->context->contextSize;
13378
                int oldpp = ctxt->context->proximityPosition;
13379
                int i, j;
13380
13381
                if (op->ch1 != -1) {
13382
                    total +=
13383
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13384
                    CHECK_ERROR0;
13385
                }
13386
                if (ctxt->value == NULL) {
13387
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13388
                }
13389
                if (op->ch2 == -1)
13390
                    break;
13391
13392
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13393
                    /*
13394
                     * Extract the old locset, and then evaluate the result of the
13395
                     * expression for all the element in the locset. use it to grow
13396
                     * up a new locset.
13397
                     */
13398
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13399
13400
                    if ((ctxt->value->user == NULL) ||
13401
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13402
                        break;
13403
13404
                    obj = valuePop(ctxt);
13405
                    oldlocset = obj->user;
13406
13407
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13408
13409
                    for (i = 0; i < oldlocset->locNr; i++) {
13410
                        /*
13411
                         * Run the evaluation with a node list made of a
13412
                         * single item in the nodelocset.
13413
                         */
13414
                        ctxt->context->node = oldlocset->locTab[i]->user;
13415
                        ctxt->context->contextSize = oldlocset->locNr;
13416
                        ctxt->context->proximityPosition = i + 1;
13417
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13418
          ctxt->context->node);
13419
                        valuePush(ctxt, tmp);
13420
13421
                        if (op->ch2 != -1)
13422
                            total +=
13423
                                xmlXPathCompOpEval(ctxt,
13424
                                                   &comp->steps[op->ch2]);
13425
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13426
                            xmlXPtrFreeLocationSet(newlocset);
13427
                            goto rangeto_error;
13428
      }
13429
13430
                        res = valuePop(ctxt);
13431
      if (res->type == XPATH_LOCATIONSET) {
13432
          xmlLocationSetPtr rloc =
13433
              (xmlLocationSetPtr)res->user;
13434
          for (j=0; j<rloc->locNr; j++) {
13435
              range = xmlXPtrNewRange(
13436
          oldlocset->locTab[i]->user,
13437
          oldlocset->locTab[i]->index,
13438
          rloc->locTab[j]->user2,
13439
          rloc->locTab[j]->index2);
13440
        if (range != NULL) {
13441
            xmlXPtrLocationSetAdd(newlocset, range);
13442
        }
13443
          }
13444
      } else {
13445
          range = xmlXPtrNewRangeNodeObject(
13446
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13447
                            if (range != NULL) {
13448
                                xmlXPtrLocationSetAdd(newlocset,range);
13449
          }
13450
                        }
13451
13452
                        /*
13453
                         * Cleanup
13454
                         */
13455
                        if (res != NULL) {
13456
          xmlXPathReleaseObject(ctxt->context, res);
13457
      }
13458
                        if (ctxt->value == tmp) {
13459
                            res = valuePop(ctxt);
13460
          xmlXPathReleaseObject(ctxt->context, res);
13461
                        }
13462
                    }
13463
    } else {  /* Not a location set */
13464
                    CHECK_TYPE0(XPATH_NODESET);
13465
                    obj = valuePop(ctxt);
13466
                    oldset = obj->nodesetval;
13467
13468
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13469
13470
                    if (oldset != NULL) {
13471
                        for (i = 0; i < oldset->nodeNr; i++) {
13472
                            /*
13473
                             * Run the evaluation with a node list made of a single item
13474
                             * in the nodeset.
13475
                             */
13476
                            ctxt->context->node = oldset->nodeTab[i];
13477
          /*
13478
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13479
          */
13480
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13481
        ctxt->context->node);
13482
                            valuePush(ctxt, tmp);
13483
13484
                            if (op->ch2 != -1)
13485
                                total +=
13486
                                    xmlXPathCompOpEval(ctxt,
13487
                                                   &comp->steps[op->ch2]);
13488
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13489
                                xmlXPtrFreeLocationSet(newlocset);
13490
                                goto rangeto_error;
13491
          }
13492
13493
                            res = valuePop(ctxt);
13494
                            range =
13495
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13496
                                                      res);
13497
                            if (range != NULL) {
13498
                                xmlXPtrLocationSetAdd(newlocset, range);
13499
                            }
13500
13501
                            /*
13502
                             * Cleanup
13503
                             */
13504
                            if (res != NULL) {
13505
        xmlXPathReleaseObject(ctxt->context, res);
13506
          }
13507
                            if (ctxt->value == tmp) {
13508
                                res = valuePop(ctxt);
13509
        xmlXPathReleaseObject(ctxt->context, res);
13510
                            }
13511
                        }
13512
                    }
13513
                }
13514
13515
                /*
13516
                 * The result is used as the new evaluation set.
13517
                 */
13518
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13519
rangeto_error:
13520
    xmlXPathReleaseObject(ctxt->context, obj);
13521
                ctxt->context->node = oldnode;
13522
                ctxt->context->contextSize = oldcs;
13523
                ctxt->context->proximityPosition = oldpp;
13524
                break;
13525
            }
13526
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13527
0
        default:
13528
0
            xmlGenericError(xmlGenericErrorContext,
13529
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13530
0
            ctxt->error = XPATH_INVALID_OPERAND;
13531
0
            break;
13532
2.72M
    }
13533
13534
2.64M
    ctxt->context->depth -= 1;
13535
2.64M
    return (total);
13536
2.72M
}
13537
13538
/**
13539
 * xmlXPathCompOpEvalToBoolean:
13540
 * @ctxt:  the XPath parser context
13541
 *
13542
 * Evaluates if the expression evaluates to true.
13543
 *
13544
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13545
 */
13546
static int
13547
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13548
          xmlXPathStepOpPtr op,
13549
          int isPredicate)
13550
574k
{
13551
574k
    xmlXPathObjectPtr resObj = NULL;
13552
13553
575k
start:
13554
575k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13555
0
        return(0);
13556
    /* comp = ctxt->comp; */
13557
575k
    switch (op->op) {
13558
0
        case XPATH_OP_END:
13559
0
            return (0);
13560
8.99k
  case XPATH_OP_VALUE:
13561
8.99k
      resObj = (xmlXPathObjectPtr) op->value4;
13562
8.99k
      if (isPredicate)
13563
8.99k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13564
0
      return(xmlXPathCastToBoolean(resObj));
13565
906
  case XPATH_OP_SORT:
13566
      /*
13567
      * We don't need sorting for boolean results. Skip this one.
13568
      */
13569
906
            if (op->ch1 != -1) {
13570
906
    op = &ctxt->comp->steps[op->ch1];
13571
906
    goto start;
13572
906
      }
13573
0
      return(0);
13574
88.4k
  case XPATH_OP_COLLECT:
13575
88.4k
      if (op->ch1 == -1)
13576
0
    return(0);
13577
13578
88.4k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13579
88.4k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13580
223
    return(-1);
13581
13582
88.1k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13583
88.1k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13584
388
    return(-1);
13585
13586
87.8k
      resObj = valuePop(ctxt);
13587
87.8k
      if (resObj == NULL)
13588
0
    return(-1);
13589
87.8k
      break;
13590
477k
  default:
13591
      /*
13592
      * Fallback to call xmlXPathCompOpEval().
13593
      */
13594
477k
      xmlXPathCompOpEval(ctxt, op);
13595
477k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13596
370
    return(-1);
13597
13598
477k
      resObj = valuePop(ctxt);
13599
477k
      if (resObj == NULL)
13600
0
    return(-1);
13601
477k
      break;
13602
575k
    }
13603
13604
564k
    if (resObj) {
13605
564k
  int res;
13606
13607
564k
  if (resObj->type == XPATH_BOOLEAN) {
13608
69.2k
      res = resObj->boolval;
13609
495k
  } else if (isPredicate) {
13610
      /*
13611
      * For predicates a result of type "number" is handled
13612
      * differently:
13613
      * SPEC XPath 1.0:
13614
      * "If the result is a number, the result will be converted
13615
      *  to true if the number is equal to the context position
13616
      *  and will be converted to false otherwise;"
13617
      */
13618
495k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13619
495k
  } else {
13620
0
      res = xmlXPathCastToBoolean(resObj);
13621
0
  }
13622
564k
  xmlXPathReleaseObject(ctxt->context, resObj);
13623
564k
  return(res);
13624
564k
    }
13625
13626
0
    return(0);
13627
564k
}
13628
13629
#ifdef XPATH_STREAMING
13630
/**
13631
 * xmlXPathRunStreamEval:
13632
 * @ctxt:  the XPath parser context with the compiled expression
13633
 *
13634
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13635
 */
13636
static int
13637
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13638
          xmlXPathObjectPtr *resultSeq, int toBool)
13639
44.5k
{
13640
44.5k
    int max_depth, min_depth;
13641
44.5k
    int from_root;
13642
44.5k
    int ret, depth;
13643
44.5k
    int eval_all_nodes;
13644
44.5k
    xmlNodePtr cur = NULL, limit = NULL;
13645
44.5k
    xmlStreamCtxtPtr patstream = NULL;
13646
13647
44.5k
    int nb_nodes = 0;
13648
13649
44.5k
    if ((ctxt == NULL) || (comp == NULL))
13650
0
        return(-1);
13651
44.5k
    max_depth = xmlPatternMaxDepth(comp);
13652
44.5k
    if (max_depth == -1)
13653
0
        return(-1);
13654
44.5k
    if (max_depth == -2)
13655
35.1k
        max_depth = 10000;
13656
44.5k
    min_depth = xmlPatternMinDepth(comp);
13657
44.5k
    if (min_depth == -1)
13658
0
        return(-1);
13659
44.5k
    from_root = xmlPatternFromRoot(comp);
13660
44.5k
    if (from_root < 0)
13661
0
        return(-1);
13662
#if 0
13663
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13664
#endif
13665
13666
44.5k
    if (! toBool) {
13667
44.5k
  if (resultSeq == NULL)
13668
0
      return(-1);
13669
44.5k
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13670
44.5k
  if (*resultSeq == NULL)
13671
0
      return(-1);
13672
44.5k
    }
13673
13674
    /*
13675
     * handle the special cases of "/" amd "." being matched
13676
     */
13677
44.5k
    if (min_depth == 0) {
13678
2.39k
  if (from_root) {
13679
      /* Select "/" */
13680
0
      if (toBool)
13681
0
    return(1);
13682
            /* TODO: Check memory error. */
13683
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13684
0
                         (xmlNodePtr) ctxt->doc);
13685
2.39k
  } else {
13686
      /* Select "self::node()" */
13687
2.39k
      if (toBool)
13688
0
    return(1);
13689
            /* TODO: Check memory error. */
13690
2.39k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13691
2.39k
  }
13692
2.39k
    }
13693
44.5k
    if (max_depth == 0) {
13694
514
  return(0);
13695
514
    }
13696
13697
44.0k
    if (from_root) {
13698
31.8k
        cur = (xmlNodePtr)ctxt->doc;
13699
31.8k
    } else if (ctxt->node != NULL) {
13700
12.1k
        switch (ctxt->node->type) {
13701
0
            case XML_ELEMENT_NODE:
13702
12.1k
            case XML_DOCUMENT_NODE:
13703
12.1k
            case XML_DOCUMENT_FRAG_NODE:
13704
12.1k
            case XML_HTML_DOCUMENT_NODE:
13705
12.1k
          cur = ctxt->node;
13706
12.1k
    break;
13707
0
            case XML_ATTRIBUTE_NODE:
13708
0
            case XML_TEXT_NODE:
13709
0
            case XML_CDATA_SECTION_NODE:
13710
0
            case XML_ENTITY_REF_NODE:
13711
0
            case XML_ENTITY_NODE:
13712
0
            case XML_PI_NODE:
13713
0
            case XML_COMMENT_NODE:
13714
0
            case XML_NOTATION_NODE:
13715
0
            case XML_DTD_NODE:
13716
0
            case XML_DOCUMENT_TYPE_NODE:
13717
0
            case XML_ELEMENT_DECL:
13718
0
            case XML_ATTRIBUTE_DECL:
13719
0
            case XML_ENTITY_DECL:
13720
0
            case XML_NAMESPACE_DECL:
13721
0
            case XML_XINCLUDE_START:
13722
0
            case XML_XINCLUDE_END:
13723
0
    break;
13724
12.1k
  }
13725
12.1k
  limit = cur;
13726
12.1k
    }
13727
44.0k
    if (cur == NULL) {
13728
0
        return(0);
13729
0
    }
13730
13731
44.0k
    patstream = xmlPatternGetStreamCtxt(comp);
13732
44.0k
    if (patstream == NULL) {
13733
  /*
13734
  * QUESTION TODO: Is this an error?
13735
  */
13736
0
  return(0);
13737
0
    }
13738
13739
44.0k
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13740
13741
44.0k
    if (from_root) {
13742
31.8k
  ret = xmlStreamPush(patstream, NULL, NULL);
13743
31.8k
  if (ret < 0) {
13744
31.8k
  } else if (ret == 1) {
13745
8.56k
      if (toBool)
13746
0
    goto return_1;
13747
            /* TODO: Check memory error. */
13748
8.56k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13749
8.56k
  }
13750
31.8k
    }
13751
44.0k
    depth = 0;
13752
44.0k
    goto scan_children;
13753
3.69M
next_node:
13754
5.74M
    do {
13755
5.74M
        if (ctxt->opLimit != 0) {
13756
0
            if (ctxt->opCount >= ctxt->opLimit) {
13757
0
                xmlGenericError(xmlGenericErrorContext,
13758
0
                        "XPath operation limit exceeded\n");
13759
0
                xmlFreeStreamCtxt(patstream);
13760
0
                return(-1);
13761
0
            }
13762
0
            ctxt->opCount++;
13763
0
        }
13764
13765
5.74M
        nb_nodes++;
13766
13767
5.74M
  switch (cur->type) {
13768
2.66M
      case XML_ELEMENT_NODE:
13769
5.39M
      case XML_TEXT_NODE:
13770
5.40M
      case XML_CDATA_SECTION_NODE:
13771
5.65M
      case XML_COMMENT_NODE:
13772
5.72M
      case XML_PI_NODE:
13773
5.72M
    if (cur->type == XML_ELEMENT_NODE) {
13774
2.66M
        ret = xmlStreamPush(patstream, cur->name,
13775
2.66M
        (cur->ns ? cur->ns->href : NULL));
13776
3.05M
    } else if (eval_all_nodes)
13777
807k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13778
2.25M
    else
13779
2.25M
        break;
13780
13781
3.47M
    if (ret < 0) {
13782
        /* NOP. */
13783
3.47M
    } else if (ret == 1) {
13784
1.58M
        if (toBool)
13785
0
      goto return_1;
13786
1.58M
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13787
1.58M
            < 0) {
13788
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13789
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13790
0
        }
13791
1.58M
    }
13792
3.47M
    if ((cur->children == NULL) || (depth >= max_depth)) {
13793
2.18M
        ret = xmlStreamPop(patstream);
13794
2.18M
        while (cur->next != NULL) {
13795
1.96M
      cur = cur->next;
13796
1.96M
      if ((cur->type != XML_ENTITY_DECL) &&
13797
1.96M
          (cur->type != XML_DTD_NODE))
13798
1.96M
          goto next_node;
13799
1.96M
        }
13800
2.18M
    }
13801
1.52M
      default:
13802
1.52M
    break;
13803
5.74M
  }
13804
13805
3.82M
scan_children:
13806
3.82M
  if (cur->type == XML_NAMESPACE_DECL) break;
13807
3.82M
  if ((cur->children != NULL) && (depth < max_depth)) {
13808
      /*
13809
       * Do not descend on entities declarations
13810
       */
13811
1.33M
      if (cur->children->type != XML_ENTITY_DECL) {
13812
1.33M
    cur = cur->children;
13813
1.33M
    depth++;
13814
    /*
13815
     * Skip DTDs
13816
     */
13817
1.33M
    if (cur->type != XML_DTD_NODE)
13818
1.32M
        continue;
13819
1.33M
      }
13820
1.33M
  }
13821
13822
2.49M
  if (cur == limit)
13823
0
      break;
13824
13825
2.49M
  while (cur->next != NULL) {
13826
1.73M
      cur = cur->next;
13827
1.73M
      if ((cur->type != XML_ENTITY_DECL) &&
13828
1.73M
    (cur->type != XML_DTD_NODE))
13829
1.73M
    goto next_node;
13830
1.73M
  }
13831
13832
1.33M
  do {
13833
1.33M
      cur = cur->parent;
13834
1.33M
      depth--;
13835
1.33M
      if ((cur == NULL) || (cur == limit) ||
13836
1.33M
                (cur->type == XML_DOCUMENT_NODE))
13837
44.0k
          goto done;
13838
1.28M
      if (cur->type == XML_ELEMENT_NODE) {
13839
1.28M
    ret = xmlStreamPop(patstream);
13840
1.28M
      } else if ((eval_all_nodes) &&
13841
0
    ((cur->type == XML_TEXT_NODE) ||
13842
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13843
0
     (cur->type == XML_COMMENT_NODE) ||
13844
0
     (cur->type == XML_PI_NODE)))
13845
0
      {
13846
0
    ret = xmlStreamPop(patstream);
13847
0
      }
13848
1.28M
      if (cur->next != NULL) {
13849
720k
    cur = cur->next;
13850
720k
    break;
13851
720k
      }
13852
1.28M
  } while (cur != NULL);
13853
13854
2.04M
    } while ((cur != NULL) && (depth >= 0));
13855
13856
44.0k
done:
13857
13858
#if 0
13859
    printf("stream eval: checked %d nodes selected %d\n",
13860
           nb_nodes, retObj->nodesetval->nodeNr);
13861
#endif
13862
13863
44.0k
    if (patstream)
13864
44.0k
  xmlFreeStreamCtxt(patstream);
13865
44.0k
    return(0);
13866
13867
0
return_1:
13868
0
    if (patstream)
13869
0
  xmlFreeStreamCtxt(patstream);
13870
0
    return(1);
13871
3.69M
}
13872
#endif /* XPATH_STREAMING */
13873
13874
/**
13875
 * xmlXPathRunEval:
13876
 * @ctxt:  the XPath parser context with the compiled expression
13877
 * @toBool:  evaluate to a boolean result
13878
 *
13879
 * Evaluate the Precompiled XPath expression in the given context.
13880
 */
13881
static int
13882
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13883
173k
{
13884
173k
    xmlXPathCompExprPtr comp;
13885
173k
    int oldDepth;
13886
13887
173k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13888
0
  return(-1);
13889
13890
173k
    if (ctxt->valueTab == NULL) {
13891
  /* Allocate the value stack */
13892
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
13893
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13894
0
  if (ctxt->valueTab == NULL) {
13895
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13896
0
      return(-1);
13897
0
  }
13898
0
  ctxt->valueNr = 0;
13899
0
  ctxt->valueMax = 10;
13900
0
  ctxt->value = NULL;
13901
0
        ctxt->valueFrame = 0;
13902
0
    }
13903
173k
#ifdef XPATH_STREAMING
13904
173k
    if (ctxt->comp->stream) {
13905
44.5k
  int res;
13906
13907
44.5k
  if (toBool) {
13908
      /*
13909
      * Evaluation to boolean result.
13910
      */
13911
0
      res = xmlXPathRunStreamEval(ctxt->context,
13912
0
    ctxt->comp->stream, NULL, 1);
13913
0
      if (res != -1)
13914
0
    return(res);
13915
44.5k
  } else {
13916
44.5k
      xmlXPathObjectPtr resObj = NULL;
13917
13918
      /*
13919
      * Evaluation to a sequence.
13920
      */
13921
44.5k
      res = xmlXPathRunStreamEval(ctxt->context,
13922
44.5k
    ctxt->comp->stream, &resObj, 0);
13923
13924
44.5k
      if ((res != -1) && (resObj != NULL)) {
13925
44.5k
    valuePush(ctxt, resObj);
13926
44.5k
    return(0);
13927
44.5k
      }
13928
0
      if (resObj != NULL)
13929
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13930
0
  }
13931
  /*
13932
  * QUESTION TODO: This falls back to normal XPath evaluation
13933
  * if res == -1. Is this intended?
13934
  */
13935
44.5k
    }
13936
129k
#endif
13937
129k
    comp = ctxt->comp;
13938
129k
    if (comp->last < 0) {
13939
0
  xmlGenericError(xmlGenericErrorContext,
13940
0
      "xmlXPathRunEval: last is less than zero\n");
13941
0
  return(-1);
13942
0
    }
13943
129k
    oldDepth = ctxt->context->depth;
13944
129k
    if (toBool)
13945
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13946
0
      &comp->steps[comp->last], 0));
13947
129k
    else
13948
129k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13949
129k
    ctxt->context->depth = oldDepth;
13950
13951
129k
    return(0);
13952
129k
}
13953
13954
/************************************************************************
13955
 *                  *
13956
 *      Public interfaces       *
13957
 *                  *
13958
 ************************************************************************/
13959
13960
/**
13961
 * xmlXPathEvalPredicate:
13962
 * @ctxt:  the XPath context
13963
 * @res:  the Predicate Expression evaluation result
13964
 *
13965
 * Evaluate a predicate result for the current node.
13966
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13967
 * the result to a boolean. If the result is a number, the result will
13968
 * be converted to true if the number is equal to the position of the
13969
 * context node in the context node list (as returned by the position
13970
 * function) and will be converted to false otherwise; if the result
13971
 * is not a number, then the result will be converted as if by a call
13972
 * to the boolean function.
13973
 *
13974
 * Returns 1 if predicate is true, 0 otherwise
13975
 */
13976
int
13977
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13978
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13979
0
    switch (res->type) {
13980
0
        case XPATH_BOOLEAN:
13981
0
      return(res->boolval);
13982
0
        case XPATH_NUMBER:
13983
0
      return(res->floatval == ctxt->proximityPosition);
13984
0
        case XPATH_NODESET:
13985
0
        case XPATH_XSLT_TREE:
13986
0
      if (res->nodesetval == NULL)
13987
0
    return(0);
13988
0
      return(res->nodesetval->nodeNr != 0);
13989
0
        case XPATH_STRING:
13990
0
      return((res->stringval != NULL) &&
13991
0
             (xmlStrlen(res->stringval) != 0));
13992
0
        default:
13993
0
      STRANGE
13994
0
    }
13995
0
    return(0);
13996
0
}
13997
13998
/**
13999
 * xmlXPathEvaluatePredicateResult:
14000
 * @ctxt:  the XPath Parser context
14001
 * @res:  the Predicate Expression evaluation result
14002
 *
14003
 * Evaluate a predicate result for the current node.
14004
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14005
 * the result to a boolean. If the result is a number, the result will
14006
 * be converted to true if the number is equal to the position of the
14007
 * context node in the context node list (as returned by the position
14008
 * function) and will be converted to false otherwise; if the result
14009
 * is not a number, then the result will be converted as if by a call
14010
 * to the boolean function.
14011
 *
14012
 * Returns 1 if predicate is true, 0 otherwise
14013
 */
14014
int
14015
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14016
504k
                                xmlXPathObjectPtr res) {
14017
504k
    if ((ctxt == NULL) || (res == NULL)) return(0);
14018
504k
    switch (res->type) {
14019
0
        case XPATH_BOOLEAN:
14020
0
      return(res->boolval);
14021
33.8k
        case XPATH_NUMBER:
14022
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14023
      return((res->floatval == ctxt->context->proximityPosition) &&
14024
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14025
#else
14026
33.8k
      return(res->floatval == ctxt->context->proximityPosition);
14027
0
#endif
14028
470k
        case XPATH_NODESET:
14029
470k
        case XPATH_XSLT_TREE:
14030
470k
      if (res->nodesetval == NULL)
14031
1.19k
    return(0);
14032
469k
      return(res->nodesetval->nodeNr != 0);
14033
122
        case XPATH_STRING:
14034
122
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14035
#ifdef LIBXML_XPTR_LOCS_ENABLED
14036
  case XPATH_LOCATIONSET:{
14037
      xmlLocationSetPtr ptr = res->user;
14038
      if (ptr == NULL)
14039
          return(0);
14040
      return (ptr->locNr != 0);
14041
      }
14042
#endif
14043
0
        default:
14044
0
      STRANGE
14045
504k
    }
14046
0
    return(0);
14047
504k
}
14048
14049
#ifdef XPATH_STREAMING
14050
/**
14051
 * xmlXPathTryStreamCompile:
14052
 * @ctxt: an XPath context
14053
 * @str:  the XPath expression
14054
 *
14055
 * Try to compile the XPath expression as a streamable subset.
14056
 *
14057
 * Returns the compiled expression or NULL if failed to compile.
14058
 */
14059
static xmlXPathCompExprPtr
14060
218k
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14061
    /*
14062
     * Optimization: use streaming patterns when the XPath expression can
14063
     * be compiled to a stream lookup
14064
     */
14065
218k
    xmlPatternPtr stream;
14066
218k
    xmlXPathCompExprPtr comp;
14067
218k
    xmlDictPtr dict = NULL;
14068
218k
    const xmlChar **namespaces = NULL;
14069
218k
    xmlNsPtr ns;
14070
218k
    int i, j;
14071
14072
218k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14073
218k
        (!xmlStrchr(str, '@'))) {
14074
147k
  const xmlChar *tmp;
14075
14076
  /*
14077
   * We don't try to handle expressions using the verbose axis
14078
   * specifiers ("::"), just the simplified form at this point.
14079
   * Additionally, if there is no list of namespaces available and
14080
   *  there's a ":" in the expression, indicating a prefixed QName,
14081
   *  then we won't try to compile either. xmlPatterncompile() needs
14082
   *  to have a list of namespaces at compilation time in order to
14083
   *  compile prefixed name tests.
14084
   */
14085
147k
  tmp = xmlStrchr(str, ':');
14086
147k
  if ((tmp != NULL) &&
14087
147k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14088
5.89k
      return(NULL);
14089
14090
141k
  if (ctxt != NULL) {
14091
141k
      dict = ctxt->dict;
14092
141k
      if (ctxt->nsNr > 0) {
14093
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14094
0
    if (namespaces == NULL) {
14095
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14096
0
        return(NULL);
14097
0
    }
14098
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14099
0
        ns = ctxt->namespaces[j];
14100
0
        namespaces[i++] = ns->href;
14101
0
        namespaces[i++] = ns->prefix;
14102
0
    }
14103
0
    namespaces[i++] = NULL;
14104
0
    namespaces[i] = NULL;
14105
0
      }
14106
141k
  }
14107
14108
141k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14109
141k
  if (namespaces != NULL) {
14110
0
      xmlFree((xmlChar **)namespaces);
14111
0
  }
14112
141k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14113
44.5k
      comp = xmlXPathNewCompExpr();
14114
44.5k
      if (comp == NULL) {
14115
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14116
0
    return(NULL);
14117
0
      }
14118
44.5k
      comp->stream = stream;
14119
44.5k
      comp->dict = dict;
14120
44.5k
      if (comp->dict)
14121
0
    xmlDictReference(comp->dict);
14122
44.5k
      return(comp);
14123
44.5k
  }
14124
97.0k
  xmlFreePattern(stream);
14125
97.0k
    }
14126
167k
    return(NULL);
14127
218k
}
14128
#endif /* XPATH_STREAMING */
14129
14130
static void
14131
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14132
                           xmlXPathStepOpPtr op)
14133
1.92M
{
14134
1.92M
    xmlXPathCompExprPtr comp = pctxt->comp;
14135
1.92M
    xmlXPathContextPtr ctxt;
14136
14137
    /*
14138
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14139
    * internal representation.
14140
    */
14141
14142
1.92M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14143
1.92M
        (op->ch1 != -1) &&
14144
1.92M
        (op->ch2 == -1 /* no predicate */))
14145
611k
    {
14146
611k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14147
14148
611k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14149
611k
            ((xmlXPathAxisVal) prevop->value ==
14150
116k
                AXIS_DESCENDANT_OR_SELF) &&
14151
611k
            (prevop->ch2 == -1) &&
14152
611k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14153
611k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14154
57.7k
        {
14155
            /*
14156
            * This is a "descendant-or-self::node()" without predicates.
14157
            * Try to eliminate it.
14158
            */
14159
14160
57.7k
            switch ((xmlXPathAxisVal) op->value) {
14161
42.9k
                case AXIS_CHILD:
14162
42.9k
                case AXIS_DESCENDANT:
14163
                    /*
14164
                    * Convert "descendant-or-self::node()/child::" or
14165
                    * "descendant-or-self::node()/descendant::" to
14166
                    * "descendant::"
14167
                    */
14168
42.9k
                    op->ch1   = prevop->ch1;
14169
42.9k
                    op->value = AXIS_DESCENDANT;
14170
42.9k
                    break;
14171
0
                case AXIS_SELF:
14172
203
                case AXIS_DESCENDANT_OR_SELF:
14173
                    /*
14174
                    * Convert "descendant-or-self::node()/self::" or
14175
                    * "descendant-or-self::node()/descendant-or-self::" to
14176
                    * to "descendant-or-self::"
14177
                    */
14178
203
                    op->ch1   = prevop->ch1;
14179
203
                    op->value = AXIS_DESCENDANT_OR_SELF;
14180
203
                    break;
14181
14.5k
                default:
14182
14.5k
                    break;
14183
57.7k
            }
14184
57.7k
  }
14185
611k
    }
14186
14187
    /* OP_VALUE has invalid ch1. */
14188
1.92M
    if (op->op == XPATH_OP_VALUE)
14189
60.0k
        return;
14190
14191
    /* Recurse */
14192
1.86M
    ctxt = pctxt->context;
14193
1.86M
    if (ctxt != NULL) {
14194
1.86M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14195
187
            return;
14196
1.86M
        ctxt->depth += 1;
14197
1.86M
    }
14198
1.86M
    if (op->ch1 != -1)
14199
1.27M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14200
1.86M
    if (op->ch2 != -1)
14201
521k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14202
1.86M
    if (ctxt != NULL)
14203
1.86M
        ctxt->depth -= 1;
14204
1.86M
}
14205
14206
/**
14207
 * xmlXPathCtxtCompile:
14208
 * @ctxt: an XPath context
14209
 * @str:  the XPath expression
14210
 *
14211
 * Compile an XPath expression
14212
 *
14213
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14214
 *         the caller has to free the object.
14215
 */
14216
xmlXPathCompExprPtr
14217
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14218
0
    xmlXPathParserContextPtr pctxt;
14219
0
    xmlXPathCompExprPtr comp;
14220
0
    int oldDepth = 0;
14221
14222
0
#ifdef XPATH_STREAMING
14223
0
    comp = xmlXPathTryStreamCompile(ctxt, str);
14224
0
    if (comp != NULL)
14225
0
        return(comp);
14226
0
#endif
14227
14228
0
    xmlInitParser();
14229
14230
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
14231
0
    if (pctxt == NULL)
14232
0
        return NULL;
14233
0
    if (ctxt != NULL)
14234
0
        oldDepth = ctxt->depth;
14235
0
    xmlXPathCompileExpr(pctxt, 1);
14236
0
    if (ctxt != NULL)
14237
0
        ctxt->depth = oldDepth;
14238
14239
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
14240
0
    {
14241
0
        xmlXPathFreeParserContext(pctxt);
14242
0
        return(NULL);
14243
0
    }
14244
14245
0
    if (*pctxt->cur != 0) {
14246
  /*
14247
   * aleksey: in some cases this line prints *second* error message
14248
   * (see bug #78858) and probably this should be fixed.
14249
   * However, we are not sure that all error messages are printed
14250
   * out in other places. It's not critical so we leave it as-is for now
14251
   */
14252
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14253
0
  comp = NULL;
14254
0
    } else {
14255
0
  comp = pctxt->comp;
14256
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14257
0
            if (ctxt != NULL)
14258
0
                oldDepth = ctxt->depth;
14259
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14260
0
            if (ctxt != NULL)
14261
0
                ctxt->depth = oldDepth;
14262
0
  }
14263
0
  pctxt->comp = NULL;
14264
0
    }
14265
0
    xmlXPathFreeParserContext(pctxt);
14266
14267
0
    if (comp != NULL) {
14268
0
  comp->expr = xmlStrdup(str);
14269
#ifdef DEBUG_EVAL_COUNTS
14270
  comp->string = xmlStrdup(str);
14271
  comp->nb = 0;
14272
#endif
14273
0
    }
14274
0
    return(comp);
14275
0
}
14276
14277
/**
14278
 * xmlXPathCompile:
14279
 * @str:  the XPath expression
14280
 *
14281
 * Compile an XPath expression
14282
 *
14283
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14284
 *         the caller has to free the object.
14285
 */
14286
xmlXPathCompExprPtr
14287
0
xmlXPathCompile(const xmlChar *str) {
14288
0
    return(xmlXPathCtxtCompile(NULL, str));
14289
0
}
14290
14291
/**
14292
 * xmlXPathCompiledEvalInternal:
14293
 * @comp:  the compiled XPath expression
14294
 * @ctxt:  the XPath context
14295
 * @resObj: the resulting XPath object or NULL
14296
 * @toBool: 1 if only a boolean result is requested
14297
 *
14298
 * Evaluate the Precompiled XPath expression in the given context.
14299
 * The caller has to free @resObj.
14300
 *
14301
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14302
 *         the caller has to free the object.
14303
 */
14304
static int
14305
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14306
           xmlXPathContextPtr ctxt,
14307
           xmlXPathObjectPtr *resObjPtr,
14308
           int toBool)
14309
0
{
14310
0
    xmlXPathParserContextPtr pctxt;
14311
0
    xmlXPathObjectPtr resObj;
14312
#ifndef LIBXML_THREAD_ENABLED
14313
    static int reentance = 0;
14314
#endif
14315
0
    int res;
14316
14317
0
    CHECK_CTXT_NEG(ctxt)
14318
14319
0
    if (comp == NULL)
14320
0
  return(-1);
14321
0
    xmlInitParser();
14322
14323
#ifndef LIBXML_THREAD_ENABLED
14324
    reentance++;
14325
    if (reentance > 1)
14326
  xmlXPathDisableOptimizer = 1;
14327
#endif
14328
14329
#ifdef DEBUG_EVAL_COUNTS
14330
    comp->nb++;
14331
    if ((comp->string != NULL) && (comp->nb > 100)) {
14332
  fprintf(stderr, "100 x %s\n", comp->string);
14333
  comp->nb = 0;
14334
    }
14335
#endif
14336
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14337
0
    res = xmlXPathRunEval(pctxt, toBool);
14338
14339
0
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14340
0
        resObj = NULL;
14341
0
    } else {
14342
0
        resObj = valuePop(pctxt);
14343
0
        if (resObj == NULL) {
14344
0
            if (!toBool)
14345
0
                xmlGenericError(xmlGenericErrorContext,
14346
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14347
0
        } else if (pctxt->valueNr > 0) {
14348
0
            xmlGenericError(xmlGenericErrorContext,
14349
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14350
0
                pctxt->valueNr);
14351
0
        }
14352
0
    }
14353
14354
0
    if (resObjPtr)
14355
0
        *resObjPtr = resObj;
14356
0
    else
14357
0
        xmlXPathReleaseObject(ctxt, resObj);
14358
14359
0
    pctxt->comp = NULL;
14360
0
    xmlXPathFreeParserContext(pctxt);
14361
#ifndef LIBXML_THREAD_ENABLED
14362
    reentance--;
14363
#endif
14364
14365
0
    return(res);
14366
0
}
14367
14368
/**
14369
 * xmlXPathCompiledEval:
14370
 * @comp:  the compiled XPath expression
14371
 * @ctx:  the XPath context
14372
 *
14373
 * Evaluate the Precompiled XPath expression in the given context.
14374
 *
14375
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14376
 *         the caller has to free the object.
14377
 */
14378
xmlXPathObjectPtr
14379
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14380
0
{
14381
0
    xmlXPathObjectPtr res = NULL;
14382
14383
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14384
0
    return(res);
14385
0
}
14386
14387
/**
14388
 * xmlXPathCompiledEvalToBoolean:
14389
 * @comp:  the compiled XPath expression
14390
 * @ctxt:  the XPath context
14391
 *
14392
 * Applies the XPath boolean() function on the result of the given
14393
 * compiled expression.
14394
 *
14395
 * Returns 1 if the expression evaluated to true, 0 if to false and
14396
 *         -1 in API and internal errors.
14397
 */
14398
int
14399
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14400
            xmlXPathContextPtr ctxt)
14401
0
{
14402
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14403
0
}
14404
14405
/**
14406
 * xmlXPathEvalExpr:
14407
 * @ctxt:  the XPath Parser context
14408
 *
14409
 * Parse and evaluate an XPath expression in the given context,
14410
 * then push the result on the context stack
14411
 */
14412
void
14413
218k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14414
218k
#ifdef XPATH_STREAMING
14415
218k
    xmlXPathCompExprPtr comp;
14416
218k
#endif
14417
218k
    int oldDepth = 0;
14418
14419
218k
    if (ctxt == NULL) return;
14420
14421
218k
#ifdef XPATH_STREAMING
14422
218k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14423
218k
    if (comp != NULL) {
14424
44.5k
        if (ctxt->comp != NULL)
14425
44.5k
      xmlXPathFreeCompExpr(ctxt->comp);
14426
44.5k
        ctxt->comp = comp;
14427
44.5k
    } else
14428
173k
#endif
14429
173k
    {
14430
173k
        if (ctxt->context != NULL)
14431
173k
            oldDepth = ctxt->context->depth;
14432
173k
  xmlXPathCompileExpr(ctxt, 1);
14433
173k
        if (ctxt->context != NULL)
14434
173k
            ctxt->context->depth = oldDepth;
14435
173k
        CHECK_ERROR;
14436
14437
        /* Check for trailing characters. */
14438
150k
        if (*ctxt->cur != 0)
14439
129k
            XP_ERROR(XPATH_EXPR_ERROR);
14440
14441
129k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14442
128k
            if (ctxt->context != NULL)
14443
128k
                oldDepth = ctxt->context->depth;
14444
128k
      xmlXPathOptimizeExpression(ctxt,
14445
128k
    &ctxt->comp->steps[ctxt->comp->last]);
14446
128k
            if (ctxt->context != NULL)
14447
128k
                ctxt->context->depth = oldDepth;
14448
128k
        }
14449
129k
    }
14450
14451
173k
    xmlXPathRunEval(ctxt, 0);
14452
173k
}
14453
14454
/**
14455
 * xmlXPathEval:
14456
 * @str:  the XPath expression
14457
 * @ctx:  the XPath context
14458
 *
14459
 * Evaluate the XPath Location Path in the given context.
14460
 *
14461
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14462
 *         the caller has to free the object.
14463
 */
14464
xmlXPathObjectPtr
14465
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14466
0
    xmlXPathParserContextPtr ctxt;
14467
0
    xmlXPathObjectPtr res;
14468
14469
0
    CHECK_CTXT(ctx)
14470
14471
0
    xmlInitParser();
14472
14473
0
    ctxt = xmlXPathNewParserContext(str, ctx);
14474
0
    if (ctxt == NULL)
14475
0
        return NULL;
14476
0
    xmlXPathEvalExpr(ctxt);
14477
14478
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14479
0
  res = NULL;
14480
0
    } else {
14481
0
  res = valuePop(ctxt);
14482
0
        if (res == NULL) {
14483
0
            xmlGenericError(xmlGenericErrorContext,
14484
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14485
0
        } else if (ctxt->valueNr > 0) {
14486
0
            xmlGenericError(xmlGenericErrorContext,
14487
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14488
0
                ctxt->valueNr);
14489
0
        }
14490
0
    }
14491
14492
0
    xmlXPathFreeParserContext(ctxt);
14493
0
    return(res);
14494
0
}
14495
14496
/**
14497
 * xmlXPathSetContextNode:
14498
 * @node: the node to to use as the context node
14499
 * @ctx:  the XPath context
14500
 *
14501
 * Sets 'node' as the context node. The node must be in the same
14502
 * document as that associated with the context.
14503
 *
14504
 * Returns -1 in case of error or 0 if successful
14505
 */
14506
int
14507
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14508
0
    if ((node == NULL) || (ctx == NULL))
14509
0
        return(-1);
14510
14511
0
    if (node->doc == ctx->doc) {
14512
0
        ctx->node = node;
14513
0
  return(0);
14514
0
    }
14515
0
    return(-1);
14516
0
}
14517
14518
/**
14519
 * xmlXPathNodeEval:
14520
 * @node: the node to to use as the context node
14521
 * @str:  the XPath expression
14522
 * @ctx:  the XPath context
14523
 *
14524
 * Evaluate the XPath Location Path in the given context. The node 'node'
14525
 * is set as the context node. The context node is not restored.
14526
 *
14527
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14528
 *         the caller has to free the object.
14529
 */
14530
xmlXPathObjectPtr
14531
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14532
0
    if (str == NULL)
14533
0
        return(NULL);
14534
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14535
0
        return(NULL);
14536
0
    return(xmlXPathEval(str, ctx));
14537
0
}
14538
14539
/**
14540
 * xmlXPathEvalExpression:
14541
 * @str:  the XPath expression
14542
 * @ctxt:  the XPath context
14543
 *
14544
 * Alias for xmlXPathEval().
14545
 *
14546
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14547
 *         the caller has to free the object.
14548
 */
14549
xmlXPathObjectPtr
14550
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14551
0
    return(xmlXPathEval(str, ctxt));
14552
0
}
14553
14554
/************************************************************************
14555
 *                  *
14556
 *  Extra functions not pertaining to the XPath spec    *
14557
 *                  *
14558
 ************************************************************************/
14559
/**
14560
 * xmlXPathEscapeUriFunction:
14561
 * @ctxt:  the XPath Parser context
14562
 * @nargs:  the number of arguments
14563
 *
14564
 * Implement the escape-uri() XPath function
14565
 *    string escape-uri(string $str, bool $escape-reserved)
14566
 *
14567
 * This function applies the URI escaping rules defined in section 2 of [RFC
14568
 * 2396] to the string supplied as $uri-part, which typically represents all
14569
 * or part of a URI. The effect of the function is to replace any special
14570
 * character in the string by an escape sequence of the form %xx%yy...,
14571
 * where xxyy... is the hexadecimal representation of the octets used to
14572
 * represent the character in UTF-8.
14573
 *
14574
 * The set of characters that are escaped depends on the setting of the
14575
 * boolean argument $escape-reserved.
14576
 *
14577
 * If $escape-reserved is true, all characters are escaped other than lower
14578
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14579
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14580
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14581
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14582
 * A-F).
14583
 *
14584
 * If $escape-reserved is false, the behavior differs in that characters
14585
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14586
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14587
 *
14588
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14589
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14590
 * compared using string comparison functions, this function must always use
14591
 * the upper-case letters A-F.
14592
 *
14593
 * Generally, $escape-reserved should be set to true when escaping a string
14594
 * that is to form a single part of a URI, and to false when escaping an
14595
 * entire URI or URI reference.
14596
 *
14597
 * In the case of non-ascii characters, the string is encoded according to
14598
 * utf-8 and then converted according to RFC 2396.
14599
 *
14600
 * Examples
14601
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14602
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14603
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14604
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14605
 *
14606
 */
14607
static void
14608
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14609
0
    xmlXPathObjectPtr str;
14610
0
    int escape_reserved;
14611
0
    xmlBufPtr target;
14612
0
    xmlChar *cptr;
14613
0
    xmlChar escape[4];
14614
14615
0
    CHECK_ARITY(2);
14616
14617
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14618
14619
0
    CAST_TO_STRING;
14620
0
    str = valuePop(ctxt);
14621
14622
0
    target = xmlBufCreate();
14623
14624
0
    escape[0] = '%';
14625
0
    escape[3] = 0;
14626
14627
0
    if (target) {
14628
0
  for (cptr = str->stringval; *cptr; cptr++) {
14629
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14630
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14631
0
    (*cptr >= '0' && *cptr <= '9') ||
14632
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14633
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14634
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14635
0
    (*cptr == '%' &&
14636
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14637
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14638
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14639
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14640
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14641
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14642
0
    (!escape_reserved &&
14643
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14644
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14645
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14646
0
      *cptr == ','))) {
14647
0
    xmlBufAdd(target, cptr, 1);
14648
0
      } else {
14649
0
    if ((*cptr >> 4) < 10)
14650
0
        escape[1] = '0' + (*cptr >> 4);
14651
0
    else
14652
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14653
0
    if ((*cptr & 0xF) < 10)
14654
0
        escape[2] = '0' + (*cptr & 0xF);
14655
0
    else
14656
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14657
14658
0
    xmlBufAdd(target, &escape[0], 3);
14659
0
      }
14660
0
  }
14661
0
    }
14662
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14663
0
  xmlBufContent(target)));
14664
0
    xmlBufFree(target);
14665
0
    xmlXPathReleaseObject(ctxt->context, str);
14666
0
}
14667
14668
/**
14669
 * xmlXPathRegisterAllFunctions:
14670
 * @ctxt:  the XPath context
14671
 *
14672
 * Registers all default XPath functions in this context
14673
 */
14674
void
14675
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14676
284k
{
14677
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14678
284k
                         xmlXPathBooleanFunction);
14679
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14680
284k
                         xmlXPathCeilingFunction);
14681
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14682
284k
                         xmlXPathCountFunction);
14683
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14684
284k
                         xmlXPathConcatFunction);
14685
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14686
284k
                         xmlXPathContainsFunction);
14687
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14688
284k
                         xmlXPathIdFunction);
14689
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14690
284k
                         xmlXPathFalseFunction);
14691
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14692
284k
                         xmlXPathFloorFunction);
14693
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14694
284k
                         xmlXPathLastFunction);
14695
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14696
284k
                         xmlXPathLangFunction);
14697
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14698
284k
                         xmlXPathLocalNameFunction);
14699
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14700
284k
                         xmlXPathNotFunction);
14701
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14702
284k
                         xmlXPathNameFunction);
14703
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14704
284k
                         xmlXPathNamespaceURIFunction);
14705
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14706
284k
                         xmlXPathNormalizeFunction);
14707
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14708
284k
                         xmlXPathNumberFunction);
14709
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14710
284k
                         xmlXPathPositionFunction);
14711
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14712
284k
                         xmlXPathRoundFunction);
14713
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14714
284k
                         xmlXPathStringFunction);
14715
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14716
284k
                         xmlXPathStringLengthFunction);
14717
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14718
284k
                         xmlXPathStartsWithFunction);
14719
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14720
284k
                         xmlXPathSubstringFunction);
14721
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14722
284k
                         xmlXPathSubstringBeforeFunction);
14723
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14724
284k
                         xmlXPathSubstringAfterFunction);
14725
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14726
284k
                         xmlXPathSumFunction);
14727
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14728
284k
                         xmlXPathTrueFunction);
14729
284k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14730
284k
                         xmlXPathTranslateFunction);
14731
14732
284k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14733
284k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14734
284k
                         xmlXPathEscapeUriFunction);
14735
284k
}
14736
14737
#endif /* LIBXML_XPATH_ENABLED */