Coverage Report

Created: 2023-06-07 06:14

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/valid.h>
35
#include <libxml/xpath.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/parserInternals.h>
38
#include <libxml/hash.h>
39
#ifdef LIBXML_XPTR_LOCS_ENABLED
40
#include <libxml/xpointer.h>
41
#endif
42
#ifdef LIBXML_DEBUG_ENABLED
43
#include <libxml/debugXML.h>
44
#endif
45
#include <libxml/xmlerror.h>
46
#include <libxml/threads.h>
47
#include <libxml/globals.h>
48
#ifdef LIBXML_PATTERN_ENABLED
49
#include <libxml/pattern.h>
50
#endif
51
52
#include "private/buf.h"
53
#include "private/error.h"
54
#include "private/xpath.h"
55
56
#ifdef LIBXML_PATTERN_ENABLED
57
#define XPATH_STREAMING
58
#endif
59
60
#define TODO                \
61
0
    xmlGenericError(xmlGenericErrorContext,       \
62
0
      "Unimplemented block at %s:%d\n",       \
63
0
            __FILE__, __LINE__);
64
65
/**
66
 * WITH_TIM_SORT:
67
 *
68
 * Use the Timsort algorithm provided in timsort.h to sort
69
 * nodeset as this is a great improvement over the old Shell sort
70
 * used in xmlXPathNodeSetSort()
71
 */
72
#define WITH_TIM_SORT
73
74
/*
75
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
76
* If defined, this will use xmlXPathCmpNodesExt() instead of
77
* xmlXPathCmpNodes(). The new function is optimized comparison of
78
* non-element nodes; actually it will speed up comparison only if
79
* xmlXPathOrderDocElems() was called in order to index the elements of
80
* a tree in document order; Libxslt does such an indexing, thus it will
81
* benefit from this optimization.
82
*/
83
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
84
85
/*
86
* XP_OPTIMIZED_FILTER_FIRST:
87
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
88
* in a way, that it stop evaluation at the first node.
89
*/
90
#define XP_OPTIMIZED_FILTER_FIRST
91
92
/*
93
* XP_DEBUG_OBJ_USAGE:
94
* Internal flag to enable tracking of how much XPath objects have been
95
* created.
96
*/
97
/* #define XP_DEBUG_OBJ_USAGE */
98
99
/*
100
 * XPATH_MAX_STEPS:
101
 * when compiling an XPath expression we arbitrary limit the maximum
102
 * number of step operation in the compiled expression. 1000000 is
103
 * an insanely large value which should never be reached under normal
104
 * circumstances
105
 */
106
15.4k
#define XPATH_MAX_STEPS 1000000
107
108
/*
109
 * XPATH_MAX_STACK_DEPTH:
110
 * when evaluating an XPath expression we arbitrary limit the maximum
111
 * number of object allowed to be pushed on the stack. 1000000 is
112
 * an insanely large value which should never be reached under normal
113
 * circumstances
114
 */
115
0
#define XPATH_MAX_STACK_DEPTH 1000000
116
117
/*
118
 * XPATH_MAX_NODESET_LENGTH:
119
 * when evaluating an XPath expression nodesets are created and we
120
 * arbitrary limit the maximum length of those node set. 10000000 is
121
 * an insanely large value which should never be reached under normal
122
 * circumstances, one would first need to construct an in memory tree
123
 * with more than 10 millions nodes.
124
 */
125
36.9k
#define XPATH_MAX_NODESET_LENGTH 10000000
126
127
/*
128
 * XPATH_MAX_RECRUSION_DEPTH:
129
 * Maximum amount of nested functions calls when parsing or evaluating
130
 * expressions
131
 */
132
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
133
4.97M
#define XPATH_MAX_RECURSION_DEPTH 500
134
#elif defined(_WIN32)
135
/* Windows typically limits stack size to 1MB. */
136
#define XPATH_MAX_RECURSION_DEPTH 1000
137
#else
138
#define XPATH_MAX_RECURSION_DEPTH 5000
139
#endif
140
141
/*
142
 * TODO:
143
 * There are a few spots where some tests are done which depend upon ascii
144
 * data.  These should be enhanced for full UTF8 support (see particularly
145
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146
 */
147
148
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
149
150
/************************************************************************
151
 *                  *
152
 *      Floating point stuff        *
153
 *                  *
154
 ************************************************************************/
155
156
double xmlXPathNAN = 0.0;
157
double xmlXPathPINF = 0.0;
158
double xmlXPathNINF = 0.0;
159
160
/**
161
 * xmlXPathInit:
162
 *
163
 * DEPRECATED: Alias for xmlInitParser.
164
 */
165
void
166
0
xmlXPathInit(void) {
167
0
    xmlInitParser();
168
0
}
169
170
/**
171
 * xmlInitXPathInternal:
172
 *
173
 * Initialize the XPath environment
174
 */
175
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
176
void
177
2
xmlInitXPathInternal(void) {
178
2
#if defined(NAN) && defined(INFINITY)
179
2
    xmlXPathNAN = NAN;
180
2
    xmlXPathPINF = INFINITY;
181
2
    xmlXPathNINF = -INFINITY;
182
#else
183
    /* MSVC doesn't allow division by zero in constant expressions. */
184
    double zero = 0.0;
185
    xmlXPathNAN = 0.0 / zero;
186
    xmlXPathPINF = 1.0 / zero;
187
    xmlXPathNINF = -xmlXPathPINF;
188
#endif
189
2
}
190
191
/**
192
 * xmlXPathIsNaN:
193
 * @val:  a double value
194
 *
195
 * Returns 1 if the value is a NaN, 0 otherwise
196
 */
197
int
198
1.92M
xmlXPathIsNaN(double val) {
199
1.92M
#ifdef isnan
200
1.92M
    return isnan(val);
201
#else
202
    return !(val == val);
203
#endif
204
1.92M
}
205
206
/**
207
 * xmlXPathIsInf:
208
 * @val:  a double value
209
 *
210
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
211
 */
212
int
213
4.70k
xmlXPathIsInf(double val) {
214
4.70k
#ifdef isinf
215
4.70k
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
216
#else
217
    if (val >= xmlXPathPINF)
218
        return 1;
219
    if (val <= -xmlXPathPINF)
220
        return -1;
221
    return 0;
222
#endif
223
4.70k
}
224
225
#endif /* SCHEMAS or XPATH */
226
227
#ifdef LIBXML_XPATH_ENABLED
228
229
/*
230
 * TODO: when compatibility allows remove all "fake node libxslt" strings
231
 *       the test should just be name[0] = ' '
232
 */
233
#ifdef DEBUG_XPATH_EXPRESSION
234
#define DEBUG_STEP
235
#define DEBUG_EXPR
236
#define DEBUG_EVAL_COUNTS
237
#endif
238
239
static xmlNs xmlXPathXMLNamespaceStruct = {
240
    NULL,
241
    XML_NAMESPACE_DECL,
242
    XML_XML_NAMESPACE,
243
    BAD_CAST "xml",
244
    NULL,
245
    NULL
246
};
247
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
248
#ifndef LIBXML_THREAD_ENABLED
249
/*
250
 * Optimizer is disabled only when threaded apps are detected while
251
 * the library ain't compiled for thread safety.
252
 */
253
static int xmlXPathDisableOptimizer = 0;
254
#endif
255
256
static void
257
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
258
259
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
260
/**
261
 * xmlXPathCmpNodesExt:
262
 * @node1:  the first node
263
 * @node2:  the second node
264
 *
265
 * Compare two nodes w.r.t document order.
266
 * This one is optimized for handling of non-element nodes.
267
 *
268
 * Returns -2 in case of error 1 if first point < second point, 0 if
269
 *         it's the same node, -1 otherwise
270
 */
271
static int
272
12.3M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
273
12.3M
    int depth1, depth2;
274
12.3M
    int misc = 0, precedence1 = 0, precedence2 = 0;
275
12.3M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
276
12.3M
    xmlNodePtr cur, root;
277
12.3M
    ptrdiff_t l1, l2;
278
279
12.3M
    if ((node1 == NULL) || (node2 == NULL))
280
0
  return(-2);
281
282
12.3M
    if (node1 == node2)
283
0
  return(0);
284
285
    /*
286
     * a couple of optimizations which will avoid computations in most cases
287
     */
288
12.3M
    switch (node1->type) {
289
7.90M
  case XML_ELEMENT_NODE:
290
7.90M
      if (node2->type == XML_ELEMENT_NODE) {
291
6.20M
    if ((0 > (ptrdiff_t) node1->content) &&
292
6.20M
        (0 > (ptrdiff_t) node2->content) &&
293
6.20M
        (node1->doc == node2->doc))
294
4.37M
    {
295
4.37M
        l1 = -((ptrdiff_t) node1->content);
296
4.37M
        l2 = -((ptrdiff_t) node2->content);
297
4.37M
        if (l1 < l2)
298
4.37M
      return(1);
299
113
        if (l1 > l2)
300
113
      return(-1);
301
113
    } else
302
1.83M
        goto turtle_comparison;
303
6.20M
      }
304
1.69M
      break;
305
1.69M
  case XML_ATTRIBUTE_NODE:
306
0
      precedence1 = 1; /* element is owner */
307
0
      miscNode1 = node1;
308
0
      node1 = node1->parent;
309
0
      misc = 1;
310
0
      break;
311
4.18M
  case XML_TEXT_NODE:
312
4.19M
  case XML_CDATA_SECTION_NODE:
313
4.23M
  case XML_COMMENT_NODE:
314
4.24M
  case XML_PI_NODE: {
315
4.24M
      miscNode1 = node1;
316
      /*
317
      * Find nearest element node.
318
      */
319
4.24M
      if (node1->prev != NULL) {
320
5.80M
    do {
321
5.80M
        node1 = node1->prev;
322
5.80M
        if (node1->type == XML_ELEMENT_NODE) {
323
638k
      precedence1 = 3; /* element in prev-sibl axis */
324
638k
      break;
325
638k
        }
326
5.16M
        if (node1->prev == NULL) {
327
49.2k
      precedence1 = 2; /* element is parent */
328
      /*
329
      * URGENT TODO: Are there any cases, where the
330
      * parent of such a node is not an element node?
331
      */
332
49.2k
      node1 = node1->parent;
333
49.2k
      break;
334
49.2k
        }
335
5.16M
    } while (1);
336
3.56M
      } else {
337
3.56M
    precedence1 = 2; /* element is parent */
338
3.56M
    node1 = node1->parent;
339
3.56M
      }
340
4.24M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
341
4.24M
    (0 <= (ptrdiff_t) node1->content)) {
342
    /*
343
    * Fallback for whatever case.
344
    */
345
3.53M
    node1 = miscNode1;
346
3.53M
    precedence1 = 0;
347
3.53M
      } else
348
717k
    misc = 1;
349
4.24M
  }
350
0
      break;
351
13.9k
  case XML_NAMESPACE_DECL:
352
      /*
353
      * TODO: why do we return 1 for namespace nodes?
354
      */
355
13.9k
      return(1);
356
224k
  default:
357
224k
      break;
358
12.3M
    }
359
6.16M
    switch (node2->type) {
360
2.66M
  case XML_ELEMENT_NODE:
361
2.66M
      break;
362
0
  case XML_ATTRIBUTE_NODE:
363
0
      precedence2 = 1; /* element is owner */
364
0
      miscNode2 = node2;
365
0
      node2 = node2->parent;
366
0
      misc = 1;
367
0
      break;
368
2.84M
  case XML_TEXT_NODE:
369
2.84M
  case XML_CDATA_SECTION_NODE:
370
2.88M
  case XML_COMMENT_NODE:
371
2.89M
  case XML_PI_NODE: {
372
2.89M
      miscNode2 = node2;
373
2.89M
      if (node2->prev != NULL) {
374
5.99M
    do {
375
5.99M
        node2 = node2->prev;
376
5.99M
        if (node2->type == XML_ELEMENT_NODE) {
377
835k
      precedence2 = 3; /* element in prev-sibl axis */
378
835k
      break;
379
835k
        }
380
5.15M
        if (node2->prev == NULL) {
381
48.8k
      precedence2 = 2; /* element is parent */
382
48.8k
      node2 = node2->parent;
383
48.8k
      break;
384
48.8k
        }
385
5.15M
    } while (1);
386
2.01M
      } else {
387
2.01M
    precedence2 = 2; /* element is parent */
388
2.01M
    node2 = node2->parent;
389
2.01M
      }
390
2.89M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
391
2.89M
    (0 <= (ptrdiff_t) node2->content))
392
1.97M
      {
393
1.97M
    node2 = miscNode2;
394
1.97M
    precedence2 = 0;
395
1.97M
      } else
396
920k
    misc = 1;
397
2.89M
  }
398
0
      break;
399
620
  case XML_NAMESPACE_DECL:
400
620
      return(1);
401
605k
  default:
402
605k
      break;
403
6.16M
    }
404
6.16M
    if (misc) {
405
1.44M
  if (node1 == node2) {
406
376k
      if (precedence1 == precedence2) {
407
    /*
408
    * The ugly case; but normally there aren't many
409
    * adjacent non-element nodes around.
410
    */
411
63.6k
    cur = miscNode2->prev;
412
73.2k
    while (cur != NULL) {
413
73.2k
        if (cur == miscNode1)
414
62.9k
      return(1);
415
10.3k
        if (cur->type == XML_ELEMENT_NODE)
416
719
      return(-1);
417
9.58k
        cur = cur->prev;
418
9.58k
    }
419
0
    return (-1);
420
312k
      } else {
421
    /*
422
    * Evaluate based on higher precedence wrt to the element.
423
    * TODO: This assumes attributes are sorted before content.
424
    *   Is this 100% correct?
425
    */
426
312k
    if (precedence1 < precedence2)
427
312k
        return(1);
428
857
    else
429
857
        return(-1);
430
312k
      }
431
376k
  }
432
  /*
433
  * Special case: One of the helper-elements is contained by the other.
434
  * <foo>
435
  *   <node2>
436
  *     <node1>Text-1(precedence1 == 2)</node1>
437
  *   </node2>
438
  *   Text-6(precedence2 == 3)
439
  * </foo>
440
  */
441
1.07M
  if ((precedence2 == 3) && (precedence1 > 1)) {
442
113k
      cur = node1->parent;
443
4.26M
      while (cur) {
444
4.16M
    if (cur == node2)
445
5.33k
        return(1);
446
4.15M
    cur = cur->parent;
447
4.15M
      }
448
113k
  }
449
1.06M
  if ((precedence1 == 3) && (precedence2 > 1)) {
450
102k
      cur = node2->parent;
451
3.94M
      while (cur) {
452
3.84M
    if (cur == node1)
453
5.22k
        return(-1);
454
3.83M
    cur = cur->parent;
455
3.83M
      }
456
102k
  }
457
1.06M
    }
458
459
    /*
460
     * Speedup using document order if available.
461
     */
462
5.78M
    if ((node1->type == XML_ELEMENT_NODE) &&
463
5.78M
  (node2->type == XML_ELEMENT_NODE) &&
464
5.78M
  (0 > (ptrdiff_t) node1->content) &&
465
5.78M
  (0 > (ptrdiff_t) node2->content) &&
466
5.78M
  (node1->doc == node2->doc)) {
467
468
1.06M
  l1 = -((ptrdiff_t) node1->content);
469
1.06M
  l2 = -((ptrdiff_t) node2->content);
470
1.06M
  if (l1 < l2)
471
1.04M
      return(1);
472
13.1k
  if (l1 > l2)
473
13.1k
      return(-1);
474
13.1k
    }
475
476
6.55M
turtle_comparison:
477
478
6.55M
    if (node1 == node2->prev)
479
1.82M
  return(1);
480
4.72M
    if (node1 == node2->next)
481
7.03k
  return(-1);
482
    /*
483
     * compute depth to root
484
     */
485
10.6M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
486
6.09M
  if (cur->parent == node1)
487
153k
      return(1);
488
5.93M
  depth2++;
489
5.93M
    }
490
4.56M
    root = cur;
491
10.5M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
492
7.07M
  if (cur->parent == node2)
493
1.09M
      return(-1);
494
5.97M
  depth1++;
495
5.97M
    }
496
    /*
497
     * Distinct document (or distinct entities :-( ) case.
498
     */
499
3.46M
    if (root != cur) {
500
1.08M
  return(-2);
501
1.08M
    }
502
    /*
503
     * get the nearest common ancestor.
504
     */
505
3.19M
    while (depth1 > depth2) {
506
805k
  depth1--;
507
805k
  node1 = node1->parent;
508
805k
    }
509
3.17M
    while (depth2 > depth1) {
510
785k
  depth2--;
511
785k
  node2 = node2->parent;
512
785k
    }
513
3.18M
    while (node1->parent != node2->parent) {
514
795k
  node1 = node1->parent;
515
795k
  node2 = node2->parent;
516
  /* should not happen but just in case ... */
517
795k
  if ((node1 == NULL) || (node2 == NULL))
518
0
      return(-2);
519
795k
    }
520
    /*
521
     * Find who's first.
522
     */
523
2.38M
    if (node1 == node2->prev)
524
10.1k
  return(1);
525
2.37M
    if (node1 == node2->next)
526
806k
  return(-1);
527
    /*
528
     * Speedup using document order if available.
529
     */
530
1.57M
    if ((node1->type == XML_ELEMENT_NODE) &&
531
1.57M
  (node2->type == XML_ELEMENT_NODE) &&
532
1.57M
  (0 > (ptrdiff_t) node1->content) &&
533
1.57M
  (0 > (ptrdiff_t) node2->content) &&
534
1.57M
  (node1->doc == node2->doc)) {
535
536
0
  l1 = -((ptrdiff_t) node1->content);
537
0
  l2 = -((ptrdiff_t) node2->content);
538
0
  if (l1 < l2)
539
0
      return(1);
540
0
  if (l1 > l2)
541
0
      return(-1);
542
0
    }
543
544
10.9M
    for (cur = node1->next;cur != NULL;cur = cur->next)
545
9.42M
  if (cur == node2)
546
22
      return(1);
547
1.57M
    return(-1); /* assume there is no sibling list corruption */
548
1.57M
}
549
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
550
551
/*
552
 * Wrapper for the Timsort algorithm from timsort.h
553
 */
554
#ifdef WITH_TIM_SORT
555
#define SORT_NAME libxml_domnode
556
1.71M
#define SORT_TYPE xmlNodePtr
557
/**
558
 * wrap_cmp:
559
 * @x: a node
560
 * @y: another node
561
 *
562
 * Comparison function for the Timsort implementation
563
 *
564
 * Returns -2 in case of error -1 if first point < second point, 0 if
565
 *         it's the same node, +1 otherwise
566
 */
567
static
568
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
569
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
570
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
571
12.3M
    {
572
12.3M
        int res = xmlXPathCmpNodesExt(x, y);
573
12.3M
        return res == -2 ? res : -res;
574
12.3M
    }
575
#else
576
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
577
    {
578
        int res = xmlXPathCmpNodes(x, y);
579
        return res == -2 ? res : -res;
580
    }
581
#endif
582
12.3M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
583
#include "timsort.h"
584
#endif /* WITH_TIM_SORT */
585
586
/************************************************************************
587
 *                  *
588
 *      Error handling routines       *
589
 *                  *
590
 ************************************************************************/
591
592
/**
593
 * XP_ERRORNULL:
594
 * @X:  the error code
595
 *
596
 * Macro to raise an XPath error and return NULL.
597
 */
598
#define XP_ERRORNULL(X)             \
599
246
    { xmlXPathErr(ctxt, X); return(NULL); }
600
601
/*
602
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603
 */
604
static const char* const xmlXPathErrorMessages[] = {
605
    "Ok\n",
606
    "Number encoding\n",
607
    "Unfinished literal\n",
608
    "Start of literal\n",
609
    "Expected $ for variable reference\n",
610
    "Undefined variable\n",
611
    "Invalid predicate\n",
612
    "Invalid expression\n",
613
    "Missing closing curly brace\n",
614
    "Unregistered function\n",
615
    "Invalid operand\n",
616
    "Invalid type\n",
617
    "Invalid number of arguments\n",
618
    "Invalid context size\n",
619
    "Invalid context position\n",
620
    "Memory allocation error\n",
621
    "Syntax error\n",
622
    "Resource error\n",
623
    "Sub resource error\n",
624
    "Undefined namespace prefix\n",
625
    "Encoding error\n",
626
    "Char out of XML range\n",
627
    "Invalid or incomplete context\n",
628
    "Stack usage error\n",
629
    "Forbidden variable\n",
630
    "Operation limit exceeded\n",
631
    "Recursion limit exceeded\n",
632
    "?? Unknown error ??\n" /* Must be last in the list! */
633
};
634
7.93k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
635
7.93k
       sizeof(xmlXPathErrorMessages[0])) - 1)
636
/**
637
 * xmlXPathErrMemory:
638
 * @ctxt:  an XPath context
639
 * @extra:  extra information
640
 *
641
 * Handle a redefinition of attribute error
642
 */
643
static void
644
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
645
14.8k
{
646
14.8k
    if (ctxt != NULL) {
647
14.7k
        xmlResetError(&ctxt->lastError);
648
14.7k
        if (extra) {
649
14.7k
            xmlChar buf[200];
650
651
14.7k
            xmlStrPrintf(buf, 200,
652
14.7k
                         "Memory allocation failed : %s\n",
653
14.7k
                         extra);
654
14.7k
            ctxt->lastError.message = (char *) xmlStrdup(buf);
655
14.7k
        } else {
656
2
            ctxt->lastError.message = (char *)
657
2
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
658
2
        }
659
14.7k
        ctxt->lastError.domain = XML_FROM_XPATH;
660
14.7k
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
661
14.7k
  if (ctxt->error != NULL)
662
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
663
14.7k
    } else {
664
59
        if (extra)
665
59
            __xmlRaiseError(NULL, NULL, NULL,
666
59
                            NULL, NULL, XML_FROM_XPATH,
667
59
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668
59
                            extra, NULL, NULL, 0, 0,
669
59
                            "Memory allocation failed : %s\n", extra);
670
0
        else
671
0
            __xmlRaiseError(NULL, NULL, NULL,
672
0
                            NULL, NULL, XML_FROM_XPATH,
673
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
674
0
                            NULL, NULL, NULL, 0, 0,
675
0
                            "Memory allocation failed\n");
676
59
    }
677
14.8k
}
678
679
/**
680
 * xmlXPathPErrMemory:
681
 * @ctxt:  an XPath parser context
682
 * @extra:  extra information
683
 *
684
 * Handle a redefinition of attribute error
685
 */
686
static void
687
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
688
14.7k
{
689
14.7k
    if (ctxt == NULL)
690
0
  xmlXPathErrMemory(NULL, extra);
691
14.7k
    else {
692
14.7k
  ctxt->error = XPATH_MEMORY_ERROR;
693
14.7k
  xmlXPathErrMemory(ctxt->context, extra);
694
14.7k
    }
695
14.7k
}
696
697
/**
698
 * xmlXPathErr:
699
 * @ctxt:  a XPath parser context
700
 * @error:  the error code
701
 *
702
 * Handle an XPath error
703
 */
704
void
705
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
706
7.93k
{
707
7.93k
    if ((error < 0) || (error > MAXERRNO))
708
0
  error = MAXERRNO;
709
7.93k
    if (ctxt == NULL) {
710
0
  __xmlRaiseError(NULL, NULL, NULL,
711
0
      NULL, NULL, XML_FROM_XPATH,
712
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713
0
      XML_ERR_ERROR, NULL, 0,
714
0
      NULL, NULL, NULL, 0, 0,
715
0
      "%s", xmlXPathErrorMessages[error]);
716
0
  return;
717
0
    }
718
    /* Only report the first error */
719
7.93k
    if (ctxt->error != 0)
720
2.45k
        return;
721
5.47k
    ctxt->error = error;
722
5.47k
    if (ctxt->context == NULL) {
723
0
  __xmlRaiseError(NULL, NULL, NULL,
724
0
      NULL, NULL, XML_FROM_XPATH,
725
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726
0
      XML_ERR_ERROR, NULL, 0,
727
0
      (const char *) ctxt->base, NULL, NULL,
728
0
      ctxt->cur - ctxt->base, 0,
729
0
      "%s", xmlXPathErrorMessages[error]);
730
0
  return;
731
0
    }
732
733
    /* cleanup current last error */
734
5.47k
    xmlResetError(&ctxt->context->lastError);
735
736
5.47k
    ctxt->context->lastError.domain = XML_FROM_XPATH;
737
5.47k
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738
5.47k
                           XPATH_EXPRESSION_OK;
739
5.47k
    ctxt->context->lastError.level = XML_ERR_ERROR;
740
5.47k
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741
5.47k
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742
5.47k
    ctxt->context->lastError.node = ctxt->context->debugNode;
743
5.47k
    if (ctxt->context->error != NULL) {
744
0
  ctxt->context->error(ctxt->context->userData,
745
0
                       &ctxt->context->lastError);
746
5.47k
    } else {
747
5.47k
  __xmlRaiseError(NULL, NULL, NULL,
748
5.47k
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749
5.47k
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750
5.47k
      XML_ERR_ERROR, NULL, 0,
751
5.47k
      (const char *) ctxt->base, NULL, NULL,
752
5.47k
      ctxt->cur - ctxt->base, 0,
753
5.47k
      "%s", xmlXPathErrorMessages[error]);
754
5.47k
    }
755
756
5.47k
}
757
758
/**
759
 * xmlXPatherror:
760
 * @ctxt:  the XPath Parser context
761
 * @file:  the file name
762
 * @line:  the line number
763
 * @no:  the error number
764
 *
765
 * Formats an error message.
766
 */
767
void
768
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
769
1.19k
              int line ATTRIBUTE_UNUSED, int no) {
770
1.19k
    xmlXPathErr(ctxt, no);
771
1.19k
}
772
773
/**
774
 * xmlXPathCheckOpLimit:
775
 * @ctxt:  the XPath Parser context
776
 * @opCount:  the number of operations to be added
777
 *
778
 * Adds opCount to the running total of operations and returns -1 if the
779
 * operation limit is exceeded. Returns 0 otherwise.
780
 */
781
static int
782
15.5M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783
15.5M
    xmlXPathContextPtr xpctxt = ctxt->context;
784
785
15.5M
    if ((opCount > xpctxt->opLimit) ||
786
15.5M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787
23
        xpctxt->opCount = xpctxt->opLimit;
788
23
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789
23
        return(-1);
790
23
    }
791
792
15.5M
    xpctxt->opCount += opCount;
793
15.5M
    return(0);
794
15.5M
}
795
796
#define OP_LIMIT_EXCEEDED(ctxt, n) \
797
15.5M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
798
799
/************************************************************************
800
 *                  *
801
 *      Utilities         *
802
 *                  *
803
 ************************************************************************/
804
805
/**
806
 * xsltPointerList:
807
 *
808
 * Pointer-list for various purposes.
809
 */
810
typedef struct _xmlPointerList xmlPointerList;
811
typedef xmlPointerList *xmlPointerListPtr;
812
struct _xmlPointerList {
813
    void **items;
814
    int number;
815
    int size;
816
};
817
/*
818
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
819
* and here, we should make the functions public.
820
*/
821
static int
822
xmlPointerListAddSize(xmlPointerListPtr list,
823
           void *item,
824
           int initialSize)
825
4.86M
{
826
4.86M
    if (list->size <= list->number) {
827
1.51k
        void **tmp;
828
1.51k
        size_t newSize;
829
830
1.51k
        if (list->size == 0) {
831
844
            if (initialSize <= 0)
832
0
                initialSize = 1;
833
844
            newSize = initialSize;
834
844
        } else {
835
670
            if (list->size > 50000000) {
836
0
                xmlXPathErrMemory(NULL,
837
0
                    "xmlPointerListAddSize: re-allocating item\n");
838
0
                return(-1);
839
0
            }
840
670
      newSize = list->size * 2;
841
670
        }
842
1.51k
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843
1.51k
  if (tmp == NULL) {
844
0
      xmlXPathErrMemory(NULL,
845
0
    "xmlPointerListAddSize: re-allocating item\n");
846
0
      return(-1);
847
0
  }
848
1.51k
        list->items = tmp;
849
1.51k
        list->size = newSize;
850
1.51k
    }
851
4.86M
    list->items[list->number++] = item;
852
4.86M
    return(0);
853
4.86M
}
854
855
/**
856
 * xsltPointerListCreate:
857
 *
858
 * Creates an xsltPointerList structure.
859
 *
860
 * Returns a xsltPointerList structure or NULL in case of an error.
861
 */
862
static xmlPointerListPtr
863
xmlPointerListCreate(int initialSize)
864
856
{
865
856
    xmlPointerListPtr ret;
866
867
856
    ret = xmlMalloc(sizeof(xmlPointerList));
868
856
    if (ret == NULL) {
869
12
  xmlXPathErrMemory(NULL,
870
12
      "xmlPointerListCreate: allocating item\n");
871
12
  return (NULL);
872
12
    }
873
844
    memset(ret, 0, sizeof(xmlPointerList));
874
844
    if (initialSize > 0) {
875
844
  xmlPointerListAddSize(ret, NULL, initialSize);
876
844
  ret->number = 0;
877
844
    }
878
844
    return (ret);
879
856
}
880
881
/**
882
 * xsltPointerListFree:
883
 *
884
 * Frees the xsltPointerList structure. This does not free
885
 * the content of the list.
886
 */
887
static void
888
xmlPointerListFree(xmlPointerListPtr list)
889
844
{
890
844
    if (list == NULL)
891
0
  return;
892
844
    if (list->items != NULL)
893
844
  xmlFree(list->items);
894
844
    xmlFree(list);
895
844
}
896
897
/************************************************************************
898
 *                  *
899
 *      Parser Types          *
900
 *                  *
901
 ************************************************************************/
902
903
/*
904
 * Types are private:
905
 */
906
907
typedef enum {
908
    XPATH_OP_END=0,
909
    XPATH_OP_AND,
910
    XPATH_OP_OR,
911
    XPATH_OP_EQUAL,
912
    XPATH_OP_CMP,
913
    XPATH_OP_PLUS,
914
    XPATH_OP_MULT,
915
    XPATH_OP_UNION,
916
    XPATH_OP_ROOT,
917
    XPATH_OP_NODE,
918
    XPATH_OP_COLLECT,
919
    XPATH_OP_VALUE, /* 11 */
920
    XPATH_OP_VARIABLE,
921
    XPATH_OP_FUNCTION,
922
    XPATH_OP_ARG,
923
    XPATH_OP_PREDICATE,
924
    XPATH_OP_FILTER, /* 16 */
925
    XPATH_OP_SORT /* 17 */
926
#ifdef LIBXML_XPTR_LOCS_ENABLED
927
    ,XPATH_OP_RANGETO
928
#endif
929
} xmlXPathOp;
930
931
typedef enum {
932
    AXIS_ANCESTOR = 1,
933
    AXIS_ANCESTOR_OR_SELF,
934
    AXIS_ATTRIBUTE,
935
    AXIS_CHILD,
936
    AXIS_DESCENDANT,
937
    AXIS_DESCENDANT_OR_SELF,
938
    AXIS_FOLLOWING,
939
    AXIS_FOLLOWING_SIBLING,
940
    AXIS_NAMESPACE,
941
    AXIS_PARENT,
942
    AXIS_PRECEDING,
943
    AXIS_PRECEDING_SIBLING,
944
    AXIS_SELF
945
} xmlXPathAxisVal;
946
947
typedef enum {
948
    NODE_TEST_NONE = 0,
949
    NODE_TEST_TYPE = 1,
950
    NODE_TEST_PI = 2,
951
    NODE_TEST_ALL = 3,
952
    NODE_TEST_NS = 4,
953
    NODE_TEST_NAME = 5
954
} xmlXPathTestVal;
955
956
typedef enum {
957
    NODE_TYPE_NODE = 0,
958
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
959
    NODE_TYPE_TEXT = XML_TEXT_NODE,
960
    NODE_TYPE_PI = XML_PI_NODE
961
} xmlXPathTypeVal;
962
963
typedef struct _xmlXPathStepOp xmlXPathStepOp;
964
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
965
struct _xmlXPathStepOp {
966
    xmlXPathOp op;    /* The identifier of the operation */
967
    int ch1;      /* First child */
968
    int ch2;      /* Second child */
969
    int value;
970
    int value2;
971
    int value3;
972
    void *value4;
973
    void *value5;
974
    xmlXPathFunction cache;
975
    void *cacheURI;
976
};
977
978
struct _xmlXPathCompExpr {
979
    int nbStep;     /* Number of steps in this expression */
980
    int maxStep;    /* Maximum number of steps allocated */
981
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
982
    int last;     /* index of last step in expression */
983
    xmlChar *expr;    /* the expression being computed */
984
    xmlDictPtr dict;    /* the dictionary to use if any */
985
#ifdef DEBUG_EVAL_COUNTS
986
    int nb;
987
    xmlChar *string;
988
#endif
989
#ifdef XPATH_STREAMING
990
    xmlPatternPtr stream;
991
#endif
992
};
993
994
/************************************************************************
995
 *                  *
996
 *      Forward declarations        *
997
 *                  *
998
 ************************************************************************/
999
static void
1000
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
1001
static void
1002
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
1003
static int
1004
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1005
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1006
static int
1007
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1008
          xmlXPathStepOpPtr op,
1009
          int isPredicate);
1010
static void
1011
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1012
1013
/************************************************************************
1014
 *                  *
1015
 *      Parser Type functions       *
1016
 *                  *
1017
 ************************************************************************/
1018
1019
/**
1020
 * xmlXPathNewCompExpr:
1021
 *
1022
 * Create a new Xpath component
1023
 *
1024
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1025
 */
1026
static xmlXPathCompExprPtr
1027
6.10k
xmlXPathNewCompExpr(void) {
1028
6.10k
    xmlXPathCompExprPtr cur;
1029
1030
6.10k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031
6.10k
    if (cur == NULL) {
1032
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1033
0
  return(NULL);
1034
0
    }
1035
6.10k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1036
6.10k
    cur->maxStep = 10;
1037
6.10k
    cur->nbStep = 0;
1038
6.10k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039
6.10k
                                     sizeof(xmlXPathStepOp));
1040
6.10k
    if (cur->steps == NULL) {
1041
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1042
0
  xmlFree(cur);
1043
0
  return(NULL);
1044
0
    }
1045
6.10k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046
6.10k
    cur->last = -1;
1047
#ifdef DEBUG_EVAL_COUNTS
1048
    cur->nb = 0;
1049
#endif
1050
6.10k
    return(cur);
1051
6.10k
}
1052
1053
/**
1054
 * xmlXPathFreeCompExpr:
1055
 * @comp:  an XPATH comp
1056
 *
1057
 * Free up the memory allocated by @comp
1058
 */
1059
void
1060
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1061
6.10k
{
1062
6.10k
    xmlXPathStepOpPtr op;
1063
6.10k
    int i;
1064
1065
6.10k
    if (comp == NULL)
1066
0
        return;
1067
6.10k
    if (comp->dict == NULL) {
1068
17.6M
  for (i = 0; i < comp->nbStep; i++) {
1069
17.6M
      op = &comp->steps[i];
1070
17.6M
      if (op->value4 != NULL) {
1071
7.92k
    if (op->op == XPATH_OP_VALUE)
1072
7.03k
        xmlXPathFreeObject(op->value4);
1073
887
    else
1074
887
        xmlFree(op->value4);
1075
7.92k
      }
1076
17.6M
      if (op->value5 != NULL)
1077
4.69M
    xmlFree(op->value5);
1078
17.6M
  }
1079
6.10k
    } else {
1080
0
  for (i = 0; i < comp->nbStep; i++) {
1081
0
      op = &comp->steps[i];
1082
0
      if (op->value4 != NULL) {
1083
0
    if (op->op == XPATH_OP_VALUE)
1084
0
        xmlXPathFreeObject(op->value4);
1085
0
      }
1086
0
  }
1087
0
        xmlDictFree(comp->dict);
1088
0
    }
1089
6.10k
    if (comp->steps != NULL) {
1090
6.10k
        xmlFree(comp->steps);
1091
6.10k
    }
1092
#ifdef DEBUG_EVAL_COUNTS
1093
    if (comp->string != NULL) {
1094
        xmlFree(comp->string);
1095
    }
1096
#endif
1097
6.10k
#ifdef XPATH_STREAMING
1098
6.10k
    if (comp->stream != NULL) {
1099
413
        xmlFreePatternList(comp->stream);
1100
413
    }
1101
6.10k
#endif
1102
6.10k
    if (comp->expr != NULL) {
1103
403
        xmlFree(comp->expr);
1104
403
    }
1105
1106
6.10k
    xmlFree(comp);
1107
6.10k
}
1108
1109
/**
1110
 * xmlXPathCompExprAdd:
1111
 * @comp:  the compiled expression
1112
 * @ch1: first child index
1113
 * @ch2: second child index
1114
 * @op:  an op
1115
 * @value:  the first int value
1116
 * @value2:  the second int value
1117
 * @value3:  the third int value
1118
 * @value4:  the first string value
1119
 * @value5:  the second string value
1120
 *
1121
 * Add a step to an XPath Compiled Expression
1122
 *
1123
 * Returns -1 in case of failure, the index otherwise
1124
 */
1125
static int
1126
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1127
   xmlXPathOp op, int value,
1128
17.6M
   int value2, int value3, void *value4, void *value5) {
1129
17.6M
    xmlXPathCompExprPtr comp = ctxt->comp;
1130
17.6M
    if (comp->nbStep >= comp->maxStep) {
1131
15.4k
  xmlXPathStepOp *real;
1132
1133
15.4k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1134
14.7k
      xmlXPathPErrMemory(ctxt, "adding step\n");
1135
14.7k
      return(-1);
1136
14.7k
        }
1137
757
  comp->maxStep *= 2;
1138
757
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139
757
                          comp->maxStep * sizeof(xmlXPathStepOp));
1140
757
  if (real == NULL) {
1141
0
      comp->maxStep /= 2;
1142
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1143
0
      return(-1);
1144
0
  }
1145
757
  comp->steps = real;
1146
757
    }
1147
17.6M
    comp->last = comp->nbStep;
1148
17.6M
    comp->steps[comp->nbStep].ch1 = ch1;
1149
17.6M
    comp->steps[comp->nbStep].ch2 = ch2;
1150
17.6M
    comp->steps[comp->nbStep].op = op;
1151
17.6M
    comp->steps[comp->nbStep].value = value;
1152
17.6M
    comp->steps[comp->nbStep].value2 = value2;
1153
17.6M
    comp->steps[comp->nbStep].value3 = value3;
1154
17.6M
    if ((comp->dict != NULL) &&
1155
17.6M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1156
0
   (op == XPATH_OP_COLLECT))) {
1157
0
        if (value4 != NULL) {
1158
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1159
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1160
0
      xmlFree(value4);
1161
0
  } else
1162
0
      comp->steps[comp->nbStep].value4 = NULL;
1163
0
        if (value5 != NULL) {
1164
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1165
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1166
0
      xmlFree(value5);
1167
0
  } else
1168
0
      comp->steps[comp->nbStep].value5 = NULL;
1169
17.6M
    } else {
1170
17.6M
  comp->steps[comp->nbStep].value4 = value4;
1171
17.6M
  comp->steps[comp->nbStep].value5 = value5;
1172
17.6M
    }
1173
17.6M
    comp->steps[comp->nbStep].cache = NULL;
1174
17.6M
    return(comp->nbStep++);
1175
17.6M
}
1176
1177
/**
1178
 * xmlXPathCompSwap:
1179
 * @comp:  the compiled expression
1180
 * @op: operation index
1181
 *
1182
 * Swaps 2 operations in the compiled expression
1183
 */
1184
static void
1185
6
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186
6
    int tmp;
1187
1188
#ifndef LIBXML_THREAD_ENABLED
1189
    /*
1190
     * Since this manipulates possibly shared variables, this is
1191
     * disabled if one detects that the library is used in a multithreaded
1192
     * application
1193
     */
1194
    if (xmlXPathDisableOptimizer)
1195
  return;
1196
#endif
1197
1198
6
    tmp = op->ch1;
1199
6
    op->ch1 = op->ch2;
1200
6
    op->ch2 = tmp;
1201
6
}
1202
1203
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204
4.94M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1205
4.94M
                  (op), (val), (val2), (val3), (val4), (val5))
1206
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1207
8.54k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1208
8.54k
                  (op), (val), (val2), (val3), (val4), (val5))
1209
1210
8.43M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1211
8.43M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212
1213
2.22k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1214
2.22k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215
1216
4.22M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1217
4.22M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1218
4.22M
      (val), (val2), 0 ,NULL ,NULL)
1219
1220
/************************************************************************
1221
 *                  *
1222
 *    XPath object cache structures       *
1223
 *                  *
1224
 ************************************************************************/
1225
1226
/* #define XP_DEFAULT_CACHE_ON */
1227
1228
12.2k
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1229
1230
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1231
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1232
struct _xmlXPathContextCache {
1233
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1234
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1235
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1236
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1237
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1238
    int maxNodeset;
1239
    int maxString;
1240
    int maxBoolean;
1241
    int maxNumber;
1242
    int maxMisc;
1243
#ifdef XP_DEBUG_OBJ_USAGE
1244
    int dbgCachedAll;
1245
    int dbgCachedNodeset;
1246
    int dbgCachedString;
1247
    int dbgCachedBool;
1248
    int dbgCachedNumber;
1249
    int dbgCachedPoint;
1250
    int dbgCachedRange;
1251
    int dbgCachedLocset;
1252
    int dbgCachedUsers;
1253
    int dbgCachedXSLTTree;
1254
    int dbgCachedUndefined;
1255
1256
1257
    int dbgReusedAll;
1258
    int dbgReusedNodeset;
1259
    int dbgReusedString;
1260
    int dbgReusedBool;
1261
    int dbgReusedNumber;
1262
    int dbgReusedPoint;
1263
    int dbgReusedRange;
1264
    int dbgReusedLocset;
1265
    int dbgReusedUsers;
1266
    int dbgReusedXSLTTree;
1267
    int dbgReusedUndefined;
1268
1269
#endif
1270
};
1271
1272
/************************************************************************
1273
 *                  *
1274
 *    Debugging related functions       *
1275
 *                  *
1276
 ************************************************************************/
1277
1278
#define STRANGE             \
1279
0
    xmlGenericError(xmlGenericErrorContext,       \
1280
0
      "Internal error at %s:%d\n",        \
1281
0
            __FILE__, __LINE__);
1282
1283
#ifdef LIBXML_DEBUG_ENABLED
1284
static void
1285
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1286
0
    int i;
1287
0
    char shift[100];
1288
1289
0
    for (i = 0;((i < depth) && (i < 25));i++)
1290
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1291
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1292
0
    if (cur == NULL) {
1293
0
  fprintf(output, "%s", shift);
1294
0
  fprintf(output, "Node is NULL !\n");
1295
0
  return;
1296
1297
0
    }
1298
1299
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1300
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1301
0
  fprintf(output, "%s", shift);
1302
0
  fprintf(output, " /\n");
1303
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1304
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1305
0
    else
1306
0
  xmlDebugDumpOneNode(output, cur, depth);
1307
0
}
1308
static void
1309
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1310
0
    xmlNodePtr tmp;
1311
0
    int i;
1312
0
    char shift[100];
1313
1314
0
    for (i = 0;((i < depth) && (i < 25));i++)
1315
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1316
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1317
0
    if (cur == NULL) {
1318
0
  fprintf(output, "%s", shift);
1319
0
  fprintf(output, "Node is NULL !\n");
1320
0
  return;
1321
1322
0
    }
1323
1324
0
    while (cur != NULL) {
1325
0
  tmp = cur;
1326
0
  cur = cur->next;
1327
0
  xmlDebugDumpOneNode(output, tmp, depth);
1328
0
    }
1329
0
}
1330
1331
static void
1332
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1333
0
    int i;
1334
0
    char shift[100];
1335
1336
0
    for (i = 0;((i < depth) && (i < 25));i++)
1337
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1338
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1339
1340
0
    if (cur == NULL) {
1341
0
  fprintf(output, "%s", shift);
1342
0
  fprintf(output, "NodeSet is NULL !\n");
1343
0
  return;
1344
1345
0
    }
1346
1347
0
    if (cur != NULL) {
1348
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1349
0
  for (i = 0;i < cur->nodeNr;i++) {
1350
0
      fprintf(output, "%s", shift);
1351
0
      fprintf(output, "%d", i + 1);
1352
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1353
0
  }
1354
0
    }
1355
0
}
1356
1357
static void
1358
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1359
0
    int i;
1360
0
    char shift[100];
1361
1362
0
    for (i = 0;((i < depth) && (i < 25));i++)
1363
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1364
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1365
1366
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1367
0
  fprintf(output, "%s", shift);
1368
0
  fprintf(output, "Value Tree is NULL !\n");
1369
0
  return;
1370
1371
0
    }
1372
1373
0
    fprintf(output, "%s", shift);
1374
0
    fprintf(output, "%d", i + 1);
1375
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1376
0
}
1377
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1378
static void
1379
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1380
    int i;
1381
    char shift[100];
1382
1383
    for (i = 0;((i < depth) && (i < 25));i++)
1384
        shift[2 * i] = shift[2 * i + 1] = ' ';
1385
    shift[2 * i] = shift[2 * i + 1] = 0;
1386
1387
    if (cur == NULL) {
1388
  fprintf(output, "%s", shift);
1389
  fprintf(output, "LocationSet is NULL !\n");
1390
  return;
1391
1392
    }
1393
1394
    for (i = 0;i < cur->locNr;i++) {
1395
  fprintf(output, "%s", shift);
1396
        fprintf(output, "%d : ", i + 1);
1397
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1398
    }
1399
}
1400
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1401
1402
/**
1403
 * xmlXPathDebugDumpObject:
1404
 * @output:  the FILE * to dump the output
1405
 * @cur:  the object to inspect
1406
 * @depth:  indentation level
1407
 *
1408
 * Dump the content of the object for debugging purposes
1409
 */
1410
void
1411
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1412
0
    int i;
1413
0
    char shift[100];
1414
1415
0
    if (output == NULL) return;
1416
1417
0
    for (i = 0;((i < depth) && (i < 25));i++)
1418
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1419
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1420
1421
1422
0
    fprintf(output, "%s", shift);
1423
1424
0
    if (cur == NULL) {
1425
0
        fprintf(output, "Object is empty (NULL)\n");
1426
0
  return;
1427
0
    }
1428
0
    switch(cur->type) {
1429
0
        case XPATH_UNDEFINED:
1430
0
      fprintf(output, "Object is uninitialized\n");
1431
0
      break;
1432
0
        case XPATH_NODESET:
1433
0
      fprintf(output, "Object is a Node Set :\n");
1434
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
  case XPATH_XSLT_TREE:
1437
0
      fprintf(output, "Object is an XSLT value tree :\n");
1438
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1439
0
      break;
1440
0
        case XPATH_BOOLEAN:
1441
0
      fprintf(output, "Object is a Boolean : ");
1442
0
      if (cur->boolval) fprintf(output, "true\n");
1443
0
      else fprintf(output, "false\n");
1444
0
      break;
1445
0
        case XPATH_NUMBER:
1446
0
      switch (xmlXPathIsInf(cur->floatval)) {
1447
0
      case 1:
1448
0
    fprintf(output, "Object is a number : Infinity\n");
1449
0
    break;
1450
0
      case -1:
1451
0
    fprintf(output, "Object is a number : -Infinity\n");
1452
0
    break;
1453
0
      default:
1454
0
    if (xmlXPathIsNaN(cur->floatval)) {
1455
0
        fprintf(output, "Object is a number : NaN\n");
1456
0
    } else if (cur->floatval == 0) {
1457
                    /* Omit sign for negative zero. */
1458
0
        fprintf(output, "Object is a number : 0\n");
1459
0
    } else {
1460
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1461
0
    }
1462
0
      }
1463
0
      break;
1464
0
        case XPATH_STRING:
1465
0
      fprintf(output, "Object is a string : ");
1466
0
      xmlDebugDumpString(output, cur->stringval);
1467
0
      fprintf(output, "\n");
1468
0
      break;
1469
#ifdef LIBXML_XPTR_LOCS_ENABLED
1470
  case XPATH_POINT:
1471
      fprintf(output, "Object is a point : index %d in node", cur->index);
1472
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1473
      fprintf(output, "\n");
1474
      break;
1475
  case XPATH_RANGE:
1476
      if ((cur->user2 == NULL) ||
1477
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1478
    fprintf(output, "Object is a collapsed range :\n");
1479
    fprintf(output, "%s", shift);
1480
    if (cur->index >= 0)
1481
        fprintf(output, "index %d in ", cur->index);
1482
    fprintf(output, "node\n");
1483
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1484
                    depth + 1);
1485
      } else  {
1486
    fprintf(output, "Object is a range :\n");
1487
    fprintf(output, "%s", shift);
1488
    fprintf(output, "From ");
1489
    if (cur->index >= 0)
1490
        fprintf(output, "index %d in ", cur->index);
1491
    fprintf(output, "node\n");
1492
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1493
                    depth + 1);
1494
    fprintf(output, "%s", shift);
1495
    fprintf(output, "To ");
1496
    if (cur->index2 >= 0)
1497
        fprintf(output, "index %d in ", cur->index2);
1498
    fprintf(output, "node\n");
1499
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1500
                    depth + 1);
1501
    fprintf(output, "\n");
1502
      }
1503
      break;
1504
  case XPATH_LOCATIONSET:
1505
      fprintf(output, "Object is a Location Set:\n");
1506
      xmlXPathDebugDumpLocationSet(output,
1507
        (xmlLocationSetPtr) cur->user, depth);
1508
      break;
1509
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1510
0
  case XPATH_USERS:
1511
0
      fprintf(output, "Object is user defined\n");
1512
0
      break;
1513
0
    }
1514
0
}
1515
1516
static void
1517
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1518
0
                       xmlXPathStepOpPtr op, int depth) {
1519
0
    int i;
1520
0
    char shift[100];
1521
1522
0
    for (i = 0;((i < depth) && (i < 25));i++)
1523
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1524
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1525
1526
0
    fprintf(output, "%s", shift);
1527
0
    if (op == NULL) {
1528
0
  fprintf(output, "Step is NULL\n");
1529
0
  return;
1530
0
    }
1531
0
    switch (op->op) {
1532
0
        case XPATH_OP_END:
1533
0
      fprintf(output, "END"); break;
1534
0
        case XPATH_OP_AND:
1535
0
      fprintf(output, "AND"); break;
1536
0
        case XPATH_OP_OR:
1537
0
      fprintf(output, "OR"); break;
1538
0
        case XPATH_OP_EQUAL:
1539
0
       if (op->value)
1540
0
     fprintf(output, "EQUAL =");
1541
0
       else
1542
0
     fprintf(output, "EQUAL !=");
1543
0
       break;
1544
0
        case XPATH_OP_CMP:
1545
0
       if (op->value)
1546
0
     fprintf(output, "CMP <");
1547
0
       else
1548
0
     fprintf(output, "CMP >");
1549
0
       if (!op->value2)
1550
0
     fprintf(output, "=");
1551
0
       break;
1552
0
        case XPATH_OP_PLUS:
1553
0
       if (op->value == 0)
1554
0
     fprintf(output, "PLUS -");
1555
0
       else if (op->value == 1)
1556
0
     fprintf(output, "PLUS +");
1557
0
       else if (op->value == 2)
1558
0
     fprintf(output, "PLUS unary -");
1559
0
       else if (op->value == 3)
1560
0
     fprintf(output, "PLUS unary - -");
1561
0
       break;
1562
0
        case XPATH_OP_MULT:
1563
0
       if (op->value == 0)
1564
0
     fprintf(output, "MULT *");
1565
0
       else if (op->value == 1)
1566
0
     fprintf(output, "MULT div");
1567
0
       else
1568
0
     fprintf(output, "MULT mod");
1569
0
       break;
1570
0
        case XPATH_OP_UNION:
1571
0
       fprintf(output, "UNION"); break;
1572
0
        case XPATH_OP_ROOT:
1573
0
       fprintf(output, "ROOT"); break;
1574
0
        case XPATH_OP_NODE:
1575
0
       fprintf(output, "NODE"); break;
1576
0
        case XPATH_OP_SORT:
1577
0
       fprintf(output, "SORT"); break;
1578
0
        case XPATH_OP_COLLECT: {
1579
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1580
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1581
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1582
0
      const xmlChar *prefix = op->value4;
1583
0
      const xmlChar *name = op->value5;
1584
1585
0
      fprintf(output, "COLLECT ");
1586
0
      switch (axis) {
1587
0
    case AXIS_ANCESTOR:
1588
0
        fprintf(output, " 'ancestors' "); break;
1589
0
    case AXIS_ANCESTOR_OR_SELF:
1590
0
        fprintf(output, " 'ancestors-or-self' "); break;
1591
0
    case AXIS_ATTRIBUTE:
1592
0
        fprintf(output, " 'attributes' "); break;
1593
0
    case AXIS_CHILD:
1594
0
        fprintf(output, " 'child' "); break;
1595
0
    case AXIS_DESCENDANT:
1596
0
        fprintf(output, " 'descendant' "); break;
1597
0
    case AXIS_DESCENDANT_OR_SELF:
1598
0
        fprintf(output, " 'descendant-or-self' "); break;
1599
0
    case AXIS_FOLLOWING:
1600
0
        fprintf(output, " 'following' "); break;
1601
0
    case AXIS_FOLLOWING_SIBLING:
1602
0
        fprintf(output, " 'following-siblings' "); break;
1603
0
    case AXIS_NAMESPACE:
1604
0
        fprintf(output, " 'namespace' "); break;
1605
0
    case AXIS_PARENT:
1606
0
        fprintf(output, " 'parent' "); break;
1607
0
    case AXIS_PRECEDING:
1608
0
        fprintf(output, " 'preceding' "); break;
1609
0
    case AXIS_PRECEDING_SIBLING:
1610
0
        fprintf(output, " 'preceding-sibling' "); break;
1611
0
    case AXIS_SELF:
1612
0
        fprintf(output, " 'self' "); break;
1613
0
      }
1614
0
      switch (test) {
1615
0
                case NODE_TEST_NONE:
1616
0
        fprintf(output, "'none' "); break;
1617
0
                case NODE_TEST_TYPE:
1618
0
        fprintf(output, "'type' "); break;
1619
0
                case NODE_TEST_PI:
1620
0
        fprintf(output, "'PI' "); break;
1621
0
                case NODE_TEST_ALL:
1622
0
        fprintf(output, "'all' "); break;
1623
0
                case NODE_TEST_NS:
1624
0
        fprintf(output, "'namespace' "); break;
1625
0
                case NODE_TEST_NAME:
1626
0
        fprintf(output, "'name' "); break;
1627
0
      }
1628
0
      switch (type) {
1629
0
                case NODE_TYPE_NODE:
1630
0
        fprintf(output, "'node' "); break;
1631
0
                case NODE_TYPE_COMMENT:
1632
0
        fprintf(output, "'comment' "); break;
1633
0
                case NODE_TYPE_TEXT:
1634
0
        fprintf(output, "'text' "); break;
1635
0
                case NODE_TYPE_PI:
1636
0
        fprintf(output, "'PI' "); break;
1637
0
      }
1638
0
      if (prefix != NULL)
1639
0
    fprintf(output, "%s:", prefix);
1640
0
      if (name != NULL)
1641
0
    fprintf(output, "%s", (const char *) name);
1642
0
      break;
1643
1644
0
        }
1645
0
  case XPATH_OP_VALUE: {
1646
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1647
1648
0
      fprintf(output, "ELEM ");
1649
0
      xmlXPathDebugDumpObject(output, object, 0);
1650
0
      goto finish;
1651
0
  }
1652
0
  case XPATH_OP_VARIABLE: {
1653
0
      const xmlChar *prefix = op->value5;
1654
0
      const xmlChar *name = op->value4;
1655
1656
0
      if (prefix != NULL)
1657
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1658
0
      else
1659
0
    fprintf(output, "VARIABLE %s", name);
1660
0
      break;
1661
0
  }
1662
0
  case XPATH_OP_FUNCTION: {
1663
0
      int nbargs = op->value;
1664
0
      const xmlChar *prefix = op->value5;
1665
0
      const xmlChar *name = op->value4;
1666
1667
0
      if (prefix != NULL)
1668
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1669
0
      prefix, name, nbargs);
1670
0
      else
1671
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1672
0
      break;
1673
0
  }
1674
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1675
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1676
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1677
#ifdef LIBXML_XPTR_LOCS_ENABLED
1678
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1679
#endif
1680
0
  default:
1681
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1682
0
    }
1683
0
    fprintf(output, "\n");
1684
0
finish:
1685
0
    if (op->ch1 >= 0)
1686
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1687
0
    if (op->ch2 >= 0)
1688
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1689
0
}
1690
1691
/**
1692
 * xmlXPathDebugDumpCompExpr:
1693
 * @output:  the FILE * for the output
1694
 * @comp:  the precompiled XPath expression
1695
 * @depth:  the indentation level.
1696
 *
1697
 * Dumps the tree of the compiled XPath expression.
1698
 */
1699
void
1700
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1701
0
                    int depth) {
1702
0
    int i;
1703
0
    char shift[100];
1704
1705
0
    if ((output == NULL) || (comp == NULL)) return;
1706
1707
0
    for (i = 0;((i < depth) && (i < 25));i++)
1708
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1709
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1710
1711
0
    fprintf(output, "%s", shift);
1712
1713
0
#ifdef XPATH_STREAMING
1714
0
    if (comp->stream) {
1715
0
        fprintf(output, "Streaming Expression\n");
1716
0
    } else
1717
0
#endif
1718
0
    {
1719
0
        fprintf(output, "Compiled Expression : %d elements\n",
1720
0
                comp->nbStep);
1721
0
        i = comp->last;
1722
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1723
0
    }
1724
0
}
1725
1726
#ifdef XP_DEBUG_OBJ_USAGE
1727
1728
/*
1729
* XPath object usage related debugging variables.
1730
*/
1731
static int xmlXPathDebugObjCounterUndefined = 0;
1732
static int xmlXPathDebugObjCounterNodeset = 0;
1733
static int xmlXPathDebugObjCounterBool = 0;
1734
static int xmlXPathDebugObjCounterNumber = 0;
1735
static int xmlXPathDebugObjCounterString = 0;
1736
static int xmlXPathDebugObjCounterPoint = 0;
1737
static int xmlXPathDebugObjCounterRange = 0;
1738
static int xmlXPathDebugObjCounterLocset = 0;
1739
static int xmlXPathDebugObjCounterUsers = 0;
1740
static int xmlXPathDebugObjCounterXSLTTree = 0;
1741
static int xmlXPathDebugObjCounterAll = 0;
1742
1743
static int xmlXPathDebugObjTotalUndefined = 0;
1744
static int xmlXPathDebugObjTotalNodeset = 0;
1745
static int xmlXPathDebugObjTotalBool = 0;
1746
static int xmlXPathDebugObjTotalNumber = 0;
1747
static int xmlXPathDebugObjTotalString = 0;
1748
static int xmlXPathDebugObjTotalPoint = 0;
1749
static int xmlXPathDebugObjTotalRange = 0;
1750
static int xmlXPathDebugObjTotalLocset = 0;
1751
static int xmlXPathDebugObjTotalUsers = 0;
1752
static int xmlXPathDebugObjTotalXSLTTree = 0;
1753
static int xmlXPathDebugObjTotalAll = 0;
1754
1755
static int xmlXPathDebugObjMaxUndefined = 0;
1756
static int xmlXPathDebugObjMaxNodeset = 0;
1757
static int xmlXPathDebugObjMaxBool = 0;
1758
static int xmlXPathDebugObjMaxNumber = 0;
1759
static int xmlXPathDebugObjMaxString = 0;
1760
static int xmlXPathDebugObjMaxPoint = 0;
1761
static int xmlXPathDebugObjMaxRange = 0;
1762
static int xmlXPathDebugObjMaxLocset = 0;
1763
static int xmlXPathDebugObjMaxUsers = 0;
1764
static int xmlXPathDebugObjMaxXSLTTree = 0;
1765
static int xmlXPathDebugObjMaxAll = 0;
1766
1767
static void
1768
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1769
{
1770
    if (ctxt != NULL) {
1771
  if (ctxt->cache != NULL) {
1772
      xmlXPathContextCachePtr cache =
1773
    (xmlXPathContextCachePtr) ctxt->cache;
1774
1775
      cache->dbgCachedAll = 0;
1776
      cache->dbgCachedNodeset = 0;
1777
      cache->dbgCachedString = 0;
1778
      cache->dbgCachedBool = 0;
1779
      cache->dbgCachedNumber = 0;
1780
      cache->dbgCachedPoint = 0;
1781
      cache->dbgCachedRange = 0;
1782
      cache->dbgCachedLocset = 0;
1783
      cache->dbgCachedUsers = 0;
1784
      cache->dbgCachedXSLTTree = 0;
1785
      cache->dbgCachedUndefined = 0;
1786
1787
      cache->dbgReusedAll = 0;
1788
      cache->dbgReusedNodeset = 0;
1789
      cache->dbgReusedString = 0;
1790
      cache->dbgReusedBool = 0;
1791
      cache->dbgReusedNumber = 0;
1792
      cache->dbgReusedPoint = 0;
1793
      cache->dbgReusedRange = 0;
1794
      cache->dbgReusedLocset = 0;
1795
      cache->dbgReusedUsers = 0;
1796
      cache->dbgReusedXSLTTree = 0;
1797
      cache->dbgReusedUndefined = 0;
1798
  }
1799
    }
1800
1801
    xmlXPathDebugObjCounterUndefined = 0;
1802
    xmlXPathDebugObjCounterNodeset = 0;
1803
    xmlXPathDebugObjCounterBool = 0;
1804
    xmlXPathDebugObjCounterNumber = 0;
1805
    xmlXPathDebugObjCounterString = 0;
1806
    xmlXPathDebugObjCounterPoint = 0;
1807
    xmlXPathDebugObjCounterRange = 0;
1808
    xmlXPathDebugObjCounterLocset = 0;
1809
    xmlXPathDebugObjCounterUsers = 0;
1810
    xmlXPathDebugObjCounterXSLTTree = 0;
1811
    xmlXPathDebugObjCounterAll = 0;
1812
1813
    xmlXPathDebugObjTotalUndefined = 0;
1814
    xmlXPathDebugObjTotalNodeset = 0;
1815
    xmlXPathDebugObjTotalBool = 0;
1816
    xmlXPathDebugObjTotalNumber = 0;
1817
    xmlXPathDebugObjTotalString = 0;
1818
    xmlXPathDebugObjTotalPoint = 0;
1819
    xmlXPathDebugObjTotalRange = 0;
1820
    xmlXPathDebugObjTotalLocset = 0;
1821
    xmlXPathDebugObjTotalUsers = 0;
1822
    xmlXPathDebugObjTotalXSLTTree = 0;
1823
    xmlXPathDebugObjTotalAll = 0;
1824
1825
    xmlXPathDebugObjMaxUndefined = 0;
1826
    xmlXPathDebugObjMaxNodeset = 0;
1827
    xmlXPathDebugObjMaxBool = 0;
1828
    xmlXPathDebugObjMaxNumber = 0;
1829
    xmlXPathDebugObjMaxString = 0;
1830
    xmlXPathDebugObjMaxPoint = 0;
1831
    xmlXPathDebugObjMaxRange = 0;
1832
    xmlXPathDebugObjMaxLocset = 0;
1833
    xmlXPathDebugObjMaxUsers = 0;
1834
    xmlXPathDebugObjMaxXSLTTree = 0;
1835
    xmlXPathDebugObjMaxAll = 0;
1836
1837
}
1838
1839
static void
1840
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1841
            xmlXPathObjectType objType)
1842
{
1843
    int isCached = 0;
1844
1845
    if (ctxt != NULL) {
1846
  if (ctxt->cache != NULL) {
1847
      xmlXPathContextCachePtr cache =
1848
    (xmlXPathContextCachePtr) ctxt->cache;
1849
1850
      isCached = 1;
1851
1852
      cache->dbgReusedAll++;
1853
      switch (objType) {
1854
    case XPATH_UNDEFINED:
1855
        cache->dbgReusedUndefined++;
1856
        break;
1857
    case XPATH_NODESET:
1858
        cache->dbgReusedNodeset++;
1859
        break;
1860
    case XPATH_BOOLEAN:
1861
        cache->dbgReusedBool++;
1862
        break;
1863
    case XPATH_NUMBER:
1864
        cache->dbgReusedNumber++;
1865
        break;
1866
    case XPATH_STRING:
1867
        cache->dbgReusedString++;
1868
        break;
1869
#ifdef LIBXML_XPTR_LOCS_ENABLED
1870
    case XPATH_POINT:
1871
        cache->dbgReusedPoint++;
1872
        break;
1873
    case XPATH_RANGE:
1874
        cache->dbgReusedRange++;
1875
        break;
1876
    case XPATH_LOCATIONSET:
1877
        cache->dbgReusedLocset++;
1878
        break;
1879
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1880
    case XPATH_USERS:
1881
        cache->dbgReusedUsers++;
1882
        break;
1883
    case XPATH_XSLT_TREE:
1884
        cache->dbgReusedXSLTTree++;
1885
        break;
1886
    default:
1887
        break;
1888
      }
1889
  }
1890
    }
1891
1892
    switch (objType) {
1893
  case XPATH_UNDEFINED:
1894
      if (! isCached)
1895
    xmlXPathDebugObjTotalUndefined++;
1896
      xmlXPathDebugObjCounterUndefined++;
1897
      if (xmlXPathDebugObjCounterUndefined >
1898
    xmlXPathDebugObjMaxUndefined)
1899
    xmlXPathDebugObjMaxUndefined =
1900
        xmlXPathDebugObjCounterUndefined;
1901
      break;
1902
  case XPATH_NODESET:
1903
      if (! isCached)
1904
    xmlXPathDebugObjTotalNodeset++;
1905
      xmlXPathDebugObjCounterNodeset++;
1906
      if (xmlXPathDebugObjCounterNodeset >
1907
    xmlXPathDebugObjMaxNodeset)
1908
    xmlXPathDebugObjMaxNodeset =
1909
        xmlXPathDebugObjCounterNodeset;
1910
      break;
1911
  case XPATH_BOOLEAN:
1912
      if (! isCached)
1913
    xmlXPathDebugObjTotalBool++;
1914
      xmlXPathDebugObjCounterBool++;
1915
      if (xmlXPathDebugObjCounterBool >
1916
    xmlXPathDebugObjMaxBool)
1917
    xmlXPathDebugObjMaxBool =
1918
        xmlXPathDebugObjCounterBool;
1919
      break;
1920
  case XPATH_NUMBER:
1921
      if (! isCached)
1922
    xmlXPathDebugObjTotalNumber++;
1923
      xmlXPathDebugObjCounterNumber++;
1924
      if (xmlXPathDebugObjCounterNumber >
1925
    xmlXPathDebugObjMaxNumber)
1926
    xmlXPathDebugObjMaxNumber =
1927
        xmlXPathDebugObjCounterNumber;
1928
      break;
1929
  case XPATH_STRING:
1930
      if (! isCached)
1931
    xmlXPathDebugObjTotalString++;
1932
      xmlXPathDebugObjCounterString++;
1933
      if (xmlXPathDebugObjCounterString >
1934
    xmlXPathDebugObjMaxString)
1935
    xmlXPathDebugObjMaxString =
1936
        xmlXPathDebugObjCounterString;
1937
      break;
1938
#ifdef LIBXML_XPTR_LOCS_ENABLED
1939
  case XPATH_POINT:
1940
      if (! isCached)
1941
    xmlXPathDebugObjTotalPoint++;
1942
      xmlXPathDebugObjCounterPoint++;
1943
      if (xmlXPathDebugObjCounterPoint >
1944
    xmlXPathDebugObjMaxPoint)
1945
    xmlXPathDebugObjMaxPoint =
1946
        xmlXPathDebugObjCounterPoint;
1947
      break;
1948
  case XPATH_RANGE:
1949
      if (! isCached)
1950
    xmlXPathDebugObjTotalRange++;
1951
      xmlXPathDebugObjCounterRange++;
1952
      if (xmlXPathDebugObjCounterRange >
1953
    xmlXPathDebugObjMaxRange)
1954
    xmlXPathDebugObjMaxRange =
1955
        xmlXPathDebugObjCounterRange;
1956
      break;
1957
  case XPATH_LOCATIONSET:
1958
      if (! isCached)
1959
    xmlXPathDebugObjTotalLocset++;
1960
      xmlXPathDebugObjCounterLocset++;
1961
      if (xmlXPathDebugObjCounterLocset >
1962
    xmlXPathDebugObjMaxLocset)
1963
    xmlXPathDebugObjMaxLocset =
1964
        xmlXPathDebugObjCounterLocset;
1965
      break;
1966
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1967
  case XPATH_USERS:
1968
      if (! isCached)
1969
    xmlXPathDebugObjTotalUsers++;
1970
      xmlXPathDebugObjCounterUsers++;
1971
      if (xmlXPathDebugObjCounterUsers >
1972
    xmlXPathDebugObjMaxUsers)
1973
    xmlXPathDebugObjMaxUsers =
1974
        xmlXPathDebugObjCounterUsers;
1975
      break;
1976
  case XPATH_XSLT_TREE:
1977
      if (! isCached)
1978
    xmlXPathDebugObjTotalXSLTTree++;
1979
      xmlXPathDebugObjCounterXSLTTree++;
1980
      if (xmlXPathDebugObjCounterXSLTTree >
1981
    xmlXPathDebugObjMaxXSLTTree)
1982
    xmlXPathDebugObjMaxXSLTTree =
1983
        xmlXPathDebugObjCounterXSLTTree;
1984
      break;
1985
  default:
1986
      break;
1987
    }
1988
    if (! isCached)
1989
  xmlXPathDebugObjTotalAll++;
1990
    xmlXPathDebugObjCounterAll++;
1991
    if (xmlXPathDebugObjCounterAll >
1992
  xmlXPathDebugObjMaxAll)
1993
  xmlXPathDebugObjMaxAll =
1994
      xmlXPathDebugObjCounterAll;
1995
}
1996
1997
static void
1998
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1999
            xmlXPathObjectType objType)
2000
{
2001
    int isCached = 0;
2002
2003
    if (ctxt != NULL) {
2004
  if (ctxt->cache != NULL) {
2005
      xmlXPathContextCachePtr cache =
2006
    (xmlXPathContextCachePtr) ctxt->cache;
2007
2008
      isCached = 1;
2009
2010
      cache->dbgCachedAll++;
2011
      switch (objType) {
2012
    case XPATH_UNDEFINED:
2013
        cache->dbgCachedUndefined++;
2014
        break;
2015
    case XPATH_NODESET:
2016
        cache->dbgCachedNodeset++;
2017
        break;
2018
    case XPATH_BOOLEAN:
2019
        cache->dbgCachedBool++;
2020
        break;
2021
    case XPATH_NUMBER:
2022
        cache->dbgCachedNumber++;
2023
        break;
2024
    case XPATH_STRING:
2025
        cache->dbgCachedString++;
2026
        break;
2027
#ifdef LIBXML_XPTR_LOCS_ENABLED
2028
    case XPATH_POINT:
2029
        cache->dbgCachedPoint++;
2030
        break;
2031
    case XPATH_RANGE:
2032
        cache->dbgCachedRange++;
2033
        break;
2034
    case XPATH_LOCATIONSET:
2035
        cache->dbgCachedLocset++;
2036
        break;
2037
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2038
    case XPATH_USERS:
2039
        cache->dbgCachedUsers++;
2040
        break;
2041
    case XPATH_XSLT_TREE:
2042
        cache->dbgCachedXSLTTree++;
2043
        break;
2044
    default:
2045
        break;
2046
      }
2047
2048
  }
2049
    }
2050
    switch (objType) {
2051
  case XPATH_UNDEFINED:
2052
      xmlXPathDebugObjCounterUndefined--;
2053
      break;
2054
  case XPATH_NODESET:
2055
      xmlXPathDebugObjCounterNodeset--;
2056
      break;
2057
  case XPATH_BOOLEAN:
2058
      xmlXPathDebugObjCounterBool--;
2059
      break;
2060
  case XPATH_NUMBER:
2061
      xmlXPathDebugObjCounterNumber--;
2062
      break;
2063
  case XPATH_STRING:
2064
      xmlXPathDebugObjCounterString--;
2065
      break;
2066
#ifdef LIBXML_XPTR_LOCS_ENABLED
2067
  case XPATH_POINT:
2068
      xmlXPathDebugObjCounterPoint--;
2069
      break;
2070
  case XPATH_RANGE:
2071
      xmlXPathDebugObjCounterRange--;
2072
      break;
2073
  case XPATH_LOCATIONSET:
2074
      xmlXPathDebugObjCounterLocset--;
2075
      break;
2076
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2077
  case XPATH_USERS:
2078
      xmlXPathDebugObjCounterUsers--;
2079
      break;
2080
  case XPATH_XSLT_TREE:
2081
      xmlXPathDebugObjCounterXSLTTree--;
2082
      break;
2083
  default:
2084
      break;
2085
    }
2086
    xmlXPathDebugObjCounterAll--;
2087
}
2088
2089
static void
2090
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2091
{
2092
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2093
  reqXSLTTree, reqUndefined;
2094
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2095
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2096
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2097
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2098
    int leftObjs = xmlXPathDebugObjCounterAll;
2099
2100
    reqAll = xmlXPathDebugObjTotalAll;
2101
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2102
    reqString = xmlXPathDebugObjTotalString;
2103
    reqBool = xmlXPathDebugObjTotalBool;
2104
    reqNumber = xmlXPathDebugObjTotalNumber;
2105
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2106
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2107
2108
    printf("# XPath object usage:\n");
2109
2110
    if (ctxt != NULL) {
2111
  if (ctxt->cache != NULL) {
2112
      xmlXPathContextCachePtr cache =
2113
    (xmlXPathContextCachePtr) ctxt->cache;
2114
2115
      reAll = cache->dbgReusedAll;
2116
      reqAll += reAll;
2117
      reNodeset = cache->dbgReusedNodeset;
2118
      reqNodeset += reNodeset;
2119
      reString = cache->dbgReusedString;
2120
      reqString += reString;
2121
      reBool = cache->dbgReusedBool;
2122
      reqBool += reBool;
2123
      reNumber = cache->dbgReusedNumber;
2124
      reqNumber += reNumber;
2125
      reXSLTTree = cache->dbgReusedXSLTTree;
2126
      reqXSLTTree += reXSLTTree;
2127
      reUndefined = cache->dbgReusedUndefined;
2128
      reqUndefined += reUndefined;
2129
2130
      caAll = cache->dbgCachedAll;
2131
      caBool = cache->dbgCachedBool;
2132
      caNodeset = cache->dbgCachedNodeset;
2133
      caString = cache->dbgCachedString;
2134
      caNumber = cache->dbgCachedNumber;
2135
      caXSLTTree = cache->dbgCachedXSLTTree;
2136
      caUndefined = cache->dbgCachedUndefined;
2137
2138
      if (cache->nodesetObjs)
2139
    leftObjs -= cache->nodesetObjs->number;
2140
      if (cache->stringObjs)
2141
    leftObjs -= cache->stringObjs->number;
2142
      if (cache->booleanObjs)
2143
    leftObjs -= cache->booleanObjs->number;
2144
      if (cache->numberObjs)
2145
    leftObjs -= cache->numberObjs->number;
2146
      if (cache->miscObjs)
2147
    leftObjs -= cache->miscObjs->number;
2148
  }
2149
    }
2150
2151
    printf("# all\n");
2152
    printf("#   total  : %d\n", reqAll);
2153
    printf("#   left  : %d\n", leftObjs);
2154
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2155
    printf("#   reused : %d\n", reAll);
2156
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2157
2158
    printf("# node-sets\n");
2159
    printf("#   total  : %d\n", reqNodeset);
2160
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2161
    printf("#   reused : %d\n", reNodeset);
2162
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2163
2164
    printf("# strings\n");
2165
    printf("#   total  : %d\n", reqString);
2166
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2167
    printf("#   reused : %d\n", reString);
2168
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2169
2170
    printf("# booleans\n");
2171
    printf("#   total  : %d\n", reqBool);
2172
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2173
    printf("#   reused : %d\n", reBool);
2174
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2175
2176
    printf("# numbers\n");
2177
    printf("#   total  : %d\n", reqNumber);
2178
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2179
    printf("#   reused : %d\n", reNumber);
2180
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2181
2182
    printf("# XSLT result tree fragments\n");
2183
    printf("#   total  : %d\n", reqXSLTTree);
2184
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2185
    printf("#   reused : %d\n", reXSLTTree);
2186
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2187
2188
    printf("# undefined\n");
2189
    printf("#   total  : %d\n", reqUndefined);
2190
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2191
    printf("#   reused : %d\n", reUndefined);
2192
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2193
2194
}
2195
2196
#endif /* XP_DEBUG_OBJ_USAGE */
2197
2198
#endif /* LIBXML_DEBUG_ENABLED */
2199
2200
/************************************************************************
2201
 *                  *
2202
 *      XPath object caching        *
2203
 *                  *
2204
 ************************************************************************/
2205
2206
/**
2207
 * xmlXPathNewCache:
2208
 *
2209
 * Create a new object cache
2210
 *
2211
 * Returns the xmlXPathCache just allocated.
2212
 */
2213
static xmlXPathContextCachePtr
2214
xmlXPathNewCache(void)
2215
401
{
2216
401
    xmlXPathContextCachePtr ret;
2217
2218
401
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219
401
    if (ret == NULL) {
2220
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2221
0
  return(NULL);
2222
0
    }
2223
401
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2224
401
    ret->maxNodeset = 100;
2225
401
    ret->maxString = 100;
2226
401
    ret->maxBoolean = 100;
2227
401
    ret->maxNumber = 100;
2228
401
    ret->maxMisc = 100;
2229
401
    return(ret);
2230
401
}
2231
2232
static void
2233
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234
844
{
2235
844
    int i;
2236
844
    xmlXPathObjectPtr obj;
2237
2238
844
    if (list == NULL)
2239
0
  return;
2240
2241
18.4k
    for (i = 0; i < list->number; i++) {
2242
17.6k
  obj = list->items[i];
2243
  /*
2244
  * Note that it is already assured that we don't need to
2245
  * look out for namespace nodes in the node-set.
2246
  */
2247
17.6k
  if (obj->nodesetval != NULL) {
2248
8.47k
      if (obj->nodesetval->nodeTab != NULL)
2249
8.25k
    xmlFree(obj->nodesetval->nodeTab);
2250
8.47k
      xmlFree(obj->nodesetval);
2251
8.47k
  }
2252
17.6k
  xmlFree(obj);
2253
#ifdef XP_DEBUG_OBJ_USAGE
2254
  xmlXPathDebugObjCounterAll--;
2255
#endif
2256
17.6k
    }
2257
844
    xmlPointerListFree(list);
2258
844
}
2259
2260
static void
2261
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262
399
{
2263
399
    if (cache == NULL)
2264
0
  return;
2265
399
    if (cache->nodesetObjs)
2266
399
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267
399
    if (cache->stringObjs)
2268
90
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2269
399
    if (cache->booleanObjs)
2270
54
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271
399
    if (cache->numberObjs)
2272
66
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2273
399
    if (cache->miscObjs)
2274
235
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2275
399
    xmlFree(cache);
2276
399
}
2277
2278
/**
2279
 * xmlXPathContextSetCache:
2280
 *
2281
 * @ctxt:  the XPath context
2282
 * @active: enables/disables (creates/frees) the cache
2283
 * @value: a value with semantics dependent on @options
2284
 * @options: options (currently only the value 0 is used)
2285
 *
2286
 * Creates/frees an object cache on the XPath context.
2287
 * If activates XPath objects (xmlXPathObject) will be cached internally
2288
 * to be reused.
2289
 * @options:
2290
 *   0: This will set the XPath object caching:
2291
 *      @value:
2292
 *        This will set the maximum number of XPath objects
2293
 *        to be cached per slot
2294
 *        There are 5 slots for: node-set, string, number, boolean, and
2295
 *        misc objects. Use <0 for the default number (100).
2296
 *   Other values for @options have currently no effect.
2297
 *
2298
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2299
 */
2300
int
2301
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2302
      int active,
2303
      int value,
2304
      int options)
2305
401
{
2306
401
    if (ctxt == NULL)
2307
0
  return(-1);
2308
401
    if (active) {
2309
401
  xmlXPathContextCachePtr cache;
2310
2311
401
  if (ctxt->cache == NULL) {
2312
401
      ctxt->cache = xmlXPathNewCache();
2313
401
      if (ctxt->cache == NULL)
2314
0
    return(-1);
2315
401
  }
2316
401
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2317
401
  if (options == 0) {
2318
401
      if (value < 0)
2319
401
    value = 100;
2320
401
      cache->maxNodeset = value;
2321
401
      cache->maxString = value;
2322
401
      cache->maxNumber = value;
2323
401
      cache->maxBoolean = value;
2324
401
      cache->maxMisc = value;
2325
401
  }
2326
401
    } else if (ctxt->cache != NULL) {
2327
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328
0
  ctxt->cache = NULL;
2329
0
    }
2330
401
    return(0);
2331
401
}
2332
2333
/**
2334
 * xmlXPathCacheWrapNodeSet:
2335
 * @ctxt: the XPath context
2336
 * @val:  the NodePtr value
2337
 *
2338
 * This is the cached version of xmlXPathWrapNodeSet().
2339
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2340
 *
2341
 * Returns the created or reused object.
2342
 *
2343
 * In case of error the node set is destroyed and NULL is returned.
2344
 */
2345
static xmlXPathObjectPtr
2346
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2347
401k
{
2348
401k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349
401k
  xmlXPathContextCachePtr cache =
2350
401k
      (xmlXPathContextCachePtr) ctxt->cache;
2351
2352
401k
  if ((cache->miscObjs != NULL) &&
2353
401k
      (cache->miscObjs->number != 0))
2354
392k
  {
2355
392k
      xmlXPathObjectPtr ret;
2356
2357
392k
      ret = (xmlXPathObjectPtr)
2358
392k
    cache->miscObjs->items[--cache->miscObjs->number];
2359
392k
      ret->type = XPATH_NODESET;
2360
392k
      ret->nodesetval = val;
2361
#ifdef XP_DEBUG_OBJ_USAGE
2362
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363
#endif
2364
392k
      return(ret);
2365
392k
  }
2366
401k
    }
2367
2368
9.00k
    return(xmlXPathWrapNodeSet(val));
2369
2370
401k
}
2371
2372
/**
2373
 * xmlXPathCacheWrapString:
2374
 * @ctxt: the XPath context
2375
 * @val:  the xmlChar * value
2376
 *
2377
 * This is the cached version of xmlXPathWrapString().
2378
 * Wraps the @val string into an XPath object.
2379
 *
2380
 * Returns the created or reused object.
2381
 */
2382
static xmlXPathObjectPtr
2383
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2384
35.0k
{
2385
35.0k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386
35.0k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387
2388
35.0k
  if ((cache->stringObjs != NULL) &&
2389
35.0k
      (cache->stringObjs->number != 0))
2390
3.36k
  {
2391
2392
3.36k
      xmlXPathObjectPtr ret;
2393
2394
3.36k
      ret = (xmlXPathObjectPtr)
2395
3.36k
    cache->stringObjs->items[--cache->stringObjs->number];
2396
3.36k
      ret->type = XPATH_STRING;
2397
3.36k
      ret->stringval = val;
2398
#ifdef XP_DEBUG_OBJ_USAGE
2399
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400
#endif
2401
3.36k
      return(ret);
2402
31.6k
  } else if ((cache->miscObjs != NULL) &&
2403
31.6k
      (cache->miscObjs->number != 0))
2404
30.9k
  {
2405
30.9k
      xmlXPathObjectPtr ret;
2406
      /*
2407
      * Fallback to misc-cache.
2408
      */
2409
30.9k
      ret = (xmlXPathObjectPtr)
2410
30.9k
    cache->miscObjs->items[--cache->miscObjs->number];
2411
2412
30.9k
      ret->type = XPATH_STRING;
2413
30.9k
      ret->stringval = val;
2414
#ifdef XP_DEBUG_OBJ_USAGE
2415
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416
#endif
2417
30.9k
      return(ret);
2418
30.9k
  }
2419
35.0k
    }
2420
770
    return(xmlXPathWrapString(val));
2421
35.0k
}
2422
2423
/**
2424
 * xmlXPathCacheNewNodeSet:
2425
 * @ctxt: the XPath context
2426
 * @val:  the NodePtr value
2427
 *
2428
 * This is the cached version of xmlXPathNewNodeSet().
2429
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2430
 * it with the single Node @val
2431
 *
2432
 * Returns the created or reused object.
2433
 */
2434
static xmlXPathObjectPtr
2435
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2436
405k
{
2437
405k
    if ((ctxt != NULL) && (ctxt->cache)) {
2438
405k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439
2440
405k
  if ((cache->nodesetObjs != NULL) &&
2441
405k
      (cache->nodesetObjs->number != 0))
2442
405k
  {
2443
405k
      xmlXPathObjectPtr ret;
2444
      /*
2445
      * Use the nodeset-cache.
2446
      */
2447
405k
      ret = (xmlXPathObjectPtr)
2448
405k
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449
405k
      ret->type = XPATH_NODESET;
2450
405k
      ret->boolval = 0;
2451
405k
      if (val) {
2452
403k
    if ((ret->nodesetval->nodeMax == 0) ||
2453
403k
        (val->type == XML_NAMESPACE_DECL))
2454
9.13k
    {
2455
                    /* TODO: Check memory error. */
2456
9.13k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457
394k
    } else {
2458
394k
        ret->nodesetval->nodeTab[0] = val;
2459
394k
        ret->nodesetval->nodeNr = 1;
2460
394k
    }
2461
403k
      }
2462
#ifdef XP_DEBUG_OBJ_USAGE
2463
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464
#endif
2465
405k
      return(ret);
2466
405k
  } else if ((cache->miscObjs != NULL) &&
2467
613
      (cache->miscObjs->number != 0))
2468
4
  {
2469
4
      xmlXPathObjectPtr ret;
2470
4
            xmlNodeSetPtr set;
2471
      /*
2472
      * Fallback to misc-cache.
2473
      */
2474
2475
4
      set = xmlXPathNodeSetCreate(val);
2476
4
      if (set == NULL) {
2477
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2478
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2479
0
    return(NULL);
2480
0
      }
2481
2482
4
      ret = (xmlXPathObjectPtr)
2483
4
    cache->miscObjs->items[--cache->miscObjs->number];
2484
2485
4
      ret->type = XPATH_NODESET;
2486
4
      ret->boolval = 0;
2487
4
      ret->nodesetval = set;
2488
#ifdef XP_DEBUG_OBJ_USAGE
2489
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490
#endif
2491
4
      return(ret);
2492
4
  }
2493
405k
    }
2494
609
    return(xmlXPathNewNodeSet(val));
2495
405k
}
2496
2497
/**
2498
 * xmlXPathCacheNewString:
2499
 * @ctxt: the XPath context
2500
 * @val:  the xmlChar * value
2501
 *
2502
 * This is the cached version of xmlXPathNewString().
2503
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2504
 *
2505
 * Returns the created or reused object.
2506
 */
2507
static xmlXPathObjectPtr
2508
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2509
1.86M
{
2510
1.86M
    if ((ctxt != NULL) && (ctxt->cache)) {
2511
1.86M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512
2513
1.86M
  if ((cache->stringObjs != NULL) &&
2514
1.86M
      (cache->stringObjs->number != 0))
2515
1.86M
  {
2516
1.86M
      xmlXPathObjectPtr ret;
2517
1.86M
            xmlChar *copy;
2518
2519
1.86M
            if (val == NULL)
2520
0
                val = BAD_CAST "";
2521
1.86M
            copy = xmlStrdup(val);
2522
1.86M
            if (copy == NULL) {
2523
1
                xmlXPathErrMemory(ctxt, NULL);
2524
1
                return(NULL);
2525
1
            }
2526
2527
1.86M
      ret = (xmlXPathObjectPtr)
2528
1.86M
    cache->stringObjs->items[--cache->stringObjs->number];
2529
1.86M
      ret->type = XPATH_STRING;
2530
1.86M
            ret->stringval = copy;
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
1.86M
      return(ret);
2535
1.86M
  } else if ((cache->miscObjs != NULL) &&
2536
366
      (cache->miscObjs->number != 0))
2537
195
  {
2538
195
      xmlXPathObjectPtr ret;
2539
195
            xmlChar *copy;
2540
2541
195
            if (val == NULL)
2542
0
                val = BAD_CAST "";
2543
195
            copy = xmlStrdup(val);
2544
195
            if (copy == NULL) {
2545
1
                xmlXPathErrMemory(ctxt, NULL);
2546
1
                return(NULL);
2547
1
            }
2548
2549
194
      ret = (xmlXPathObjectPtr)
2550
194
    cache->miscObjs->items[--cache->miscObjs->number];
2551
2552
194
      ret->type = XPATH_STRING;
2553
194
            ret->stringval = copy;
2554
#ifdef XP_DEBUG_OBJ_USAGE
2555
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556
#endif
2557
194
      return(ret);
2558
195
  }
2559
1.86M
    }
2560
171
    return(xmlXPathNewString(val));
2561
1.86M
}
2562
2563
/**
2564
 * xmlXPathCacheNewCString:
2565
 * @ctxt: the XPath context
2566
 * @val:  the char * value
2567
 *
2568
 * This is the cached version of xmlXPathNewCString().
2569
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2570
 *
2571
 * Returns the created or reused object.
2572
 */
2573
static xmlXPathObjectPtr
2574
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2575
355
{
2576
355
    return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2577
355
}
2578
2579
/**
2580
 * xmlXPathCacheNewBoolean:
2581
 * @ctxt: the XPath context
2582
 * @val:  the boolean value
2583
 *
2584
 * This is the cached version of xmlXPathNewBoolean().
2585
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586
 *
2587
 * Returns the created or reused object.
2588
 */
2589
static xmlXPathObjectPtr
2590
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591
10.9k
{
2592
10.9k
    if ((ctxt != NULL) && (ctxt->cache)) {
2593
10.9k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595
10.9k
  if ((cache->booleanObjs != NULL) &&
2596
10.9k
      (cache->booleanObjs->number != 0))
2597
10.4k
  {
2598
10.4k
      xmlXPathObjectPtr ret;
2599
2600
10.4k
      ret = (xmlXPathObjectPtr)
2601
10.4k
    cache->booleanObjs->items[--cache->booleanObjs->number];
2602
10.4k
      ret->type = XPATH_BOOLEAN;
2603
10.4k
      ret->boolval = (val != 0);
2604
#ifdef XP_DEBUG_OBJ_USAGE
2605
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606
#endif
2607
10.4k
      return(ret);
2608
10.4k
  } else if ((cache->miscObjs != NULL) &&
2609
500
      (cache->miscObjs->number != 0))
2610
414
  {
2611
414
      xmlXPathObjectPtr ret;
2612
2613
414
      ret = (xmlXPathObjectPtr)
2614
414
    cache->miscObjs->items[--cache->miscObjs->number];
2615
2616
414
      ret->type = XPATH_BOOLEAN;
2617
414
      ret->boolval = (val != 0);
2618
#ifdef XP_DEBUG_OBJ_USAGE
2619
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620
#endif
2621
414
      return(ret);
2622
414
  }
2623
10.9k
    }
2624
86
    return(xmlXPathNewBoolean(val));
2625
10.9k
}
2626
2627
/**
2628
 * xmlXPathCacheNewFloat:
2629
 * @ctxt: the XPath context
2630
 * @val:  the double value
2631
 *
2632
 * This is the cached version of xmlXPathNewFloat().
2633
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2634
 *
2635
 * Returns the created or reused object.
2636
 */
2637
static xmlXPathObjectPtr
2638
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639
2.14M
{
2640
2.14M
     if ((ctxt != NULL) && (ctxt->cache)) {
2641
2.14M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643
2.14M
  if ((cache->numberObjs != NULL) &&
2644
2.14M
      (cache->numberObjs->number != 0))
2645
2.13M
  {
2646
2.13M
      xmlXPathObjectPtr ret;
2647
2648
2.13M
      ret = (xmlXPathObjectPtr)
2649
2.13M
    cache->numberObjs->items[--cache->numberObjs->number];
2650
2.13M
      ret->type = XPATH_NUMBER;
2651
2.13M
      ret->floatval = val;
2652
#ifdef XP_DEBUG_OBJ_USAGE
2653
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654
#endif
2655
2.13M
      return(ret);
2656
2.13M
  } else if ((cache->miscObjs != NULL) &&
2657
8.60k
      (cache->miscObjs->number != 0))
2658
1.08k
  {
2659
1.08k
      xmlXPathObjectPtr ret;
2660
2661
1.08k
      ret = (xmlXPathObjectPtr)
2662
1.08k
    cache->miscObjs->items[--cache->miscObjs->number];
2663
2664
1.08k
      ret->type = XPATH_NUMBER;
2665
1.08k
      ret->floatval = val;
2666
#ifdef XP_DEBUG_OBJ_USAGE
2667
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668
#endif
2669
1.08k
      return(ret);
2670
1.08k
  }
2671
2.14M
    }
2672
7.51k
    return(xmlXPathNewFloat(val));
2673
2.14M
}
2674
2675
/**
2676
 * xmlXPathCacheConvertString:
2677
 * @ctxt: the XPath context
2678
 * @val:  an XPath object
2679
 *
2680
 * This is the cached version of xmlXPathConvertString().
2681
 * Converts an existing object to its string() equivalent
2682
 *
2683
 * Returns a created or reused object, the old one is freed (cached)
2684
 *         (or the operation is done directly on @val)
2685
 */
2686
2687
static xmlXPathObjectPtr
2688
66.3k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689
66.3k
    xmlChar *res = NULL;
2690
2691
66.3k
    if (val == NULL)
2692
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694
66.3k
    switch (val->type) {
2695
0
    case XPATH_UNDEFINED:
2696
#ifdef DEBUG_EXPR
2697
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698
#endif
2699
0
  break;
2700
33.4k
    case XPATH_NODESET:
2701
33.4k
    case XPATH_XSLT_TREE:
2702
33.4k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2703
33.4k
  break;
2704
31.3k
    case XPATH_STRING:
2705
31.3k
  return(val);
2706
72
    case XPATH_BOOLEAN:
2707
72
  res = xmlXPathCastBooleanToString(val->boolval);
2708
72
  break;
2709
1.50k
    case XPATH_NUMBER:
2710
1.50k
  res = xmlXPathCastNumberToString(val->floatval);
2711
1.50k
  break;
2712
0
    case XPATH_USERS:
2713
#ifdef LIBXML_XPTR_LOCS_ENABLED
2714
    case XPATH_POINT:
2715
    case XPATH_RANGE:
2716
    case XPATH_LOCATIONSET:
2717
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2718
0
  TODO;
2719
0
  break;
2720
66.3k
    }
2721
35.0k
    xmlXPathReleaseObject(ctxt, val);
2722
35.0k
    if (res == NULL)
2723
2
  return(xmlXPathCacheNewCString(ctxt, ""));
2724
35.0k
    return(xmlXPathCacheWrapString(ctxt, res));
2725
35.0k
}
2726
2727
/**
2728
 * xmlXPathCacheObjectCopy:
2729
 * @ctxt: the XPath context
2730
 * @val:  the original object
2731
 *
2732
 * This is the cached version of xmlXPathObjectCopy().
2733
 * Acquire a copy of a given object
2734
 *
2735
 * Returns a created or reused created object.
2736
 */
2737
static xmlXPathObjectPtr
2738
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739
12.2k
{
2740
12.2k
    if (val == NULL)
2741
0
  return(NULL);
2742
2743
12.2k
    if (XP_HAS_CACHE(ctxt)) {
2744
12.2k
  switch (val->type) {
2745
0
      case XPATH_NODESET:
2746
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2747
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748
7.46k
      case XPATH_STRING:
2749
7.46k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2750
0
      case XPATH_BOOLEAN:
2751
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752
4.75k
      case XPATH_NUMBER:
2753
4.75k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754
0
      default:
2755
0
    break;
2756
12.2k
  }
2757
12.2k
    }
2758
0
    return(xmlXPathObjectCopy(val));
2759
12.2k
}
2760
2761
/**
2762
 * xmlXPathCacheConvertBoolean:
2763
 * @ctxt: the XPath context
2764
 * @val:  an XPath object
2765
 *
2766
 * This is the cached version of xmlXPathConvertBoolean().
2767
 * Converts an existing object to its boolean() equivalent
2768
 *
2769
 * Returns a created or reused object, the old one is freed (or the operation
2770
 *         is done directly on @val)
2771
 */
2772
static xmlXPathObjectPtr
2773
3.26k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
3.26k
    xmlXPathObjectPtr ret;
2775
2776
3.26k
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2778
3.26k
    if (val->type == XPATH_BOOLEAN)
2779
48
  return(val);
2780
3.21k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781
3.21k
    xmlXPathReleaseObject(ctxt, val);
2782
3.21k
    return(ret);
2783
3.26k
}
2784
2785
/**
2786
 * xmlXPathCacheConvertNumber:
2787
 * @ctxt: the XPath context
2788
 * @val:  an XPath object
2789
 *
2790
 * This is the cached version of xmlXPathConvertNumber().
2791
 * Converts an existing object to its number() equivalent
2792
 *
2793
 * Returns a created or reused object, the old one is freed (or the operation
2794
 *         is done directly on @val)
2795
 */
2796
static xmlXPathObjectPtr
2797
2.04M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798
2.04M
    xmlXPathObjectPtr ret;
2799
2800
2.04M
    if (val == NULL)
2801
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802
2.04M
    if (val->type == XPATH_NUMBER)
2803
1
  return(val);
2804
2.04M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805
2.04M
    xmlXPathReleaseObject(ctxt, val);
2806
2.04M
    return(ret);
2807
2.04M
}
2808
2809
/************************************************************************
2810
 *                  *
2811
 *    Parser stacks related functions and macros    *
2812
 *                  *
2813
 ************************************************************************/
2814
2815
/**
2816
 * valuePop:
2817
 * @ctxt: an XPath evaluation context
2818
 *
2819
 * Pops the top XPath object from the value stack
2820
 *
2821
 * Returns the XPath object just removed
2822
 */
2823
xmlXPathObjectPtr
2824
valuePop(xmlXPathParserContextPtr ctxt)
2825
5.40M
{
2826
5.40M
    xmlXPathObjectPtr ret;
2827
2828
5.40M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829
7
        return (NULL);
2830
2831
5.40M
    ctxt->valueNr--;
2832
5.40M
    if (ctxt->valueNr > 0)
2833
1.54M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834
3.85M
    else
2835
3.85M
        ctxt->value = NULL;
2836
5.40M
    ret = ctxt->valueTab[ctxt->valueNr];
2837
5.40M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2838
5.40M
    return (ret);
2839
5.40M
}
2840
/**
2841
 * valuePush:
2842
 * @ctxt:  an XPath evaluation context
2843
 * @value:  the XPath object
2844
 *
2845
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2846
 * a memory error is recorded in the parser context.
2847
 *
2848
 * Returns the number of items on the value stack, or -1 in case of error.
2849
 *
2850
 * The object is destroyed in case of error.
2851
 */
2852
int
2853
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854
5.40M
{
2855
5.40M
    if (ctxt == NULL) return(-1);
2856
5.40M
    if (value == NULL) {
2857
        /*
2858
         * A NULL value typically indicates that a memory allocation failed,
2859
         * so we set ctxt->error here to propagate the error.
2860
         */
2861
34
  ctxt->error = XPATH_MEMORY_ERROR;
2862
34
        return(-1);
2863
34
    }
2864
5.40M
    if (ctxt->valueNr >= ctxt->valueMax) {
2865
0
        xmlXPathObjectPtr *tmp;
2866
2867
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2868
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2869
0
            xmlXPathFreeObject(value);
2870
0
            return (-1);
2871
0
        }
2872
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2873
0
                                             2 * ctxt->valueMax *
2874
0
                                             sizeof(ctxt->valueTab[0]));
2875
0
        if (tmp == NULL) {
2876
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2877
0
            xmlXPathFreeObject(value);
2878
0
            return (-1);
2879
0
        }
2880
0
        ctxt->valueMax *= 2;
2881
0
  ctxt->valueTab = tmp;
2882
0
    }
2883
5.40M
    ctxt->valueTab[ctxt->valueNr] = value;
2884
5.40M
    ctxt->value = value;
2885
5.40M
    return (ctxt->valueNr++);
2886
5.40M
}
2887
2888
/**
2889
 * xmlXPathPopBoolean:
2890
 * @ctxt:  an XPath parser context
2891
 *
2892
 * Pops a boolean from the stack, handling conversion if needed.
2893
 * Check error with #xmlXPathCheckError.
2894
 *
2895
 * Returns the boolean
2896
 */
2897
int
2898
25
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899
25
    xmlXPathObjectPtr obj;
2900
25
    int ret;
2901
2902
25
    obj = valuePop(ctxt);
2903
25
    if (obj == NULL) {
2904
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905
0
  return(0);
2906
0
    }
2907
25
    if (obj->type != XPATH_BOOLEAN)
2908
25
  ret = xmlXPathCastToBoolean(obj);
2909
0
    else
2910
0
        ret = obj->boolval;
2911
25
    xmlXPathReleaseObject(ctxt->context, obj);
2912
25
    return(ret);
2913
25
}
2914
2915
/**
2916
 * xmlXPathPopNumber:
2917
 * @ctxt:  an XPath parser context
2918
 *
2919
 * Pops a number from the stack, handling conversion if needed.
2920
 * Check error with #xmlXPathCheckError.
2921
 *
2922
 * Returns the number
2923
 */
2924
double
2925
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2926
0
    xmlXPathObjectPtr obj;
2927
0
    double ret;
2928
2929
0
    obj = valuePop(ctxt);
2930
0
    if (obj == NULL) {
2931
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932
0
  return(0);
2933
0
    }
2934
0
    if (obj->type != XPATH_NUMBER)
2935
0
  ret = xmlXPathCastToNumber(obj);
2936
0
    else
2937
0
        ret = obj->floatval;
2938
0
    xmlXPathReleaseObject(ctxt->context, obj);
2939
0
    return(ret);
2940
0
}
2941
2942
/**
2943
 * xmlXPathPopString:
2944
 * @ctxt:  an XPath parser context
2945
 *
2946
 * Pops a string from the stack, handling conversion if needed.
2947
 * Check error with #xmlXPathCheckError.
2948
 *
2949
 * Returns the string
2950
 */
2951
xmlChar *
2952
18.3k
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953
18.3k
    xmlXPathObjectPtr obj;
2954
18.3k
    xmlChar * ret;
2955
2956
18.3k
    obj = valuePop(ctxt);
2957
18.3k
    if (obj == NULL) {
2958
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959
0
  return(NULL);
2960
0
    }
2961
18.3k
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2962
    /* TODO: needs refactoring somewhere else */
2963
18.3k
    if (obj->stringval == ret)
2964
2
  obj->stringval = NULL;
2965
18.3k
    xmlXPathReleaseObject(ctxt->context, obj);
2966
18.3k
    return(ret);
2967
18.3k
}
2968
2969
/**
2970
 * xmlXPathPopNodeSet:
2971
 * @ctxt:  an XPath parser context
2972
 *
2973
 * Pops a node-set from the stack, handling conversion if needed.
2974
 * Check error with #xmlXPathCheckError.
2975
 *
2976
 * Returns the node-set
2977
 */
2978
xmlNodeSetPtr
2979
241k
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980
241k
    xmlXPathObjectPtr obj;
2981
241k
    xmlNodeSetPtr ret;
2982
2983
241k
    if (ctxt == NULL) return(NULL);
2984
241k
    if (ctxt->value == NULL) {
2985
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986
0
  return(NULL);
2987
0
    }
2988
241k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2989
448
  xmlXPathSetTypeError(ctxt);
2990
448
  return(NULL);
2991
448
    }
2992
241k
    obj = valuePop(ctxt);
2993
241k
    ret = obj->nodesetval;
2994
#if 0
2995
    /* to fix memory leak of not clearing obj->user */
2996
    if (obj->boolval && obj->user != NULL)
2997
        xmlFreeNodeList((xmlNodePtr) obj->user);
2998
#endif
2999
241k
    obj->nodesetval = NULL;
3000
241k
    xmlXPathReleaseObject(ctxt->context, obj);
3001
241k
    return(ret);
3002
241k
}
3003
3004
/**
3005
 * xmlXPathPopExternal:
3006
 * @ctxt:  an XPath parser context
3007
 *
3008
 * Pops an external object from the stack, handling conversion if needed.
3009
 * Check error with #xmlXPathCheckError.
3010
 *
3011
 * Returns the object
3012
 */
3013
void *
3014
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3015
0
    xmlXPathObjectPtr obj;
3016
0
    void * ret;
3017
3018
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3019
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3020
0
  return(NULL);
3021
0
    }
3022
0
    if (ctxt->value->type != XPATH_USERS) {
3023
0
  xmlXPathSetTypeError(ctxt);
3024
0
  return(NULL);
3025
0
    }
3026
0
    obj = valuePop(ctxt);
3027
0
    ret = obj->user;
3028
0
    obj->user = NULL;
3029
0
    xmlXPathReleaseObject(ctxt->context, obj);
3030
0
    return(ret);
3031
0
}
3032
3033
/*
3034
 * Macros for accessing the content. Those should be used only by the parser,
3035
 * and not exported.
3036
 *
3037
 * Dirty macros, i.e. one need to make assumption on the context to use them
3038
 *
3039
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3040
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3041
 *           in ISO-Latin or UTF-8.
3042
 *           This should be used internally by the parser
3043
 *           only to compare to ASCII values otherwise it would break when
3044
 *           running with UTF-8 encoding.
3045
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3046
 *           to compare on ASCII based substring.
3047
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3048
 *           strings within the parser.
3049
 *   CURRENT Returns the current char value, with the full decoding of
3050
 *           UTF-8 if we are using this mode. It returns an int.
3051
 *   NEXT    Skip to the next character, this does the proper decoding
3052
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3053
 *           It returns the pointer to the current xmlChar.
3054
 */
3055
3056
99.5M
#define CUR (*ctxt->cur)
3057
1.88k
#define SKIP(val) ctxt->cur += (val)
3058
38.6M
#define NXT(val) ctxt->cur[(val)]
3059
677
#define CUR_PTR ctxt->cur
3060
25.8M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061
3062
#define COPY_BUF(l,b,i,v)                                              \
3063
6.69M
    if (l == 1) b[i++] = v;                                            \
3064
6.69M
    else i += xmlCopyChar(l,&b[i],v)
3065
3066
17.3M
#define NEXTL(l)  ctxt->cur += l
3067
3068
#define SKIP_BLANKS             \
3069
54.8M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070
3071
#define CURRENT (*ctxt->cur)
3072
32.6M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3073
3074
3075
#ifndef DBL_DIG
3076
#define DBL_DIG 16
3077
#endif
3078
#ifndef DBL_EPSILON
3079
#define DBL_EPSILON 1E-9
3080
#endif
3081
3082
20
#define UPPER_DOUBLE 1E9
3083
0
#define LOWER_DOUBLE 1E-5
3084
#define LOWER_DOUBLE_EXP 5
3085
3086
#define INTEGER_DIGITS DBL_DIG
3087
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3088
20
#define EXPONENT_DIGITS (3 + 2)
3089
3090
/**
3091
 * xmlXPathFormatNumber:
3092
 * @number:     number to format
3093
 * @buffer:     output buffer
3094
 * @buffersize: size of output buffer
3095
 *
3096
 * Convert the number into a string representation.
3097
 */
3098
static void
3099
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3100
41
{
3101
41
    switch (xmlXPathIsInf(number)) {
3102
0
    case 1:
3103
0
  if (buffersize > (int)sizeof("Infinity"))
3104
0
      snprintf(buffer, buffersize, "Infinity");
3105
0
  break;
3106
0
    case -1:
3107
0
  if (buffersize > (int)sizeof("-Infinity"))
3108
0
      snprintf(buffer, buffersize, "-Infinity");
3109
0
  break;
3110
41
    default:
3111
41
  if (xmlXPathIsNaN(number)) {
3112
0
      if (buffersize > (int)sizeof("NaN"))
3113
0
    snprintf(buffer, buffersize, "NaN");
3114
41
  } else if (number == 0) {
3115
            /* Omit sign for negative zero. */
3116
0
      snprintf(buffer, buffersize, "0");
3117
41
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3118
41
                   (number == (int) number)) {
3119
21
      char work[30];
3120
21
      char *ptr, *cur;
3121
21
      int value = (int) number;
3122
3123
21
            ptr = &buffer[0];
3124
21
      if (value == 0) {
3125
0
    *ptr++ = '0';
3126
21
      } else {
3127
21
    snprintf(work, 29, "%d", value);
3128
21
    cur = &work[0];
3129
62
    while ((*cur) && (ptr - buffer < buffersize)) {
3130
41
        *ptr++ = *cur++;
3131
41
    }
3132
21
      }
3133
21
      if (ptr - buffer < buffersize) {
3134
21
    *ptr = 0;
3135
21
      } else if (buffersize > 0) {
3136
0
    ptr--;
3137
0
    *ptr = 0;
3138
0
      }
3139
21
  } else {
3140
      /*
3141
        For the dimension of work,
3142
            DBL_DIG is number of significant digits
3143
      EXPONENT is only needed for "scientific notation"
3144
            3 is sign, decimal point, and terminating zero
3145
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3146
        Note that this dimension is slightly (a few characters)
3147
        larger than actually necessary.
3148
      */
3149
20
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3150
20
      int integer_place, fraction_place;
3151
20
      char *ptr;
3152
20
      char *after_fraction;
3153
20
      double absolute_value;
3154
20
      int size;
3155
3156
20
      absolute_value = fabs(number);
3157
3158
      /*
3159
       * First choose format - scientific or regular floating point.
3160
       * In either case, result is in work, and after_fraction points
3161
       * just past the fractional part.
3162
      */
3163
20
      if ( ((absolute_value > UPPER_DOUBLE) ||
3164
20
      (absolute_value < LOWER_DOUBLE)) &&
3165
20
     (absolute_value != 0.0) ) {
3166
    /* Use scientific notation */
3167
20
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3168
20
    fraction_place = DBL_DIG - 1;
3169
20
    size = snprintf(work, sizeof(work),"%*.*e",
3170
20
       integer_place, fraction_place, number);
3171
103
    while ((size > 0) && (work[size] != 'e')) size--;
3172
3173
20
      }
3174
0
      else {
3175
    /* Use regular notation */
3176
0
    if (absolute_value > 0.0) {
3177
0
        integer_place = (int)log10(absolute_value);
3178
0
        if (integer_place > 0)
3179
0
            fraction_place = DBL_DIG - integer_place - 1;
3180
0
        else
3181
0
            fraction_place = DBL_DIG - integer_place;
3182
0
    } else {
3183
0
        fraction_place = 1;
3184
0
    }
3185
0
    size = snprintf(work, sizeof(work), "%0.*f",
3186
0
        fraction_place, number);
3187
0
      }
3188
3189
      /* Remove leading spaces sometimes inserted by snprintf */
3190
37
      while (work[0] == ' ') {
3191
357
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192
17
    size--;
3193
17
      }
3194
3195
      /* Remove fractional trailing zeroes */
3196
20
      after_fraction = work + size;
3197
20
      ptr = after_fraction;
3198
20
      while (*(--ptr) == '0')
3199
0
    ;
3200
20
      if (*ptr != '.')
3201
20
          ptr++;
3202
103
      while ((*ptr++ = *after_fraction++) != 0);
3203
3204
      /* Finally copy result back to caller */
3205
20
      size = strlen(work) + 1;
3206
20
      if (size > buffersize) {
3207
0
    work[buffersize - 1] = 0;
3208
0
    size = buffersize;
3209
0
      }
3210
20
      memmove(buffer, work, size);
3211
20
  }
3212
41
  break;
3213
41
    }
3214
41
}
3215
3216
3217
/************************************************************************
3218
 *                  *
3219
 *      Routines to handle NodeSets     *
3220
 *                  *
3221
 ************************************************************************/
3222
3223
/**
3224
 * xmlXPathOrderDocElems:
3225
 * @doc:  an input document
3226
 *
3227
 * Call this routine to speed up XPath computation on static documents.
3228
 * This stamps all the element nodes with the document order
3229
 * Like for line information, the order is kept in the element->content
3230
 * field, the value stored is actually - the node number (starting at -1)
3231
 * to be able to differentiate from line numbers.
3232
 *
3233
 * Returns the number of elements found in the document or -1 in case
3234
 *    of error.
3235
 */
3236
long
3237
399
xmlXPathOrderDocElems(xmlDocPtr doc) {
3238
399
    ptrdiff_t count = 0;
3239
399
    xmlNodePtr cur;
3240
3241
399
    if (doc == NULL)
3242
0
  return(-1);
3243
399
    cur = doc->children;
3244
1.48M
    while (cur != NULL) {
3245
1.48M
  if (cur->type == XML_ELEMENT_NODE) {
3246
1.34M
      cur->content = (void *) (-(++count));
3247
1.34M
      if (cur->children != NULL) {
3248
16.3k
    cur = cur->children;
3249
16.3k
    continue;
3250
16.3k
      }
3251
1.34M
  }
3252
1.46M
  if (cur->next != NULL) {
3253
1.46M
      cur = cur->next;
3254
1.46M
      continue;
3255
1.46M
  }
3256
16.7k
  do {
3257
16.7k
      cur = cur->parent;
3258
16.7k
      if (cur == NULL)
3259
0
    break;
3260
16.7k
      if (cur == (xmlNodePtr) doc) {
3261
380
    cur = NULL;
3262
380
    break;
3263
380
      }
3264
16.3k
      if (cur->next != NULL) {
3265
3.06k
    cur = cur->next;
3266
3.06k
    break;
3267
3.06k
      }
3268
16.3k
  } while (cur != NULL);
3269
3.44k
    }
3270
399
    return(count);
3271
399
}
3272
3273
/**
3274
 * xmlXPathCmpNodes:
3275
 * @node1:  the first node
3276
 * @node2:  the second node
3277
 *
3278
 * Compare two nodes w.r.t document order
3279
 *
3280
 * Returns -2 in case of error 1 if first point < second point, 0 if
3281
 *         it's the same node, -1 otherwise
3282
 */
3283
int
3284
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285
0
    int depth1, depth2;
3286
0
    int attr1 = 0, attr2 = 0;
3287
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288
0
    xmlNodePtr cur, root;
3289
3290
0
    if ((node1 == NULL) || (node2 == NULL))
3291
0
  return(-2);
3292
    /*
3293
     * a couple of optimizations which will avoid computations in most cases
3294
     */
3295
0
    if (node1 == node2)   /* trivial case */
3296
0
  return(0);
3297
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3298
0
  attr1 = 1;
3299
0
  attrNode1 = node1;
3300
0
  node1 = node1->parent;
3301
0
    }
3302
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr2 = 1;
3304
0
  attrNode2 = node2;
3305
0
  node2 = node2->parent;
3306
0
    }
3307
0
    if (node1 == node2) {
3308
0
  if (attr1 == attr2) {
3309
      /* not required, but we keep attributes in order */
3310
0
      if (attr1 != 0) {
3311
0
          cur = attrNode2->prev;
3312
0
    while (cur != NULL) {
3313
0
        if (cur == attrNode1)
3314
0
            return (1);
3315
0
        cur = cur->prev;
3316
0
    }
3317
0
    return (-1);
3318
0
      }
3319
0
      return(0);
3320
0
  }
3321
0
  if (attr2 == 1)
3322
0
      return(1);
3323
0
  return(-1);
3324
0
    }
3325
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3326
0
        (node2->type == XML_NAMESPACE_DECL))
3327
0
  return(1);
3328
0
    if (node1 == node2->prev)
3329
0
  return(1);
3330
0
    if (node1 == node2->next)
3331
0
  return(-1);
3332
3333
    /*
3334
     * Speedup using document order if available.
3335
     */
3336
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3337
0
  (node2->type == XML_ELEMENT_NODE) &&
3338
0
  (0 > (ptrdiff_t) node1->content) &&
3339
0
  (0 > (ptrdiff_t) node2->content) &&
3340
0
  (node1->doc == node2->doc)) {
3341
0
  ptrdiff_t l1, l2;
3342
3343
0
  l1 = -((ptrdiff_t) node1->content);
3344
0
  l2 = -((ptrdiff_t) node2->content);
3345
0
  if (l1 < l2)
3346
0
      return(1);
3347
0
  if (l1 > l2)
3348
0
      return(-1);
3349
0
    }
3350
3351
    /*
3352
     * compute depth to root
3353
     */
3354
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355
0
  if (cur->parent == node1)
3356
0
      return(1);
3357
0
  depth2++;
3358
0
    }
3359
0
    root = cur;
3360
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361
0
  if (cur->parent == node2)
3362
0
      return(-1);
3363
0
  depth1++;
3364
0
    }
3365
    /*
3366
     * Distinct document (or distinct entities :-( ) case.
3367
     */
3368
0
    if (root != cur) {
3369
0
  return(-2);
3370
0
    }
3371
    /*
3372
     * get the nearest common ancestor.
3373
     */
3374
0
    while (depth1 > depth2) {
3375
0
  depth1--;
3376
0
  node1 = node1->parent;
3377
0
    }
3378
0
    while (depth2 > depth1) {
3379
0
  depth2--;
3380
0
  node2 = node2->parent;
3381
0
    }
3382
0
    while (node1->parent != node2->parent) {
3383
0
  node1 = node1->parent;
3384
0
  node2 = node2->parent;
3385
  /* should not happen but just in case ... */
3386
0
  if ((node1 == NULL) || (node2 == NULL))
3387
0
      return(-2);
3388
0
    }
3389
    /*
3390
     * Find who's first.
3391
     */
3392
0
    if (node1 == node2->prev)
3393
0
  return(1);
3394
0
    if (node1 == node2->next)
3395
0
  return(-1);
3396
    /*
3397
     * Speedup using document order if available.
3398
     */
3399
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3400
0
  (node2->type == XML_ELEMENT_NODE) &&
3401
0
  (0 > (ptrdiff_t) node1->content) &&
3402
0
  (0 > (ptrdiff_t) node2->content) &&
3403
0
  (node1->doc == node2->doc)) {
3404
0
  ptrdiff_t l1, l2;
3405
3406
0
  l1 = -((ptrdiff_t) node1->content);
3407
0
  l2 = -((ptrdiff_t) node2->content);
3408
0
  if (l1 < l2)
3409
0
      return(1);
3410
0
  if (l1 > l2)
3411
0
      return(-1);
3412
0
    }
3413
3414
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3415
0
  if (cur == node2)
3416
0
      return(1);
3417
0
    return(-1); /* assume there is no sibling list corruption */
3418
0
}
3419
3420
/**
3421
 * xmlXPathNodeSetSort:
3422
 * @set:  the node set
3423
 *
3424
 * Sort the node set in document order
3425
 */
3426
void
3427
6.34k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428
#ifndef WITH_TIM_SORT
3429
    int i, j, incr, len;
3430
    xmlNodePtr tmp;
3431
#endif
3432
3433
6.34k
    if (set == NULL)
3434
0
  return;
3435
3436
#ifndef WITH_TIM_SORT
3437
    /*
3438
     * Use the old Shell's sort implementation to sort the node-set
3439
     * Timsort ought to be quite faster
3440
     */
3441
    len = set->nodeNr;
3442
    for (incr = len / 2; incr > 0; incr /= 2) {
3443
  for (i = incr; i < len; i++) {
3444
      j = i - incr;
3445
      while (j >= 0) {
3446
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3447
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3448
      set->nodeTab[j + incr]) == -1)
3449
#else
3450
    if (xmlXPathCmpNodes(set->nodeTab[j],
3451
      set->nodeTab[j + incr]) == -1)
3452
#endif
3453
    {
3454
        tmp = set->nodeTab[j];
3455
        set->nodeTab[j] = set->nodeTab[j + incr];
3456
        set->nodeTab[j + incr] = tmp;
3457
        j -= incr;
3458
    } else
3459
        break;
3460
      }
3461
  }
3462
    }
3463
#else /* WITH_TIM_SORT */
3464
6.34k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465
6.34k
#endif /* WITH_TIM_SORT */
3466
6.34k
}
3467
3468
493k
#define XML_NODESET_DEFAULT 10
3469
/**
3470
 * xmlXPathNodeSetDupNs:
3471
 * @node:  the parent node of the namespace XPath node
3472
 * @ns:  the libxml namespace declaration node.
3473
 *
3474
 * Namespace node in libxml don't match the XPath semantic. In a node set
3475
 * the namespace nodes are duplicated and the next pointer is set to the
3476
 * parent node in the XPath semantic.
3477
 *
3478
 * Returns the newly created object.
3479
 */
3480
static xmlNodePtr
3481
379k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482
379k
    xmlNsPtr cur;
3483
3484
379k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485
0
  return(NULL);
3486
379k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3487
0
  return((xmlNodePtr) ns);
3488
3489
    /*
3490
     * Allocate a new Namespace and fill the fields.
3491
     */
3492
379k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493
379k
    if (cur == NULL) {
3494
1
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495
1
  return(NULL);
3496
1
    }
3497
379k
    memset(cur, 0, sizeof(xmlNs));
3498
379k
    cur->type = XML_NAMESPACE_DECL;
3499
379k
    if (ns->href != NULL)
3500
379k
  cur->href = xmlStrdup(ns->href);
3501
379k
    if (ns->prefix != NULL)
3502
379k
  cur->prefix = xmlStrdup(ns->prefix);
3503
379k
    cur->next = (xmlNsPtr) node;
3504
379k
    return((xmlNodePtr) cur);
3505
379k
}
3506
3507
/**
3508
 * xmlXPathNodeSetFreeNs:
3509
 * @ns:  the XPath namespace node found in a nodeset.
3510
 *
3511
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3512
 * the namespace nodes are duplicated and the next pointer is set to the
3513
 * parent node in the XPath semantic. Check if such a node needs to be freed
3514
 */
3515
void
3516
379k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517
379k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518
0
  return;
3519
3520
379k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521
379k
  if (ns->href != NULL)
3522
379k
      xmlFree((xmlChar *)ns->href);
3523
379k
  if (ns->prefix != NULL)
3524
379k
      xmlFree((xmlChar *)ns->prefix);
3525
379k
  xmlFree(ns);
3526
379k
    }
3527
379k
}
3528
3529
/**
3530
 * xmlXPathNodeSetCreate:
3531
 * @val:  an initial xmlNodePtr, or NULL
3532
 *
3533
 * Create a new xmlNodeSetPtr of type double and of value @val
3534
 *
3535
 * Returns the newly created object.
3536
 */
3537
xmlNodeSetPtr
3538
486k
xmlXPathNodeSetCreate(xmlNodePtr val) {
3539
486k
    xmlNodeSetPtr ret;
3540
3541
486k
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542
486k
    if (ret == NULL) {
3543
9
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3544
9
  return(NULL);
3545
9
    }
3546
486k
    memset(ret, 0 , sizeof(xmlNodeSet));
3547
486k
    if (val != NULL) {
3548
63.3k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549
63.3k
               sizeof(xmlNodePtr));
3550
63.3k
  if (ret->nodeTab == NULL) {
3551
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3552
0
      xmlFree(ret);
3553
0
      return(NULL);
3554
0
  }
3555
63.3k
  memset(ret->nodeTab, 0 ,
3556
63.3k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557
63.3k
        ret->nodeMax = XML_NODESET_DEFAULT;
3558
63.3k
  if (val->type == XML_NAMESPACE_DECL) {
3559
0
      xmlNsPtr ns = (xmlNsPtr) val;
3560
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3561
3562
0
            if (nsNode == NULL) {
3563
0
                xmlXPathFreeNodeSet(ret);
3564
0
                return(NULL);
3565
0
            }
3566
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
3567
0
  } else
3568
63.3k
      ret->nodeTab[ret->nodeNr++] = val;
3569
63.3k
    }
3570
486k
    return(ret);
3571
486k
}
3572
3573
/**
3574
 * xmlXPathNodeSetContains:
3575
 * @cur:  the node-set
3576
 * @val:  the node
3577
 *
3578
 * checks whether @cur contains @val
3579
 *
3580
 * Returns true (1) if @cur contains @val, false (0) otherwise
3581
 */
3582
int
3583
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3584
0
    int i;
3585
3586
0
    if ((cur == NULL) || (val == NULL)) return(0);
3587
0
    if (val->type == XML_NAMESPACE_DECL) {
3588
0
  for (i = 0; i < cur->nodeNr; i++) {
3589
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3590
0
    xmlNsPtr ns1, ns2;
3591
3592
0
    ns1 = (xmlNsPtr) val;
3593
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3594
0
    if (ns1 == ns2)
3595
0
        return(1);
3596
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3597
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3598
0
        return(1);
3599
0
      }
3600
0
  }
3601
0
    } else {
3602
0
  for (i = 0; i < cur->nodeNr; i++) {
3603
0
      if (cur->nodeTab[i] == val)
3604
0
    return(1);
3605
0
  }
3606
0
    }
3607
0
    return(0);
3608
0
}
3609
3610
/**
3611
 * xmlXPathNodeSetAddNs:
3612
 * @cur:  the initial node set
3613
 * @node:  the hosting node
3614
 * @ns:  a the namespace node
3615
 *
3616
 * add a new namespace node to an existing NodeSet
3617
 *
3618
 * Returns 0 in case of success and -1 in case of error
3619
 */
3620
int
3621
358k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622
358k
    int i;
3623
358k
    xmlNodePtr nsNode;
3624
3625
358k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626
358k
        (ns->type != XML_NAMESPACE_DECL) ||
3627
358k
  (node->type != XML_ELEMENT_NODE))
3628
0
  return(-1);
3629
3630
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3631
    /*
3632
     * prevent duplicates
3633
     */
3634
896k
    for (i = 0;i < cur->nodeNr;i++) {
3635
538k
        if ((cur->nodeTab[i] != NULL) &&
3636
538k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637
538k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638
538k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639
0
      return(0);
3640
538k
    }
3641
3642
    /*
3643
     * grow the nodeTab if needed
3644
     */
3645
358k
    if (cur->nodeMax == 0) {
3646
449
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647
449
               sizeof(xmlNodePtr));
3648
449
  if (cur->nodeTab == NULL) {
3649
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3650
0
      return(-1);
3651
0
  }
3652
449
  memset(cur->nodeTab, 0 ,
3653
449
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654
449
        cur->nodeMax = XML_NODESET_DEFAULT;
3655
357k
    } else if (cur->nodeNr == cur->nodeMax) {
3656
0
        xmlNodePtr *temp;
3657
3658
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660
0
            return(-1);
3661
0
        }
3662
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663
0
              sizeof(xmlNodePtr));
3664
0
  if (temp == NULL) {
3665
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3666
0
      return(-1);
3667
0
  }
3668
0
        cur->nodeMax *= 2;
3669
0
  cur->nodeTab = temp;
3670
0
    }
3671
358k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3672
358k
    if(nsNode == NULL)
3673
1
        return(-1);
3674
358k
    cur->nodeTab[cur->nodeNr++] = nsNode;
3675
358k
    return(0);
3676
358k
}
3677
3678
/**
3679
 * xmlXPathNodeSetAdd:
3680
 * @cur:  the initial node set
3681
 * @val:  a new xmlNodePtr
3682
 *
3683
 * add a new xmlNodePtr to an existing NodeSet
3684
 *
3685
 * Returns 0 in case of success, and -1 in case of error
3686
 */
3687
int
3688
3.26k
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3689
3.26k
    int i;
3690
3691
3.26k
    if ((cur == NULL) || (val == NULL)) return(-1);
3692
3693
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3694
    /*
3695
     * prevent duplicates
3696
     */
3697
94.2k
    for (i = 0;i < cur->nodeNr;i++)
3698
94.1k
        if (cur->nodeTab[i] == val) return(0);
3699
3700
    /*
3701
     * grow the nodeTab if needed
3702
     */
3703
75
    if (cur->nodeMax == 0) {
3704
14
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705
14
               sizeof(xmlNodePtr));
3706
14
  if (cur->nodeTab == NULL) {
3707
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3708
0
      return(-1);
3709
0
  }
3710
14
  memset(cur->nodeTab, 0 ,
3711
14
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712
14
        cur->nodeMax = XML_NODESET_DEFAULT;
3713
61
    } else if (cur->nodeNr == cur->nodeMax) {
3714
3
        xmlNodePtr *temp;
3715
3716
3
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3717
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3718
0
            return(-1);
3719
0
        }
3720
3
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3721
3
              sizeof(xmlNodePtr));
3722
3
  if (temp == NULL) {
3723
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3724
0
      return(-1);
3725
0
  }
3726
3
        cur->nodeMax *= 2;
3727
3
  cur->nodeTab = temp;
3728
3
    }
3729
75
    if (val->type == XML_NAMESPACE_DECL) {
3730
0
  xmlNsPtr ns = (xmlNsPtr) val;
3731
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3732
3733
0
        if (nsNode == NULL)
3734
0
            return(-1);
3735
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
3736
0
    } else
3737
75
  cur->nodeTab[cur->nodeNr++] = val;
3738
75
    return(0);
3739
75
}
3740
3741
/**
3742
 * xmlXPathNodeSetAddUnique:
3743
 * @cur:  the initial node set
3744
 * @val:  a new xmlNodePtr
3745
 *
3746
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3747
 * when we are sure the node is not already in the set.
3748
 *
3749
 * Returns 0 in case of success and -1 in case of failure
3750
 */
3751
int
3752
11.7M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753
11.7M
    if ((cur == NULL) || (val == NULL)) return(-1);
3754
3755
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3756
    /*
3757
     * grow the nodeTab if needed
3758
     */
3759
11.7M
    if (cur->nodeMax == 0) {
3760
83.3k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761
83.3k
               sizeof(xmlNodePtr));
3762
83.3k
  if (cur->nodeTab == NULL) {
3763
5
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3764
5
      return(-1);
3765
5
  }
3766
83.3k
  memset(cur->nodeTab, 0 ,
3767
83.3k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768
83.3k
        cur->nodeMax = XML_NODESET_DEFAULT;
3769
11.6M
    } else if (cur->nodeNr == cur->nodeMax) {
3770
34.2k
        xmlNodePtr *temp;
3771
3772
34.2k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774
0
            return(-1);
3775
0
        }
3776
34.2k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777
34.2k
              sizeof(xmlNodePtr));
3778
34.2k
  if (temp == NULL) {
3779
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3780
0
      return(-1);
3781
0
  }
3782
34.2k
  cur->nodeTab = temp;
3783
34.2k
        cur->nodeMax *= 2;
3784
34.2k
    }
3785
11.7M
    if (val->type == XML_NAMESPACE_DECL) {
3786
6.98k
  xmlNsPtr ns = (xmlNsPtr) val;
3787
6.98k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788
3789
6.98k
        if (nsNode == NULL)
3790
0
            return(-1);
3791
6.98k
  cur->nodeTab[cur->nodeNr++] = nsNode;
3792
6.98k
    } else
3793
11.7M
  cur->nodeTab[cur->nodeNr++] = val;
3794
11.7M
    return(0);
3795
11.7M
}
3796
3797
/**
3798
 * xmlXPathNodeSetMerge:
3799
 * @val1:  the first NodeSet or NULL
3800
 * @val2:  the second NodeSet
3801
 *
3802
 * Merges two nodesets, all nodes from @val2 are added to @val1
3803
 * if @val1 is NULL, a new set is created and copied from @val2
3804
 *
3805
 * Returns @val1 once extended or NULL in case of error.
3806
 *
3807
 * Frees @val1 in case of error.
3808
 */
3809
xmlNodeSetPtr
3810
38.8k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811
38.8k
    int i, j, initNr, skip;
3812
38.8k
    xmlNodePtr n1, n2;
3813
3814
38.8k
    if (val2 == NULL) return(val1);
3815
38.8k
    if (val1 == NULL) {
3816
38
  val1 = xmlXPathNodeSetCreate(NULL);
3817
38
        if (val1 == NULL)
3818
2
            return (NULL);
3819
38
    }
3820
3821
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822
38.8k
    initNr = val1->nodeNr;
3823
3824
1.24M
    for (i = 0;i < val2->nodeNr;i++) {
3825
1.20M
  n2 = val2->nodeTab[i];
3826
  /*
3827
   * check against duplicates
3828
   */
3829
1.20M
  skip = 0;
3830
41.2M
  for (j = 0; j < initNr; j++) {
3831
40.0M
      n1 = val1->nodeTab[j];
3832
40.0M
      if (n1 == n2) {
3833
983
    skip = 1;
3834
983
    break;
3835
40.0M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836
40.0M
           (n2->type == XML_NAMESPACE_DECL)) {
3837
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3838
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3839
0
      ((xmlNsPtr) n2)->prefix)))
3840
0
    {
3841
0
        skip = 1;
3842
0
        break;
3843
0
    }
3844
0
      }
3845
40.0M
  }
3846
1.20M
  if (skip)
3847
983
      continue;
3848
3849
  /*
3850
   * grow the nodeTab if needed
3851
   */
3852
1.20M
  if (val1->nodeMax == 0) {
3853
5.86k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854
5.86k
                sizeof(xmlNodePtr));
3855
5.86k
      if (val1->nodeTab == NULL) {
3856
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3857
0
    goto error;
3858
0
      }
3859
5.86k
      memset(val1->nodeTab, 0 ,
3860
5.86k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861
5.86k
      val1->nodeMax = XML_NODESET_DEFAULT;
3862
1.20M
  } else if (val1->nodeNr == val1->nodeMax) {
3863
420
      xmlNodePtr *temp;
3864
3865
420
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867
0
                goto error;
3868
0
            }
3869
420
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870
420
               sizeof(xmlNodePtr));
3871
420
      if (temp == NULL) {
3872
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3873
0
    goto error;
3874
0
      }
3875
420
      val1->nodeTab = temp;
3876
420
      val1->nodeMax *= 2;
3877
420
  }
3878
1.20M
  if (n2->type == XML_NAMESPACE_DECL) {
3879
14.2k
      xmlNsPtr ns = (xmlNsPtr) n2;
3880
14.2k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881
3882
14.2k
            if (nsNode == NULL)
3883
0
                goto error;
3884
14.2k
      val1->nodeTab[val1->nodeNr++] = nsNode;
3885
14.2k
  } else
3886
1.19M
      val1->nodeTab[val1->nodeNr++] = n2;
3887
1.20M
    }
3888
3889
38.8k
    return(val1);
3890
3891
0
error:
3892
0
    xmlXPathFreeNodeSet(val1);
3893
0
    return(NULL);
3894
38.8k
}
3895
3896
3897
/**
3898
 * xmlXPathNodeSetMergeAndClear:
3899
 * @set1:  the first NodeSet or NULL
3900
 * @set2:  the second NodeSet
3901
 *
3902
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3903
 * Checks for duplicate nodes. Clears set2.
3904
 *
3905
 * Returns @set1 once extended or NULL in case of error.
3906
 *
3907
 * Frees @set1 in case of error.
3908
 */
3909
static xmlNodeSetPtr
3910
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3911
525k
{
3912
525k
    {
3913
525k
  int i, j, initNbSet1;
3914
525k
  xmlNodePtr n1, n2;
3915
3916
525k
  initNbSet1 = set1->nodeNr;
3917
1.07M
  for (i = 0;i < set2->nodeNr;i++) {
3918
546k
      n2 = set2->nodeTab[i];
3919
      /*
3920
      * Skip duplicates.
3921
      */
3922
22.4M
      for (j = 0; j < initNbSet1; j++) {
3923
22.4M
    n1 = set1->nodeTab[j];
3924
22.4M
    if (n1 == n2) {
3925
516k
        goto skip_node;
3926
21.9M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3927
21.9M
        (n2->type == XML_NAMESPACE_DECL))
3928
336k
    {
3929
336k
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930
336k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931
6.76k
      ((xmlNsPtr) n2)->prefix)))
3932
0
        {
3933
      /*
3934
      * Free the namespace node.
3935
      */
3936
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3937
0
      goto skip_node;
3938
0
        }
3939
336k
    }
3940
22.4M
      }
3941
      /*
3942
      * grow the nodeTab if needed
3943
      */
3944
30.4k
      if (set1->nodeMax == 0) {
3945
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3946
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3947
0
    if (set1->nodeTab == NULL) {
3948
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3949
0
        goto error;
3950
0
    }
3951
0
    memset(set1->nodeTab, 0,
3952
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3953
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3954
30.4k
      } else if (set1->nodeNr >= set1->nodeMax) {
3955
1.45k
    xmlNodePtr *temp;
3956
3957
1.45k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959
0
                    goto error;
3960
0
                }
3961
1.45k
    temp = (xmlNodePtr *) xmlRealloc(
3962
1.45k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963
1.45k
    if (temp == NULL) {
3964
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3965
0
        goto error;
3966
0
    }
3967
1.45k
    set1->nodeTab = temp;
3968
1.45k
    set1->nodeMax *= 2;
3969
1.45k
      }
3970
30.4k
      set1->nodeTab[set1->nodeNr++] = n2;
3971
546k
skip_node:
3972
546k
            set2->nodeTab[i] = NULL;
3973
546k
  }
3974
525k
    }
3975
525k
    set2->nodeNr = 0;
3976
525k
    return(set1);
3977
3978
0
error:
3979
0
    xmlXPathFreeNodeSet(set1);
3980
0
    xmlXPathNodeSetClear(set2, 1);
3981
0
    return(NULL);
3982
525k
}
3983
3984
/**
3985
 * xmlXPathNodeSetMergeAndClearNoDupls:
3986
 * @set1:  the first NodeSet or NULL
3987
 * @set2:  the second NodeSet
3988
 *
3989
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3990
 * Doesn't check for duplicate nodes. Clears set2.
3991
 *
3992
 * Returns @set1 once extended or NULL in case of error.
3993
 *
3994
 * Frees @set1 in case of error.
3995
 */
3996
static xmlNodeSetPtr
3997
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3998
143k
{
3999
143k
    {
4000
143k
  int i;
4001
143k
  xmlNodePtr n2;
4002
4003
613k
  for (i = 0;i < set2->nodeNr;i++) {
4004
470k
      n2 = set2->nodeTab[i];
4005
470k
      if (set1->nodeMax == 0) {
4006
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008
0
    if (set1->nodeTab == NULL) {
4009
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4010
0
        goto error;
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
470k
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
772
    xmlNodePtr *temp;
4017
4018
772
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    goto error;
4021
0
                }
4022
772
    temp = (xmlNodePtr *) xmlRealloc(
4023
772
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
772
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        goto error;
4027
0
    }
4028
772
    set1->nodeTab = temp;
4029
772
    set1->nodeMax *= 2;
4030
772
      }
4031
470k
      set1->nodeTab[set1->nodeNr++] = n2;
4032
470k
            set2->nodeTab[i] = NULL;
4033
470k
  }
4034
143k
    }
4035
143k
    set2->nodeNr = 0;
4036
143k
    return(set1);
4037
4038
0
error:
4039
0
    xmlXPathFreeNodeSet(set1);
4040
0
    xmlXPathNodeSetClear(set2, 1);
4041
0
    return(NULL);
4042
143k
}
4043
4044
/**
4045
 * xmlXPathNodeSetDel:
4046
 * @cur:  the initial node set
4047
 * @val:  an xmlNodePtr
4048
 *
4049
 * Removes an xmlNodePtr from an existing NodeSet
4050
 */
4051
void
4052
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4053
0
    int i;
4054
4055
0
    if (cur == NULL) return;
4056
0
    if (val == NULL) return;
4057
4058
    /*
4059
     * find node in nodeTab
4060
     */
4061
0
    for (i = 0;i < cur->nodeNr;i++)
4062
0
        if (cur->nodeTab[i] == val) break;
4063
4064
0
    if (i >= cur->nodeNr) { /* not found */
4065
#ifdef DEBUG
4066
        xmlGenericError(xmlGenericErrorContext,
4067
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4068
    val->name);
4069
#endif
4070
0
        return;
4071
0
    }
4072
0
    if ((cur->nodeTab[i] != NULL) &&
4073
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4075
0
    cur->nodeNr--;
4076
0
    for (;i < cur->nodeNr;i++)
4077
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4078
0
    cur->nodeTab[cur->nodeNr] = NULL;
4079
0
}
4080
4081
/**
4082
 * xmlXPathNodeSetRemove:
4083
 * @cur:  the initial node set
4084
 * @val:  the index to remove
4085
 *
4086
 * Removes an entry from an existing NodeSet list.
4087
 */
4088
void
4089
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4090
0
    if (cur == NULL) return;
4091
0
    if (val >= cur->nodeNr) return;
4092
0
    if ((cur->nodeTab[val] != NULL) &&
4093
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4094
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4095
0
    cur->nodeNr--;
4096
0
    for (;val < cur->nodeNr;val++)
4097
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4098
0
    cur->nodeTab[cur->nodeNr] = NULL;
4099
0
}
4100
4101
/**
4102
 * xmlXPathFreeNodeSet:
4103
 * @obj:  the xmlNodeSetPtr to free
4104
 *
4105
 * Free the NodeSet compound (not the actual nodes !).
4106
 */
4107
void
4108
481k
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109
481k
    if (obj == NULL) return;
4110
478k
    if (obj->nodeTab != NULL) {
4111
144k
  int i;
4112
4113
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114
10.8M
  for (i = 0;i < obj->nodeNr;i++)
4115
10.7M
      if ((obj->nodeTab[i] != NULL) &&
4116
10.7M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117
373k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118
144k
  xmlFree(obj->nodeTab);
4119
144k
    }
4120
478k
    xmlFree(obj);
4121
478k
}
4122
4123
/**
4124
 * xmlXPathNodeSetClearFromPos:
4125
 * @set: the node set to be cleared
4126
 * @pos: the start position to clear from
4127
 *
4128
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4129
 * are feed) starting with the entry at @pos, but does *not* free the list
4130
 * itself. Sets the length of the list to @pos.
4131
 */
4132
static void
4133
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4134
0
{
4135
0
    if ((set == NULL) || (pos >= set->nodeNr))
4136
0
  return;
4137
0
    else if ((hasNsNodes)) {
4138
0
  int i;
4139
0
  xmlNodePtr node;
4140
4141
0
  for (i = pos; i < set->nodeNr; i++) {
4142
0
      node = set->nodeTab[i];
4143
0
      if ((node != NULL) &&
4144
0
    (node->type == XML_NAMESPACE_DECL))
4145
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146
0
  }
4147
0
    }
4148
0
    set->nodeNr = pos;
4149
0
}
4150
4151
/**
4152
 * xmlXPathNodeSetClear:
4153
 * @set:  the node set to clear
4154
 *
4155
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4156
 * are feed), but does *not* free the list itself. Sets the length of the
4157
 * list to 0.
4158
 */
4159
static void
4160
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4161
0
{
4162
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4163
0
}
4164
4165
/**
4166
 * xmlXPathNodeSetKeepLast:
4167
 * @set: the node set to be cleared
4168
 *
4169
 * Move the last node to the first position and clear temporary XPath objects
4170
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4171
 * to 1.
4172
 */
4173
static void
4174
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4175
12
{
4176
12
    int i;
4177
12
    xmlNodePtr node;
4178
4179
12
    if ((set == NULL) || (set->nodeNr <= 1))
4180
0
  return;
4181
748k
    for (i = 0; i < set->nodeNr - 1; i++) {
4182
748k
        node = set->nodeTab[i];
4183
748k
        if ((node != NULL) &&
4184
748k
            (node->type == XML_NAMESPACE_DECL))
4185
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
748k
    }
4187
12
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188
12
    set->nodeNr = 1;
4189
12
}
4190
4191
/**
4192
 * xmlXPathFreeValueTree:
4193
 * @obj:  the xmlNodeSetPtr to free
4194
 *
4195
 * Free the NodeSet compound and the actual tree, this is different
4196
 * from xmlXPathFreeNodeSet()
4197
 */
4198
static void
4199
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4200
0
    int i;
4201
4202
0
    if (obj == NULL) return;
4203
4204
0
    if (obj->nodeTab != NULL) {
4205
0
  for (i = 0;i < obj->nodeNr;i++) {
4206
0
      if (obj->nodeTab[i] != NULL) {
4207
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4208
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4209
0
    } else {
4210
0
        xmlFreeNodeList(obj->nodeTab[i]);
4211
0
    }
4212
0
      }
4213
0
  }
4214
0
  xmlFree(obj->nodeTab);
4215
0
    }
4216
0
    xmlFree(obj);
4217
0
}
4218
4219
#if defined(DEBUG) || defined(DEBUG_STEP)
4220
/**
4221
 * xmlGenericErrorContextNodeSet:
4222
 * @output:  a FILE * for the output
4223
 * @obj:  the xmlNodeSetPtr to display
4224
 *
4225
 * Quick display of a NodeSet
4226
 */
4227
void
4228
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4229
    int i;
4230
4231
    if (output == NULL) output = xmlGenericErrorContext;
4232
    if (obj == NULL)  {
4233
        fprintf(output, "NodeSet == NULL !\n");
4234
  return;
4235
    }
4236
    if (obj->nodeNr == 0) {
4237
        fprintf(output, "NodeSet is empty\n");
4238
  return;
4239
    }
4240
    if (obj->nodeTab == NULL) {
4241
  fprintf(output, " nodeTab == NULL !\n");
4242
  return;
4243
    }
4244
    for (i = 0; i < obj->nodeNr; i++) {
4245
        if (obj->nodeTab[i] == NULL) {
4246
      fprintf(output, " NULL !\n");
4247
      return;
4248
        }
4249
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4250
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4251
      fprintf(output, " /");
4252
  else if (obj->nodeTab[i]->name == NULL)
4253
      fprintf(output, " noname!");
4254
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4255
    }
4256
    fprintf(output, "\n");
4257
}
4258
#endif
4259
4260
/**
4261
 * xmlXPathNewNodeSet:
4262
 * @val:  the NodePtr value
4263
 *
4264
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4265
 * it with the single Node @val
4266
 *
4267
 * Returns the newly created object.
4268
 */
4269
xmlXPathObjectPtr
4270
104k
xmlXPathNewNodeSet(xmlNodePtr val) {
4271
104k
    xmlXPathObjectPtr ret;
4272
4273
104k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274
104k
    if (ret == NULL) {
4275
11
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4276
11
  return(NULL);
4277
11
    }
4278
104k
    memset(ret, 0 , sizeof(xmlXPathObject));
4279
104k
    ret->type = XPATH_NODESET;
4280
104k
    ret->boolval = 0;
4281
    /* TODO: Check memory error. */
4282
104k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4283
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4284
#ifdef XP_DEBUG_OBJ_USAGE
4285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4286
#endif
4287
104k
    return(ret);
4288
104k
}
4289
4290
/**
4291
 * xmlXPathNewValueTree:
4292
 * @val:  the NodePtr value
4293
 *
4294
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4295
 * it with the tree root @val
4296
 *
4297
 * Returns the newly created object.
4298
 */
4299
xmlXPathObjectPtr
4300
0
xmlXPathNewValueTree(xmlNodePtr val) {
4301
0
    xmlXPathObjectPtr ret;
4302
4303
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304
0
    if (ret == NULL) {
4305
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4306
0
  return(NULL);
4307
0
    }
4308
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4309
0
    ret->type = XPATH_XSLT_TREE;
4310
0
    ret->boolval = 1;
4311
0
    ret->user = (void *) val;
4312
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4313
#ifdef XP_DEBUG_OBJ_USAGE
4314
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4315
#endif
4316
0
    return(ret);
4317
0
}
4318
4319
/**
4320
 * xmlXPathNewNodeSetList:
4321
 * @val:  an existing NodeSet
4322
 *
4323
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4324
 * it with the Nodeset @val
4325
 *
4326
 * Returns the newly created object.
4327
 */
4328
xmlXPathObjectPtr
4329
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4330
0
{
4331
0
    xmlXPathObjectPtr ret;
4332
0
    int i;
4333
4334
0
    if (val == NULL)
4335
0
        ret = NULL;
4336
0
    else if (val->nodeTab == NULL)
4337
0
        ret = xmlXPathNewNodeSet(NULL);
4338
0
    else {
4339
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4340
0
        if (ret) {
4341
0
            for (i = 1; i < val->nodeNr; ++i) {
4342
                /* TODO: Propagate memory error. */
4343
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4344
0
        < 0) break;
4345
0
      }
4346
0
  }
4347
0
    }
4348
4349
0
    return (ret);
4350
0
}
4351
4352
/**
4353
 * xmlXPathWrapNodeSet:
4354
 * @val:  the NodePtr value
4355
 *
4356
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4357
 *
4358
 * Returns the newly created object.
4359
 *
4360
 * In case of error the node set is destroyed and NULL is returned.
4361
 */
4362
xmlXPathObjectPtr
4363
25.9k
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364
25.9k
    xmlXPathObjectPtr ret;
4365
4366
25.9k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367
25.9k
    if (ret == NULL) {
4368
10
        xmlXPathErrMemory(NULL, "creating node set object\n");
4369
10
        xmlXPathFreeNodeSet(val);
4370
10
  return(NULL);
4371
10
    }
4372
25.9k
    memset(ret, 0 , sizeof(xmlXPathObject));
4373
25.9k
    ret->type = XPATH_NODESET;
4374
25.9k
    ret->nodesetval = val;
4375
#ifdef XP_DEBUG_OBJ_USAGE
4376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377
#endif
4378
25.9k
    return(ret);
4379
25.9k
}
4380
4381
/**
4382
 * xmlXPathFreeNodeSetList:
4383
 * @obj:  an existing NodeSetList object
4384
 *
4385
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4386
 * the list contrary to xmlXPathFreeObject().
4387
 */
4388
void
4389
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4390
0
    if (obj == NULL) return;
4391
#ifdef XP_DEBUG_OBJ_USAGE
4392
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4393
#endif
4394
0
    xmlFree(obj);
4395
0
}
4396
4397
/**
4398
 * xmlXPathDifference:
4399
 * @nodes1:  a node-set
4400
 * @nodes2:  a node-set
4401
 *
4402
 * Implements the EXSLT - Sets difference() function:
4403
 *    node-set set:difference (node-set, node-set)
4404
 *
4405
 * Returns the difference between the two node sets, or nodes1 if
4406
 *         nodes2 is empty
4407
 */
4408
xmlNodeSetPtr
4409
16.8k
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4410
16.8k
    xmlNodeSetPtr ret;
4411
16.8k
    int i, l1;
4412
16.8k
    xmlNodePtr cur;
4413
4414
16.8k
    if (xmlXPathNodeSetIsEmpty(nodes2))
4415
16.8k
  return(nodes1);
4416
4417
    /* TODO: Check memory error. */
4418
0
    ret = xmlXPathNodeSetCreate(NULL);
4419
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4420
0
  return(ret);
4421
4422
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4423
4424
0
    for (i = 0; i < l1; i++) {
4425
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4426
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4427
            /* TODO: Propagate memory error. */
4428
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4429
0
          break;
4430
0
  }
4431
0
    }
4432
0
    return(ret);
4433
0
}
4434
4435
/**
4436
 * xmlXPathIntersection:
4437
 * @nodes1:  a node-set
4438
 * @nodes2:  a node-set
4439
 *
4440
 * Implements the EXSLT - Sets intersection() function:
4441
 *    node-set set:intersection (node-set, node-set)
4442
 *
4443
 * Returns a node set comprising the nodes that are within both the
4444
 *         node sets passed as arguments
4445
 */
4446
xmlNodeSetPtr
4447
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4448
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4449
0
    int i, l1;
4450
0
    xmlNodePtr cur;
4451
4452
0
    if (ret == NULL)
4453
0
        return(ret);
4454
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4455
0
  return(ret);
4456
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
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
 * xmlXPathDistinctSorted:
4474
 * @nodes:  a node-set, sorted by document order
4475
 *
4476
 * Implements the EXSLT - Sets distinct() function:
4477
 *    node-set set:distinct (node-set)
4478
 *
4479
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4480
 *         it is empty
4481
 */
4482
xmlNodeSetPtr
4483
100
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4484
100
    xmlNodeSetPtr ret;
4485
100
    xmlHashTablePtr hash;
4486
100
    int i, l;
4487
100
    xmlChar * strval;
4488
100
    xmlNodePtr cur;
4489
4490
100
    if (xmlXPathNodeSetIsEmpty(nodes))
4491
0
  return(nodes);
4492
4493
100
    ret = xmlXPathNodeSetCreate(NULL);
4494
100
    if (ret == NULL)
4495
0
        return(ret);
4496
100
    l = xmlXPathNodeSetGetLength(nodes);
4497
100
    hash = xmlHashCreate (l);
4498
124k
    for (i = 0; i < l; i++) {
4499
124k
  cur = xmlXPathNodeSetItem(nodes, i);
4500
124k
  strval = xmlXPathCastNodeToString(cur);
4501
124k
  if (xmlHashLookup(hash, strval) == NULL) {
4502
11.0k
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
4503
2
                xmlFree(strval);
4504
2
                goto error;
4505
2
            }
4506
11.0k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4507
0
          goto error;
4508
113k
  } else {
4509
113k
      xmlFree(strval);
4510
113k
  }
4511
124k
    }
4512
98
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4513
98
    return(ret);
4514
4515
2
error:
4516
2
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4517
2
    xmlXPathFreeNodeSet(ret);
4518
2
    return(NULL);
4519
100
}
4520
4521
/**
4522
 * xmlXPathDistinct:
4523
 * @nodes:  a node-set
4524
 *
4525
 * Implements the EXSLT - Sets distinct() function:
4526
 *    node-set set:distinct (node-set)
4527
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4528
 * is called with the sorted node-set
4529
 *
4530
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4531
 *         it is empty
4532
 */
4533
xmlNodeSetPtr
4534
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4535
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
0
  return(nodes);
4537
4538
0
    xmlXPathNodeSetSort(nodes);
4539
0
    return(xmlXPathDistinctSorted(nodes));
4540
0
}
4541
4542
/**
4543
 * xmlXPathHasSameNodes:
4544
 * @nodes1:  a node-set
4545
 * @nodes2:  a node-set
4546
 *
4547
 * Implements the EXSLT - Sets has-same-nodes function:
4548
 *    boolean set:has-same-node(node-set, node-set)
4549
 *
4550
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4551
 *         otherwise
4552
 */
4553
int
4554
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4555
0
    int i, l;
4556
0
    xmlNodePtr cur;
4557
4558
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4559
0
  xmlXPathNodeSetIsEmpty(nodes2))
4560
0
  return(0);
4561
4562
0
    l = xmlXPathNodeSetGetLength(nodes1);
4563
0
    for (i = 0; i < l; i++) {
4564
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4565
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4566
0
      return(1);
4567
0
    }
4568
0
    return(0);
4569
0
}
4570
4571
/**
4572
 * xmlXPathNodeLeadingSorted:
4573
 * @nodes: a node-set, sorted by document order
4574
 * @node: a node
4575
 *
4576
 * Implements the EXSLT - Sets leading() function:
4577
 *    node-set set:leading (node-set, node-set)
4578
 *
4579
 * Returns the nodes in @nodes that precede @node in document order,
4580
 *         @nodes if @node is NULL or an empty node-set if @nodes
4581
 *         doesn't contain @node
4582
 */
4583
xmlNodeSetPtr
4584
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4585
0
    int i, l;
4586
0
    xmlNodePtr cur;
4587
0
    xmlNodeSetPtr ret;
4588
4589
0
    if (node == NULL)
4590
0
  return(nodes);
4591
4592
0
    ret = xmlXPathNodeSetCreate(NULL);
4593
0
    if (ret == NULL)
4594
0
        return(ret);
4595
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4596
0
  (!xmlXPathNodeSetContains(nodes, node)))
4597
0
  return(ret);
4598
4599
0
    l = xmlXPathNodeSetGetLength(nodes);
4600
0
    for (i = 0; i < l; i++) {
4601
0
  cur = xmlXPathNodeSetItem(nodes, i);
4602
0
  if (cur == node)
4603
0
      break;
4604
        /* TODO: Propagate memory error. */
4605
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4606
0
      break;
4607
0
    }
4608
0
    return(ret);
4609
0
}
4610
4611
/**
4612
 * xmlXPathNodeLeading:
4613
 * @nodes:  a node-set
4614
 * @node:  a node
4615
 *
4616
 * Implements the EXSLT - Sets leading() function:
4617
 *    node-set set:leading (node-set, node-set)
4618
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4619
 * is called.
4620
 *
4621
 * Returns the nodes in @nodes that precede @node in document order,
4622
 *         @nodes if @node is NULL or an empty node-set if @nodes
4623
 *         doesn't contain @node
4624
 */
4625
xmlNodeSetPtr
4626
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627
0
    xmlXPathNodeSetSort(nodes);
4628
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4629
0
}
4630
4631
/**
4632
 * xmlXPathLeadingSorted:
4633
 * @nodes1:  a node-set, sorted by document order
4634
 * @nodes2:  a node-set, sorted by document order
4635
 *
4636
 * Implements the EXSLT - Sets leading() function:
4637
 *    node-set set:leading (node-set, node-set)
4638
 *
4639
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4640
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4642
 */
4643
xmlNodeSetPtr
4644
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4646
0
  return(nodes1);
4647
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4648
0
             xmlXPathNodeSetItem(nodes2, 1)));
4649
0
}
4650
4651
/**
4652
 * xmlXPathLeading:
4653
 * @nodes1:  a node-set
4654
 * @nodes2:  a node-set
4655
 *
4656
 * Implements the EXSLT - Sets leading() function:
4657
 *    node-set set:leading (node-set, node-set)
4658
 * @nodes1 and @nodes2 are sorted by document order, then
4659
 * #exslSetsLeadingSorted is called.
4660
 *
4661
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4662
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4664
 */
4665
xmlNodeSetPtr
4666
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4668
0
  return(nodes1);
4669
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4670
0
  return(xmlXPathNodeSetCreate(NULL));
4671
0
    xmlXPathNodeSetSort(nodes1);
4672
0
    xmlXPathNodeSetSort(nodes2);
4673
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4674
0
             xmlXPathNodeSetItem(nodes2, 1)));
4675
0
}
4676
4677
/**
4678
 * xmlXPathNodeTrailingSorted:
4679
 * @nodes: a node-set, sorted by document order
4680
 * @node: a node
4681
 *
4682
 * Implements the EXSLT - Sets trailing() function:
4683
 *    node-set set:trailing (node-set, node-set)
4684
 *
4685
 * Returns the nodes in @nodes that follow @node in document order,
4686
 *         @nodes if @node is NULL or an empty node-set if @nodes
4687
 *         doesn't contain @node
4688
 */
4689
xmlNodeSetPtr
4690
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4691
0
    int i, l;
4692
0
    xmlNodePtr cur;
4693
0
    xmlNodeSetPtr ret;
4694
4695
0
    if (node == NULL)
4696
0
  return(nodes);
4697
4698
0
    ret = xmlXPathNodeSetCreate(NULL);
4699
0
    if (ret == NULL)
4700
0
        return(ret);
4701
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4702
0
  (!xmlXPathNodeSetContains(nodes, node)))
4703
0
  return(ret);
4704
4705
0
    l = xmlXPathNodeSetGetLength(nodes);
4706
0
    for (i = l - 1; i >= 0; i--) {
4707
0
  cur = xmlXPathNodeSetItem(nodes, i);
4708
0
  if (cur == node)
4709
0
      break;
4710
        /* TODO: Propagate memory error. */
4711
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4712
0
      break;
4713
0
    }
4714
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4715
0
    return(ret);
4716
0
}
4717
4718
/**
4719
 * xmlXPathNodeTrailing:
4720
 * @nodes:  a node-set
4721
 * @node:  a node
4722
 *
4723
 * Implements the EXSLT - Sets trailing() function:
4724
 *    node-set set:trailing (node-set, node-set)
4725
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4726
 * is called.
4727
 *
4728
 * Returns the nodes in @nodes that follow @node in document order,
4729
 *         @nodes if @node is NULL or an empty node-set if @nodes
4730
 *         doesn't contain @node
4731
 */
4732
xmlNodeSetPtr
4733
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4734
0
    xmlXPathNodeSetSort(nodes);
4735
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4736
0
}
4737
4738
/**
4739
 * xmlXPathTrailingSorted:
4740
 * @nodes1:  a node-set, sorted by document order
4741
 * @nodes2:  a node-set, sorted by document order
4742
 *
4743
 * Implements the EXSLT - Sets trailing() function:
4744
 *    node-set set:trailing (node-set, node-set)
4745
 *
4746
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4747
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4748
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4749
 */
4750
xmlNodeSetPtr
4751
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4752
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4753
0
  return(nodes1);
4754
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4755
0
              xmlXPathNodeSetItem(nodes2, 0)));
4756
0
}
4757
4758
/**
4759
 * xmlXPathTrailing:
4760
 * @nodes1:  a node-set
4761
 * @nodes2:  a node-set
4762
 *
4763
 * Implements the EXSLT - Sets trailing() function:
4764
 *    node-set set:trailing (node-set, node-set)
4765
 * @nodes1 and @nodes2 are sorted by document order, then
4766
 * #xmlXPathTrailingSorted is called.
4767
 *
4768
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4769
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4770
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4771
 */
4772
xmlNodeSetPtr
4773
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4774
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4775
0
  return(nodes1);
4776
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4777
0
  return(xmlXPathNodeSetCreate(NULL));
4778
0
    xmlXPathNodeSetSort(nodes1);
4779
0
    xmlXPathNodeSetSort(nodes2);
4780
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4781
0
              xmlXPathNodeSetItem(nodes2, 0)));
4782
0
}
4783
4784
/************************************************************************
4785
 *                  *
4786
 *    Routines to handle extra functions      *
4787
 *                  *
4788
 ************************************************************************/
4789
4790
/**
4791
 * xmlXPathRegisterFunc:
4792
 * @ctxt:  the XPath context
4793
 * @name:  the function name
4794
 * @f:  the function implementation or NULL
4795
 *
4796
 * Register a new function. If @f is NULL it unregisters the function
4797
 *
4798
 * Returns 0 in case of success, -1 in case of error
4799
 */
4800
int
4801
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4802
14.4k
         xmlXPathFunction f) {
4803
14.4k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4804
14.4k
}
4805
4806
/**
4807
 * xmlXPathRegisterFuncNS:
4808
 * @ctxt:  the XPath context
4809
 * @name:  the function name
4810
 * @ns_uri:  the function namespace URI
4811
 * @f:  the function implementation or NULL
4812
 *
4813
 * Register a new function. If @f is NULL it unregisters the function
4814
 *
4815
 * Returns 0 in case of success, -1 in case of error
4816
 */
4817
int
4818
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4819
14.9k
           const xmlChar *ns_uri, xmlXPathFunction f) {
4820
14.9k
    if (ctxt == NULL)
4821
0
  return(-1);
4822
14.9k
    if (name == NULL)
4823
0
  return(-1);
4824
4825
14.9k
    if (ctxt->funcHash == NULL)
4826
0
  ctxt->funcHash = xmlHashCreate(0);
4827
14.9k
    if (ctxt->funcHash == NULL)
4828
0
  return(-1);
4829
14.9k
    if (f == NULL)
4830
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831
14.9k
XML_IGNORE_FPTR_CAST_WARNINGS
4832
14.9k
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833
14.9k
XML_POP_WARNINGS
4834
14.9k
}
4835
4836
/**
4837
 * xmlXPathRegisterFuncLookup:
4838
 * @ctxt:  the XPath context
4839
 * @f:  the lookup function
4840
 * @funcCtxt:  the lookup data
4841
 *
4842
 * Registers an external mechanism to do function lookup.
4843
 */
4844
void
4845
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4846
          xmlXPathFuncLookupFunc f,
4847
399
          void *funcCtxt) {
4848
399
    if (ctxt == NULL)
4849
0
  return;
4850
399
    ctxt->funcLookupFunc = f;
4851
399
    ctxt->funcLookupData = funcCtxt;
4852
399
}
4853
4854
/**
4855
 * xmlXPathFunctionLookup:
4856
 * @ctxt:  the XPath context
4857
 * @name:  the function name
4858
 *
4859
 * Search in the Function array of the context for the given
4860
 * function.
4861
 *
4862
 * Returns the xmlXPathFunction or NULL if not found
4863
 */
4864
xmlXPathFunction
4865
73
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4866
73
    if (ctxt == NULL)
4867
0
  return (NULL);
4868
4869
73
    if (ctxt->funcLookupFunc != NULL) {
4870
73
  xmlXPathFunction ret;
4871
73
  xmlXPathFuncLookupFunc f;
4872
4873
73
  f = ctxt->funcLookupFunc;
4874
73
  ret = f(ctxt->funcLookupData, name, NULL);
4875
73
  if (ret != NULL)
4876
0
      return(ret);
4877
73
    }
4878
73
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4879
73
}
4880
4881
/**
4882
 * xmlXPathFunctionLookupNS:
4883
 * @ctxt:  the XPath context
4884
 * @name:  the function name
4885
 * @ns_uri:  the function namespace URI
4886
 *
4887
 * Search in the Function array of the context for the given
4888
 * function.
4889
 *
4890
 * Returns the xmlXPathFunction or NULL if not found
4891
 */
4892
xmlXPathFunction
4893
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4894
246
       const xmlChar *ns_uri) {
4895
246
    xmlXPathFunction ret;
4896
4897
246
    if (ctxt == NULL)
4898
0
  return(NULL);
4899
246
    if (name == NULL)
4900
0
  return(NULL);
4901
4902
246
    if (ctxt->funcLookupFunc != NULL) {
4903
246
  xmlXPathFuncLookupFunc f;
4904
4905
246
  f = ctxt->funcLookupFunc;
4906
246
  ret = f(ctxt->funcLookupData, name, ns_uri);
4907
246
  if (ret != NULL)
4908
173
      return(ret);
4909
246
    }
4910
4911
73
    if (ctxt->funcHash == NULL)
4912
0
  return(NULL);
4913
4914
73
XML_IGNORE_FPTR_CAST_WARNINGS
4915
73
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4916
73
XML_POP_WARNINGS
4917
73
    return(ret);
4918
73
}
4919
4920
/**
4921
 * xmlXPathRegisteredFuncsCleanup:
4922
 * @ctxt:  the XPath context
4923
 *
4924
 * Cleanup the XPath context data associated to registered functions
4925
 */
4926
void
4927
402
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928
402
    if (ctxt == NULL)
4929
0
  return;
4930
4931
402
    xmlHashFree(ctxt->funcHash, NULL);
4932
402
    ctxt->funcHash = NULL;
4933
402
}
4934
4935
/************************************************************************
4936
 *                  *
4937
 *      Routines to handle Variables      *
4938
 *                  *
4939
 ************************************************************************/
4940
4941
/**
4942
 * xmlXPathRegisterVariable:
4943
 * @ctxt:  the XPath context
4944
 * @name:  the variable name
4945
 * @value:  the variable value or NULL
4946
 *
4947
 * Register a new variable value. If @value is NULL it unregisters
4948
 * the variable
4949
 *
4950
 * Returns 0 in case of success, -1 in case of error
4951
 */
4952
int
4953
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4954
1.59k
       xmlXPathObjectPtr value) {
4955
1.59k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956
1.59k
}
4957
4958
/**
4959
 * xmlXPathRegisterVariableNS:
4960
 * @ctxt:  the XPath context
4961
 * @name:  the variable name
4962
 * @ns_uri:  the variable namespace URI
4963
 * @value:  the variable value or NULL
4964
 *
4965
 * Register a new variable value. If @value is NULL it unregisters
4966
 * the variable
4967
 *
4968
 * Returns 0 in case of success, -1 in case of error
4969
 */
4970
int
4971
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972
         const xmlChar *ns_uri,
4973
1.59k
         xmlXPathObjectPtr value) {
4974
1.59k
    if (ctxt == NULL)
4975
0
  return(-1);
4976
1.59k
    if (name == NULL)
4977
0
  return(-1);
4978
4979
1.59k
    if (ctxt->varHash == NULL)
4980
399
  ctxt->varHash = xmlHashCreate(0);
4981
1.59k
    if (ctxt->varHash == NULL)
4982
0
  return(-1);
4983
1.59k
    if (value == NULL)
4984
3
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985
3
                             xmlXPathFreeObjectEntry));
4986
1.59k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987
1.59k
             (void *) value, xmlXPathFreeObjectEntry));
4988
1.59k
}
4989
4990
/**
4991
 * xmlXPathRegisterVariableLookup:
4992
 * @ctxt:  the XPath context
4993
 * @f:  the lookup function
4994
 * @data:  the lookup data
4995
 *
4996
 * register an external mechanism to do variable lookup
4997
 */
4998
void
4999
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5000
399
   xmlXPathVariableLookupFunc f, void *data) {
5001
399
    if (ctxt == NULL)
5002
0
  return;
5003
399
    ctxt->varLookupFunc = f;
5004
399
    ctxt->varLookupData = data;
5005
399
}
5006
5007
/**
5008
 * xmlXPathVariableLookup:
5009
 * @ctxt:  the XPath context
5010
 * @name:  the variable name
5011
 *
5012
 * Search in the Variable array of the context for the given
5013
 * variable value.
5014
 *
5015
 * Returns a copy of the value or NULL if not found
5016
 */
5017
xmlXPathObjectPtr
5018
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5019
0
    if (ctxt == NULL)
5020
0
  return(NULL);
5021
5022
0
    if (ctxt->varLookupFunc != NULL) {
5023
0
  xmlXPathObjectPtr ret;
5024
5025
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5026
0
          (ctxt->varLookupData, name, NULL);
5027
0
  return(ret);
5028
0
    }
5029
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5030
0
}
5031
5032
/**
5033
 * xmlXPathVariableLookupNS:
5034
 * @ctxt:  the XPath context
5035
 * @name:  the variable name
5036
 * @ns_uri:  the variable namespace URI
5037
 *
5038
 * Search in the Variable array of the context for the given
5039
 * variable value.
5040
 *
5041
 * Returns the a copy of the value or NULL if not found
5042
 */
5043
xmlXPathObjectPtr
5044
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5045
0
       const xmlChar *ns_uri) {
5046
0
    if (ctxt == NULL)
5047
0
  return(NULL);
5048
5049
0
    if (ctxt->varLookupFunc != NULL) {
5050
0
  xmlXPathObjectPtr ret;
5051
5052
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5053
0
          (ctxt->varLookupData, name, ns_uri);
5054
0
  if (ret != NULL) return(ret);
5055
0
    }
5056
5057
0
    if (ctxt->varHash == NULL)
5058
0
  return(NULL);
5059
0
    if (name == NULL)
5060
0
  return(NULL);
5061
5062
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5063
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5064
0
}
5065
5066
/**
5067
 * xmlXPathRegisteredVariablesCleanup:
5068
 * @ctxt:  the XPath context
5069
 *
5070
 * Cleanup the XPath context data associated to registered variables
5071
 */
5072
void
5073
402
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074
402
    if (ctxt == NULL)
5075
0
  return;
5076
5077
402
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078
402
    ctxt->varHash = NULL;
5079
402
}
5080
5081
/**
5082
 * xmlXPathRegisterNs:
5083
 * @ctxt:  the XPath context
5084
 * @prefix:  the namespace prefix cannot be NULL or empty string
5085
 * @ns_uri:  the namespace name
5086
 *
5087
 * Register a new namespace. If @ns_uri is NULL it unregisters
5088
 * the namespace
5089
 *
5090
 * Returns 0 in case of success, -1 in case of error
5091
 */
5092
int
5093
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5094
4.38k
         const xmlChar *ns_uri) {
5095
4.38k
    xmlChar *copy;
5096
5097
4.38k
    if (ctxt == NULL)
5098
0
  return(-1);
5099
4.38k
    if (prefix == NULL)
5100
0
  return(-1);
5101
4.38k
    if (prefix[0] == 0)
5102
0
  return(-1);
5103
5104
4.38k
    if (ctxt->nsHash == NULL)
5105
399
  ctxt->nsHash = xmlHashCreate(10);
5106
4.38k
    if (ctxt->nsHash == NULL)
5107
0
  return(-1);
5108
4.38k
    if (ns_uri == NULL)
5109
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110
0
                            xmlHashDefaultDeallocator));
5111
5112
4.38k
    copy = xmlStrdup(ns_uri);
5113
4.38k
    if (copy == NULL)
5114
0
        return(-1);
5115
4.38k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116
4.38k
                           xmlHashDefaultDeallocator) < 0) {
5117
0
        xmlFree(copy);
5118
0
        return(-1);
5119
0
    }
5120
5121
4.38k
    return(0);
5122
4.38k
}
5123
5124
/**
5125
 * xmlXPathNsLookup:
5126
 * @ctxt:  the XPath context
5127
 * @prefix:  the namespace prefix value
5128
 *
5129
 * Search in the namespace declaration array of the context for the given
5130
 * namespace name associated to the given prefix
5131
 *
5132
 * Returns the value or NULL if not found
5133
 */
5134
const xmlChar *
5135
121k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136
121k
    if (ctxt == NULL)
5137
0
  return(NULL);
5138
121k
    if (prefix == NULL)
5139
0
  return(NULL);
5140
5141
121k
#ifdef XML_XML_NAMESPACE
5142
121k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143
0
  return(XML_XML_NAMESPACE);
5144
121k
#endif
5145
5146
121k
    if (ctxt->namespaces != NULL) {
5147
0
  int i;
5148
5149
0
  for (i = 0;i < ctxt->nsNr;i++) {
5150
0
      if ((ctxt->namespaces[i] != NULL) &&
5151
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5152
0
    return(ctxt->namespaces[i]->href);
5153
0
  }
5154
0
    }
5155
5156
121k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157
121k
}
5158
5159
/**
5160
 * xmlXPathRegisteredNsCleanup:
5161
 * @ctxt:  the XPath context
5162
 *
5163
 * Cleanup the XPath context data associated to registered variables
5164
 */
5165
void
5166
812
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167
812
    if (ctxt == NULL)
5168
11
  return;
5169
5170
801
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171
801
    ctxt->nsHash = NULL;
5172
801
}
5173
5174
/************************************************************************
5175
 *                  *
5176
 *      Routines to handle Values     *
5177
 *                  *
5178
 ************************************************************************/
5179
5180
/* Allocations are terrible, one needs to optimize all this !!! */
5181
5182
/**
5183
 * xmlXPathNewFloat:
5184
 * @val:  the double value
5185
 *
5186
 * Create a new xmlXPathObjectPtr of type double and of value @val
5187
 *
5188
 * Returns the newly created object.
5189
 */
5190
xmlXPathObjectPtr
5191
209k
xmlXPathNewFloat(double val) {
5192
209k
    xmlXPathObjectPtr ret;
5193
5194
209k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195
209k
    if (ret == NULL) {
5196
6
        xmlXPathErrMemory(NULL, "creating float object\n");
5197
6
  return(NULL);
5198
6
    }
5199
209k
    memset(ret, 0 , sizeof(xmlXPathObject));
5200
209k
    ret->type = XPATH_NUMBER;
5201
209k
    ret->floatval = val;
5202
#ifdef XP_DEBUG_OBJ_USAGE
5203
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204
#endif
5205
209k
    return(ret);
5206
209k
}
5207
5208
/**
5209
 * xmlXPathNewBoolean:
5210
 * @val:  the boolean value
5211
 *
5212
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5213
 *
5214
 * Returns the newly created object.
5215
 */
5216
xmlXPathObjectPtr
5217
485
xmlXPathNewBoolean(int val) {
5218
485
    xmlXPathObjectPtr ret;
5219
5220
485
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221
485
    if (ret == NULL) {
5222
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5223
0
  return(NULL);
5224
0
    }
5225
485
    memset(ret, 0 , sizeof(xmlXPathObject));
5226
485
    ret->type = XPATH_BOOLEAN;
5227
485
    ret->boolval = (val != 0);
5228
#ifdef XP_DEBUG_OBJ_USAGE
5229
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230
#endif
5231
485
    return(ret);
5232
485
}
5233
5234
/**
5235
 * xmlXPathNewString:
5236
 * @val:  the xmlChar * value
5237
 *
5238
 * Create a new xmlXPathObjectPtr of type string and of value @val
5239
 *
5240
 * Returns the newly created object.
5241
 */
5242
xmlXPathObjectPtr
5243
2.47k
xmlXPathNewString(const xmlChar *val) {
5244
2.47k
    xmlXPathObjectPtr ret;
5245
5246
2.47k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
2.47k
    if (ret == NULL) {
5248
4
        xmlXPathErrMemory(NULL, "creating string object\n");
5249
4
  return(NULL);
5250
4
    }
5251
2.46k
    memset(ret, 0 , sizeof(xmlXPathObject));
5252
2.46k
    ret->type = XPATH_STRING;
5253
2.46k
    if (val == NULL)
5254
0
        val = BAD_CAST "";
5255
2.46k
    ret->stringval = xmlStrdup(val);
5256
2.46k
    if (ret->stringval == NULL) {
5257
0
        xmlFree(ret);
5258
0
        return(NULL);
5259
0
    }
5260
#ifdef XP_DEBUG_OBJ_USAGE
5261
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5262
#endif
5263
2.46k
    return(ret);
5264
2.46k
}
5265
5266
/**
5267
 * xmlXPathWrapString:
5268
 * @val:  the xmlChar * value
5269
 *
5270
 * Wraps the @val string into an XPath object.
5271
 *
5272
 * Returns the newly created object.
5273
 *
5274
 * Frees @val in case of error.
5275
 */
5276
xmlXPathObjectPtr
5277
183k
xmlXPathWrapString (xmlChar *val) {
5278
183k
    xmlXPathObjectPtr ret;
5279
5280
183k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281
183k
    if (ret == NULL) {
5282
1
        xmlXPathErrMemory(NULL, "creating string object\n");
5283
1
        xmlFree(val);
5284
1
  return(NULL);
5285
1
    }
5286
183k
    memset(ret, 0 , sizeof(xmlXPathObject));
5287
183k
    ret->type = XPATH_STRING;
5288
183k
    ret->stringval = val;
5289
#ifdef XP_DEBUG_OBJ_USAGE
5290
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291
#endif
5292
183k
    return(ret);
5293
183k
}
5294
5295
/**
5296
 * xmlXPathNewCString:
5297
 * @val:  the char * value
5298
 *
5299
 * Create a new xmlXPathObjectPtr of type string and of value @val
5300
 *
5301
 * Returns the newly created object.
5302
 */
5303
xmlXPathObjectPtr
5304
1.64k
xmlXPathNewCString(const char *val) {
5305
1.64k
    return(xmlXPathNewString(BAD_CAST val));
5306
1.64k
}
5307
5308
/**
5309
 * xmlXPathWrapCString:
5310
 * @val:  the char * value
5311
 *
5312
 * Wraps a string into an XPath object.
5313
 *
5314
 * Returns the newly created object.
5315
 */
5316
xmlXPathObjectPtr
5317
0
xmlXPathWrapCString (char * val) {
5318
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5319
0
}
5320
5321
/**
5322
 * xmlXPathWrapExternal:
5323
 * @val:  the user data
5324
 *
5325
 * Wraps the @val data into an XPath object.
5326
 *
5327
 * Returns the newly created object.
5328
 */
5329
xmlXPathObjectPtr
5330
0
xmlXPathWrapExternal (void *val) {
5331
0
    xmlXPathObjectPtr ret;
5332
5333
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334
0
    if (ret == NULL) {
5335
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5336
0
  return(NULL);
5337
0
    }
5338
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5339
0
    ret->type = XPATH_USERS;
5340
0
    ret->user = val;
5341
#ifdef XP_DEBUG_OBJ_USAGE
5342
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343
#endif
5344
0
    return(ret);
5345
0
}
5346
5347
/**
5348
 * xmlXPathObjectCopy:
5349
 * @val:  the original object
5350
 *
5351
 * allocate a new copy of a given object
5352
 *
5353
 * Returns the newly created object.
5354
 */
5355
xmlXPathObjectPtr
5356
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5357
0
    xmlXPathObjectPtr ret;
5358
5359
0
    if (val == NULL)
5360
0
  return(NULL);
5361
5362
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5363
0
    if (ret == NULL) {
5364
0
        xmlXPathErrMemory(NULL, "copying object\n");
5365
0
  return(NULL);
5366
0
    }
5367
0
    memcpy(ret, val , sizeof(xmlXPathObject));
5368
#ifdef XP_DEBUG_OBJ_USAGE
5369
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5370
#endif
5371
0
    switch (val->type) {
5372
0
  case XPATH_BOOLEAN:
5373
0
  case XPATH_NUMBER:
5374
#ifdef LIBXML_XPTR_LOCS_ENABLED
5375
  case XPATH_POINT:
5376
  case XPATH_RANGE:
5377
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5378
0
      break;
5379
0
  case XPATH_STRING:
5380
0
      ret->stringval = xmlStrdup(val->stringval);
5381
0
            if (ret->stringval == NULL) {
5382
0
                xmlFree(ret);
5383
0
                return(NULL);
5384
0
            }
5385
0
      break;
5386
0
  case XPATH_XSLT_TREE:
5387
#if 0
5388
/*
5389
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390
  this previous handling is no longer correct, and can cause some serious
5391
  problems (ref. bug 145547)
5392
*/
5393
      if ((val->nodesetval != NULL) &&
5394
    (val->nodesetval->nodeTab != NULL)) {
5395
    xmlNodePtr cur, tmp;
5396
    xmlDocPtr top;
5397
5398
    ret->boolval = 1;
5399
    top =  xmlNewDoc(NULL);
5400
    top->name = (char *)
5401
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5402
    ret->user = top;
5403
    if (top != NULL) {
5404
        top->doc = top;
5405
        cur = val->nodesetval->nodeTab[0]->children;
5406
        while (cur != NULL) {
5407
      tmp = xmlDocCopyNode(cur, top, 1);
5408
      xmlAddChild((xmlNodePtr) top, tmp);
5409
      cur = cur->next;
5410
        }
5411
    }
5412
5413
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5414
      } else
5415
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5416
      /* Deallocate the copied tree value */
5417
      break;
5418
#endif
5419
0
  case XPATH_NODESET:
5420
            /* TODO: Check memory error. */
5421
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5422
      /* Do not deallocate the copied tree value */
5423
0
      ret->boolval = 0;
5424
0
      break;
5425
#ifdef LIBXML_XPTR_LOCS_ENABLED
5426
  case XPATH_LOCATIONSET:
5427
  {
5428
      xmlLocationSetPtr loc = val->user;
5429
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5430
      break;
5431
  }
5432
#endif
5433
0
        case XPATH_USERS:
5434
0
      ret->user = val->user;
5435
0
      break;
5436
0
        case XPATH_UNDEFINED:
5437
0
      xmlGenericError(xmlGenericErrorContext,
5438
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5439
0
        val->type);
5440
0
      break;
5441
0
    }
5442
0
    return(ret);
5443
0
}
5444
5445
/**
5446
 * xmlXPathFreeObject:
5447
 * @obj:  the object to free
5448
 *
5449
 * Free up an xmlXPathObjectPtr object.
5450
 */
5451
void
5452
290k
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453
290k
    if (obj == NULL) return;
5454
109k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455
66.8k
  if (obj->boolval) {
5456
#if 0
5457
      if (obj->user != NULL) {
5458
                xmlXPathFreeNodeSet(obj->nodesetval);
5459
    xmlFreeNodeList((xmlNodePtr) obj->user);
5460
      } else
5461
#endif
5462
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5463
0
      if (obj->nodesetval != NULL)
5464
0
    xmlXPathFreeValueTree(obj->nodesetval);
5465
66.8k
  } else {
5466
66.8k
      if (obj->nodesetval != NULL)
5467
66.8k
    xmlXPathFreeNodeSet(obj->nodesetval);
5468
66.8k
  }
5469
#ifdef LIBXML_XPTR_LOCS_ENABLED
5470
    } else if (obj->type == XPATH_LOCATIONSET) {
5471
  if (obj->user != NULL)
5472
      xmlXPtrFreeLocationSet(obj->user);
5473
#endif
5474
66.8k
    } else if (obj->type == XPATH_STRING) {
5475
32.6k
  if (obj->stringval != NULL)
5476
32.6k
      xmlFree(obj->stringval);
5477
32.6k
    }
5478
#ifdef XP_DEBUG_OBJ_USAGE
5479
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480
#endif
5481
109k
    xmlFree(obj);
5482
109k
}
5483
5484
static void
5485
1.59k
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486
1.59k
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487
1.59k
}
5488
5489
/**
5490
 * xmlXPathReleaseObject:
5491
 * @obj:  the xmlXPathObjectPtr to free or to cache
5492
 *
5493
 * Depending on the state of the cache this frees the given
5494
 * XPath object or stores it in the cache.
5495
 */
5496
static void
5497
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5498
5.26M
{
5499
5.26M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500
856
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501
4.86M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502
5503
5.82M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504
5505
5.26M
    if (obj == NULL)
5506
0
  return;
5507
5.26M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508
0
   xmlXPathFreeObject(obj);
5509
5.26M
    } else {
5510
5.26M
  xmlXPathContextCachePtr cache =
5511
5.26M
      (xmlXPathContextCachePtr) ctxt->cache;
5512
5513
5.26M
  switch (obj->type) {
5514
861k
      case XPATH_NODESET:
5515
861k
      case XPATH_XSLT_TREE:
5516
861k
    if (obj->nodesetval != NULL) {
5517
601k
        if (obj->boolval) {
5518
      /*
5519
      * It looks like the @boolval is used for
5520
      * evaluation if this an XSLT Result Tree Fragment.
5521
      * TODO: Check if this assumption is correct.
5522
      */
5523
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5524
0
      xmlXPathFreeValueTree(obj->nodesetval);
5525
0
      obj->nodesetval = NULL;
5526
601k
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5527
601k
      (XP_CACHE_WANTS(cache->nodesetObjs,
5528
599k
          cache->maxNodeset)))
5529
413k
        {
5530
413k
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5531
413k
      goto obj_cached;
5532
413k
        } else {
5533
188k
      xmlXPathFreeNodeSet(obj->nodesetval);
5534
188k
      obj->nodesetval = NULL;
5535
188k
        }
5536
601k
    }
5537
447k
    break;
5538
2.05M
      case XPATH_STRING:
5539
2.05M
    if (obj->stringval != NULL)
5540
2.05M
        xmlFree(obj->stringval);
5541
5542
2.05M
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543
1.87M
        XP_CACHE_ADD(cache->stringObjs, obj);
5544
1.87M
        goto obj_cached;
5545
1.87M
    }
5546
182k
    break;
5547
182k
      case XPATH_BOOLEAN:
5548
10.4k
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549
10.4k
        XP_CACHE_ADD(cache->booleanObjs, obj);
5550
10.4k
        goto obj_cached;
5551
10.4k
    }
5552
0
    break;
5553
2.33M
      case XPATH_NUMBER:
5554
2.33M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555
2.13M
        XP_CACHE_ADD(cache->numberObjs, obj);
5556
2.13M
        goto obj_cached;
5557
2.13M
    }
5558
198k
    break;
5559
#ifdef LIBXML_XPTR_LOCS_ENABLED
5560
      case XPATH_LOCATIONSET:
5561
    if (obj->user != NULL) {
5562
        xmlXPtrFreeLocationSet(obj->user);
5563
    }
5564
    goto free_obj;
5565
#endif
5566
198k
      default:
5567
0
    goto free_obj;
5568
5.26M
  }
5569
5570
  /*
5571
  * Fallback to adding to the misc-objects slot.
5572
  */
5573
828k
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574
430k
      XP_CACHE_ADD(cache->miscObjs, obj);
5575
430k
  } else
5576
398k
      goto free_obj;
5577
5578
4.86M
obj_cached:
5579
5580
#ifdef XP_DEBUG_OBJ_USAGE
5581
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582
#endif
5583
5584
4.86M
  if (obj->nodesetval != NULL) {
5585
413k
      xmlNodeSetPtr tmpset = obj->nodesetval;
5586
5587
      /*
5588
      * TODO: Due to those nasty ns-nodes, we need to traverse
5589
      *  the list and free the ns-nodes.
5590
      * URGENT TODO: Check if it's actually slowing things down.
5591
      *  Maybe we shouldn't try to preserve the list.
5592
      */
5593
413k
      if (tmpset->nodeNr > 1) {
5594
1.25k
    int i;
5595
1.25k
    xmlNodePtr node;
5596
5597
15.3k
    for (i = 0; i < tmpset->nodeNr; i++) {
5598
14.1k
        node = tmpset->nodeTab[i];
5599
14.1k
        if ((node != NULL) &&
5600
14.1k
      (node->type == XML_NAMESPACE_DECL))
5601
2.11k
        {
5602
2.11k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603
2.11k
        }
5604
14.1k
    }
5605
412k
      } else if (tmpset->nodeNr == 1) {
5606
406k
    if ((tmpset->nodeTab[0] != NULL) &&
5607
406k
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608
3.49k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609
406k
      }
5610
413k
      tmpset->nodeNr = 0;
5611
413k
      memset(obj, 0, sizeof(xmlXPathObject));
5612
413k
      obj->nodesetval = tmpset;
5613
413k
  } else
5614
4.45M
      memset(obj, 0, sizeof(xmlXPathObject));
5615
5616
4.86M
  return;
5617
5618
398k
free_obj:
5619
  /*
5620
  * Cache is full; free the object.
5621
  */
5622
398k
  if (obj->nodesetval != NULL)
5623
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5624
#ifdef XP_DEBUG_OBJ_USAGE
5625
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626
#endif
5627
398k
  xmlFree(obj);
5628
398k
    }
5629
398k
    return;
5630
5.26M
}
5631
5632
5633
/************************************************************************
5634
 *                  *
5635
 *      Type Casting Routines       *
5636
 *                  *
5637
 ************************************************************************/
5638
5639
/**
5640
 * xmlXPathCastBooleanToString:
5641
 * @val:  a boolean
5642
 *
5643
 * Converts a boolean to its string value.
5644
 *
5645
 * Returns a newly allocated string.
5646
 */
5647
xmlChar *
5648
93
xmlXPathCastBooleanToString (int val) {
5649
93
    xmlChar *ret;
5650
93
    if (val)
5651
24
  ret = xmlStrdup((const xmlChar *) "true");
5652
69
    else
5653
69
  ret = xmlStrdup((const xmlChar *) "false");
5654
93
    return(ret);
5655
93
}
5656
5657
/**
5658
 * xmlXPathCastNumberToString:
5659
 * @val:  a number
5660
 *
5661
 * Converts a number to its string value.
5662
 *
5663
 * Returns a newly allocated string.
5664
 */
5665
xmlChar *
5666
3.02k
xmlXPathCastNumberToString (double val) {
5667
3.02k
    xmlChar *ret;
5668
3.02k
    switch (xmlXPathIsInf(val)) {
5669
0
    case 1:
5670
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5671
0
  break;
5672
0
    case -1:
5673
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5674
0
  break;
5675
3.02k
    default:
5676
3.02k
  if (xmlXPathIsNaN(val)) {
5677
1.62k
      ret = xmlStrdup((const xmlChar *) "NaN");
5678
1.62k
  } else if (val == 0) {
5679
            /* Omit sign for negative zero. */
5680
1.35k
      ret = xmlStrdup((const xmlChar *) "0");
5681
1.35k
  } else {
5682
      /* could be improved */
5683
41
      char buf[100];
5684
41
      xmlXPathFormatNumber(val, buf, 99);
5685
41
      buf[99] = 0;
5686
41
      ret = xmlStrdup((const xmlChar *) buf);
5687
41
  }
5688
3.02k
    }
5689
3.02k
    return(ret);
5690
3.02k
}
5691
5692
/**
5693
 * xmlXPathCastNodeToString:
5694
 * @node:  a node
5695
 *
5696
 * Converts a node to its string value.
5697
 *
5698
 * Returns a newly allocated string.
5699
 */
5700
xmlChar *
5701
2.19M
xmlXPathCastNodeToString (xmlNodePtr node) {
5702
2.19M
xmlChar *ret;
5703
2.19M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5704
564
  ret = xmlStrdup((const xmlChar *) "");
5705
2.19M
    return(ret);
5706
2.19M
}
5707
5708
/**
5709
 * xmlXPathCastNodeSetToString:
5710
 * @ns:  a node-set
5711
 *
5712
 * Converts a node-set to its string value.
5713
 *
5714
 * Returns a newly allocated string.
5715
 */
5716
xmlChar *
5717
51.3k
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718
51.3k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719
2.50k
  return(xmlStrdup((const xmlChar *) ""));
5720
5721
48.8k
    if (ns->nodeNr > 1)
5722
2.37k
  xmlXPathNodeSetSort(ns);
5723
48.8k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724
51.3k
}
5725
5726
/**
5727
 * xmlXPathCastToString:
5728
 * @val:  an XPath object
5729
 *
5730
 * Converts an existing object to its string() equivalent
5731
 *
5732
 * Returns the allocated string value of the object, NULL in case of error.
5733
 *         It's up to the caller to free the string memory with xmlFree().
5734
 */
5735
xmlChar *
5736
18.3k
xmlXPathCastToString(xmlXPathObjectPtr val) {
5737
18.3k
    xmlChar *ret = NULL;
5738
5739
18.3k
    if (val == NULL)
5740
0
  return(xmlStrdup((const xmlChar *) ""));
5741
18.3k
    switch (val->type) {
5742
0
  case XPATH_UNDEFINED:
5743
#ifdef DEBUG_EXPR
5744
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5745
#endif
5746
0
      ret = xmlStrdup((const xmlChar *) "");
5747
0
      break;
5748
12.6k
        case XPATH_NODESET:
5749
12.6k
        case XPATH_XSLT_TREE:
5750
12.6k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751
12.6k
      break;
5752
5.63k
  case XPATH_STRING:
5753
5.63k
      return(xmlStrdup(val->stringval));
5754
21
        case XPATH_BOOLEAN:
5755
21
      ret = xmlXPathCastBooleanToString(val->boolval);
5756
21
      break;
5757
2
  case XPATH_NUMBER: {
5758
2
      ret = xmlXPathCastNumberToString(val->floatval);
5759
2
      break;
5760
12.6k
  }
5761
0
  case XPATH_USERS:
5762
#ifdef LIBXML_XPTR_LOCS_ENABLED
5763
  case XPATH_POINT:
5764
  case XPATH_RANGE:
5765
  case XPATH_LOCATIONSET:
5766
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5767
0
      TODO
5768
0
      ret = xmlStrdup((const xmlChar *) "");
5769
0
      break;
5770
18.3k
    }
5771
12.6k
    return(ret);
5772
18.3k
}
5773
5774
/**
5775
 * xmlXPathConvertString:
5776
 * @val:  an XPath object
5777
 *
5778
 * Converts an existing object to its string() equivalent
5779
 *
5780
 * Returns the new object, the old one is freed (or the operation
5781
 *         is done directly on @val)
5782
 */
5783
xmlXPathObjectPtr
5784
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5785
0
    xmlChar *res = NULL;
5786
5787
0
    if (val == NULL)
5788
0
  return(xmlXPathNewCString(""));
5789
5790
0
    switch (val->type) {
5791
0
    case XPATH_UNDEFINED:
5792
#ifdef DEBUG_EXPR
5793
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5794
#endif
5795
0
  break;
5796
0
    case XPATH_NODESET:
5797
0
    case XPATH_XSLT_TREE:
5798
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5799
0
  break;
5800
0
    case XPATH_STRING:
5801
0
  return(val);
5802
0
    case XPATH_BOOLEAN:
5803
0
  res = xmlXPathCastBooleanToString(val->boolval);
5804
0
  break;
5805
0
    case XPATH_NUMBER:
5806
0
  res = xmlXPathCastNumberToString(val->floatval);
5807
0
  break;
5808
0
    case XPATH_USERS:
5809
#ifdef LIBXML_XPTR_LOCS_ENABLED
5810
    case XPATH_POINT:
5811
    case XPATH_RANGE:
5812
    case XPATH_LOCATIONSET:
5813
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5814
0
  TODO;
5815
0
  break;
5816
0
    }
5817
0
    xmlXPathFreeObject(val);
5818
0
    if (res == NULL)
5819
0
  return(xmlXPathNewCString(""));
5820
0
    return(xmlXPathWrapString(res));
5821
0
}
5822
5823
/**
5824
 * xmlXPathCastBooleanToNumber:
5825
 * @val:  a boolean
5826
 *
5827
 * Converts a boolean to its number value
5828
 *
5829
 * Returns the number value
5830
 */
5831
double
5832
894
xmlXPathCastBooleanToNumber(int val) {
5833
894
    if (val)
5834
0
  return(1.0);
5835
894
    return(0.0);
5836
894
}
5837
5838
/**
5839
 * xmlXPathCastStringToNumber:
5840
 * @val:  a string
5841
 *
5842
 * Converts a string to its number value
5843
 *
5844
 * Returns the number value
5845
 */
5846
double
5847
2.10M
xmlXPathCastStringToNumber(const xmlChar * val) {
5848
2.10M
    return(xmlXPathStringEvalNumber(val));
5849
2.10M
}
5850
5851
/**
5852
 * xmlXPathCastNodeToNumber:
5853
 * @node:  a node
5854
 *
5855
 * Converts a node to its number value
5856
 *
5857
 * Returns the number value
5858
 */
5859
double
5860
62.9k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861
62.9k
    xmlChar *strval;
5862
62.9k
    double ret;
5863
5864
62.9k
    if (node == NULL)
5865
0
  return(xmlXPathNAN);
5866
62.9k
    strval = xmlXPathCastNodeToString(node);
5867
62.9k
    if (strval == NULL)
5868
0
  return(xmlXPathNAN);
5869
62.9k
    ret = xmlXPathCastStringToNumber(strval);
5870
62.9k
    xmlFree(strval);
5871
5872
62.9k
    return(ret);
5873
62.9k
}
5874
5875
/**
5876
 * xmlXPathCastNodeSetToNumber:
5877
 * @ns:  a node-set
5878
 *
5879
 * Converts a node-set to its number value
5880
 *
5881
 * Returns the number value
5882
 */
5883
double
5884
5.83k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885
5.83k
    xmlChar *str;
5886
5.83k
    double ret;
5887
5888
5.83k
    if (ns == NULL)
5889
590
  return(xmlXPathNAN);
5890
5.24k
    str = xmlXPathCastNodeSetToString(ns);
5891
5.24k
    ret = xmlXPathCastStringToNumber(str);
5892
5.24k
    xmlFree(str);
5893
5.24k
    return(ret);
5894
5.83k
}
5895
5896
/**
5897
 * xmlXPathCastToNumber:
5898
 * @val:  an XPath object
5899
 *
5900
 * Converts an XPath object to its number value
5901
 *
5902
 * Returns the number value
5903
 */
5904
double
5905
2.04M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906
2.04M
    double ret = 0.0;
5907
5908
2.04M
    if (val == NULL)
5909
0
  return(xmlXPathNAN);
5910
2.04M
    switch (val->type) {
5911
0
    case XPATH_UNDEFINED:
5912
#ifdef DEBUG_EXPR
5913
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5914
#endif
5915
0
  ret = xmlXPathNAN;
5916
0
  break;
5917
5.83k
    case XPATH_NODESET:
5918
5.83k
    case XPATH_XSLT_TREE:
5919
5.83k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920
5.83k
  break;
5921
2.04M
    case XPATH_STRING:
5922
2.04M
  ret = xmlXPathCastStringToNumber(val->stringval);
5923
2.04M
  break;
5924
606
    case XPATH_NUMBER:
5925
606
  ret = val->floatval;
5926
606
  break;
5927
894
    case XPATH_BOOLEAN:
5928
894
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5929
894
  break;
5930
0
    case XPATH_USERS:
5931
#ifdef LIBXML_XPTR_LOCS_ENABLED
5932
    case XPATH_POINT:
5933
    case XPATH_RANGE:
5934
    case XPATH_LOCATIONSET:
5935
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5936
0
  TODO;
5937
0
  ret = xmlXPathNAN;
5938
0
  break;
5939
2.04M
    }
5940
2.04M
    return(ret);
5941
2.04M
}
5942
5943
/**
5944
 * xmlXPathConvertNumber:
5945
 * @val:  an XPath object
5946
 *
5947
 * Converts an existing object to its number() equivalent
5948
 *
5949
 * Returns the new object, the old one is freed (or the operation
5950
 *         is done directly on @val)
5951
 */
5952
xmlXPathObjectPtr
5953
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954
0
    xmlXPathObjectPtr ret;
5955
5956
0
    if (val == NULL)
5957
0
  return(xmlXPathNewFloat(0.0));
5958
0
    if (val->type == XPATH_NUMBER)
5959
0
  return(val);
5960
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961
0
    xmlXPathFreeObject(val);
5962
0
    return(ret);
5963
0
}
5964
5965
/**
5966
 * xmlXPathCastNumberToBoolean:
5967
 * @val:  a number
5968
 *
5969
 * Converts a number to its boolean value
5970
 *
5971
 * Returns the boolean value
5972
 */
5973
int
5974
1.58k
xmlXPathCastNumberToBoolean (double val) {
5975
1.58k
     if (xmlXPathIsNaN(val) || (val == 0.0))
5976
0
   return(0);
5977
1.58k
     return(1);
5978
1.58k
}
5979
5980
/**
5981
 * xmlXPathCastStringToBoolean:
5982
 * @val:  a string
5983
 *
5984
 * Converts a string to its boolean value
5985
 *
5986
 * Returns the boolean value
5987
 */
5988
int
5989
1.48k
xmlXPathCastStringToBoolean (const xmlChar *val) {
5990
1.48k
    if ((val == NULL) || (xmlStrlen(val) == 0))
5991
1.48k
  return(0);
5992
0
    return(1);
5993
1.48k
}
5994
5995
/**
5996
 * xmlXPathCastNodeSetToBoolean:
5997
 * @ns:  a node-set
5998
 *
5999
 * Converts a node-set to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
171
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005
171
    if ((ns == NULL) || (ns->nodeNr == 0))
6006
73
  return(0);
6007
98
    return(1);
6008
171
}
6009
6010
/**
6011
 * xmlXPathCastToBoolean:
6012
 * @val:  an XPath object
6013
 *
6014
 * Converts an XPath object to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
3.23k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020
3.23k
    int ret = 0;
6021
6022
3.23k
    if (val == NULL)
6023
0
  return(0);
6024
3.23k
    switch (val->type) {
6025
0
    case XPATH_UNDEFINED:
6026
#ifdef DEBUG_EXPR
6027
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028
#endif
6029
0
  ret = 0;
6030
0
  break;
6031
171
    case XPATH_NODESET:
6032
171
    case XPATH_XSLT_TREE:
6033
171
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034
171
  break;
6035
1.48k
    case XPATH_STRING:
6036
1.48k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6037
1.48k
  break;
6038
1.58k
    case XPATH_NUMBER:
6039
1.58k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040
1.58k
  break;
6041
0
    case XPATH_BOOLEAN:
6042
0
  ret = val->boolval;
6043
0
  break;
6044
0
    case XPATH_USERS:
6045
#ifdef LIBXML_XPTR_LOCS_ENABLED
6046
    case XPATH_POINT:
6047
    case XPATH_RANGE:
6048
    case XPATH_LOCATIONSET:
6049
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6050
0
  TODO;
6051
0
  ret = 0;
6052
0
  break;
6053
3.23k
    }
6054
3.23k
    return(ret);
6055
3.23k
}
6056
6057
6058
/**
6059
 * xmlXPathConvertBoolean:
6060
 * @val:  an XPath object
6061
 *
6062
 * Converts an existing object to its boolean() equivalent
6063
 *
6064
 * Returns the new object, the old one is freed (or the operation
6065
 *         is done directly on @val)
6066
 */
6067
xmlXPathObjectPtr
6068
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6069
0
    xmlXPathObjectPtr ret;
6070
6071
0
    if (val == NULL)
6072
0
  return(xmlXPathNewBoolean(0));
6073
0
    if (val->type == XPATH_BOOLEAN)
6074
0
  return(val);
6075
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6076
0
    xmlXPathFreeObject(val);
6077
0
    return(ret);
6078
0
}
6079
6080
/************************************************************************
6081
 *                  *
6082
 *    Routines to handle XPath contexts     *
6083
 *                  *
6084
 ************************************************************************/
6085
6086
/**
6087
 * xmlXPathNewContext:
6088
 * @doc:  the XML document
6089
 *
6090
 * Create a new xmlXPathContext
6091
 *
6092
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6093
 */
6094
xmlXPathContextPtr
6095
404
xmlXPathNewContext(xmlDocPtr doc) {
6096
404
    xmlXPathContextPtr ret;
6097
6098
404
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099
404
    if (ret == NULL) {
6100
0
        xmlXPathErrMemory(NULL, "creating context\n");
6101
0
  return(NULL);
6102
0
    }
6103
404
    memset(ret, 0 , sizeof(xmlXPathContext));
6104
404
    ret->doc = doc;
6105
404
    ret->node = NULL;
6106
6107
404
    ret->varHash = NULL;
6108
6109
404
    ret->nb_types = 0;
6110
404
    ret->max_types = 0;
6111
404
    ret->types = NULL;
6112
6113
404
    ret->funcHash = xmlHashCreate(0);
6114
6115
404
    ret->nb_axis = 0;
6116
404
    ret->max_axis = 0;
6117
404
    ret->axis = NULL;
6118
6119
404
    ret->nsHash = NULL;
6120
404
    ret->user = NULL;
6121
6122
404
    ret->contextSize = -1;
6123
404
    ret->proximityPosition = -1;
6124
6125
#ifdef XP_DEFAULT_CACHE_ON
6126
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6127
  xmlXPathFreeContext(ret);
6128
  return(NULL);
6129
    }
6130
#endif
6131
6132
404
    xmlXPathRegisterAllFunctions(ret);
6133
6134
404
    return(ret);
6135
404
}
6136
6137
/**
6138
 * xmlXPathFreeContext:
6139
 * @ctxt:  the context to free
6140
 *
6141
 * Free up an xmlXPathContext
6142
 */
6143
void
6144
402
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145
402
    if (ctxt == NULL) return;
6146
6147
402
    if (ctxt->cache != NULL)
6148
399
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149
402
    xmlXPathRegisteredNsCleanup(ctxt);
6150
402
    xmlXPathRegisteredFuncsCleanup(ctxt);
6151
402
    xmlXPathRegisteredVariablesCleanup(ctxt);
6152
402
    xmlResetError(&ctxt->lastError);
6153
402
    xmlFree(ctxt);
6154
402
}
6155
6156
/************************************************************************
6157
 *                  *
6158
 *    Routines to handle XPath parser contexts    *
6159
 *                  *
6160
 ************************************************************************/
6161
6162
#define CHECK_CTXT(ctxt)            \
6163
402
    if (ctxt == NULL) {           \
6164
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6165
0
    NULL, NULL, XML_FROM_XPATH,       \
6166
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6167
0
    __FILE__, __LINE__,         \
6168
0
    NULL, NULL, NULL, 0, 0,         \
6169
0
    "NULL context pointer\n");        \
6170
0
  return(NULL);             \
6171
0
    }                  \
6172
6173
#define CHECK_CTXT_NEG(ctxt)            \
6174
6.02k
    if (ctxt == NULL) {           \
6175
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6176
0
    NULL, NULL, XML_FROM_XPATH,       \
6177
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6178
0
    __FILE__, __LINE__,         \
6179
0
    NULL, NULL, NULL, 0, 0,         \
6180
0
    "NULL context pointer\n");        \
6181
0
  return(-1);             \
6182
0
    }                  \
6183
6184
6185
#define CHECK_CONTEXT(ctxt)           \
6186
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6187
        (ctxt->doc->children == NULL)) {        \
6188
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6189
  return(NULL);             \
6190
    }
6191
6192
6193
/**
6194
 * xmlXPathNewParserContext:
6195
 * @str:  the XPath expression
6196
 * @ctxt:  the XPath context
6197
 *
6198
 * Create a new xmlXPathParserContext
6199
 *
6200
 * Returns the xmlXPathParserContext just allocated.
6201
 */
6202
xmlXPathParserContextPtr
6203
5.69k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204
5.69k
    xmlXPathParserContextPtr ret;
6205
6206
5.69k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207
5.69k
    if (ret == NULL) {
6208
2
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6209
2
  return(NULL);
6210
2
    }
6211
5.69k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6212
5.69k
    ret->cur = ret->base = str;
6213
5.69k
    ret->context = ctxt;
6214
6215
5.69k
    ret->comp = xmlXPathNewCompExpr();
6216
5.69k
    if (ret->comp == NULL) {
6217
0
  xmlFree(ret->valueTab);
6218
0
  xmlFree(ret);
6219
0
  return(NULL);
6220
0
    }
6221
5.69k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222
0
        ret->comp->dict = ctxt->dict;
6223
0
  xmlDictReference(ret->comp->dict);
6224
0
    }
6225
6226
5.69k
    return(ret);
6227
5.69k
}
6228
6229
/**
6230
 * xmlXPathCompParserContext:
6231
 * @comp:  the XPath compiled expression
6232
 * @ctxt:  the XPath context
6233
 *
6234
 * Create a new xmlXPathParserContext when processing a compiled expression
6235
 *
6236
 * Returns the xmlXPathParserContext just allocated.
6237
 */
6238
static xmlXPathParserContextPtr
6239
6.02k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240
6.02k
    xmlXPathParserContextPtr ret;
6241
6242
6.02k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243
6.02k
    if (ret == NULL) {
6244
33
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245
33
  return(NULL);
6246
33
    }
6247
5.98k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6248
6249
    /* Allocate the value stack */
6250
5.98k
    ret->valueTab = (xmlXPathObjectPtr *)
6251
5.98k
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252
5.98k
    if (ret->valueTab == NULL) {
6253
0
  xmlFree(ret);
6254
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255
0
  return(NULL);
6256
0
    }
6257
5.98k
    ret->valueNr = 0;
6258
5.98k
    ret->valueMax = 10;
6259
5.98k
    ret->value = NULL;
6260
6261
5.98k
    ret->context = ctxt;
6262
5.98k
    ret->comp = comp;
6263
6264
5.98k
    return(ret);
6265
5.98k
}
6266
6267
/**
6268
 * xmlXPathFreeParserContext:
6269
 * @ctxt:  the context to free
6270
 *
6271
 * Free up an xmlXPathParserContext
6272
 */
6273
void
6274
11.6k
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275
11.6k
    int i;
6276
6277
11.6k
    if (ctxt->valueTab != NULL) {
6278
7.09k
        for (i = 0; i < ctxt->valueNr; i++) {
6279
703
            if (ctxt->context)
6280
703
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281
0
            else
6282
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6283
703
        }
6284
6.39k
        xmlFree(ctxt->valueTab);
6285
6.39k
    }
6286
11.6k
    if (ctxt->comp != NULL) {
6287
5.29k
#ifdef XPATH_STREAMING
6288
5.29k
  if (ctxt->comp->stream != NULL) {
6289
0
      xmlFreePatternList(ctxt->comp->stream);
6290
0
      ctxt->comp->stream = NULL;
6291
0
  }
6292
5.29k
#endif
6293
5.29k
  xmlXPathFreeCompExpr(ctxt->comp);
6294
5.29k
    }
6295
11.6k
    xmlFree(ctxt);
6296
11.6k
}
6297
6298
/************************************************************************
6299
 *                  *
6300
 *    The implicit core function library      *
6301
 *                  *
6302
 ************************************************************************/
6303
6304
/**
6305
 * xmlXPathNodeValHash:
6306
 * @node:  a node pointer
6307
 *
6308
 * Function computing the beginning of the string value of the node,
6309
 * used to speed up comparisons
6310
 *
6311
 * Returns an int usable as a hash
6312
 */
6313
static unsigned int
6314
2.68k
xmlXPathNodeValHash(xmlNodePtr node) {
6315
2.68k
    int len = 2;
6316
2.68k
    const xmlChar * string = NULL;
6317
2.68k
    xmlNodePtr tmp = NULL;
6318
2.68k
    unsigned int ret = 0;
6319
6320
2.68k
    if (node == NULL)
6321
0
  return(0);
6322
6323
2.68k
    if (node->type == XML_DOCUMENT_NODE) {
6324
1
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325
1
  if (tmp == NULL)
6326
0
      node = node->children;
6327
1
  else
6328
1
      node = tmp;
6329
6330
1
  if (node == NULL)
6331
0
      return(0);
6332
1
    }
6333
6334
2.68k
    switch (node->type) {
6335
0
  case XML_COMMENT_NODE:
6336
0
  case XML_PI_NODE:
6337
0
  case XML_CDATA_SECTION_NODE:
6338
0
  case XML_TEXT_NODE:
6339
0
      string = node->content;
6340
0
      if (string == NULL)
6341
0
    return(0);
6342
0
      if (string[0] == 0)
6343
0
    return(0);
6344
0
      return(string[0] + (string[1] << 8));
6345
0
  case XML_NAMESPACE_DECL:
6346
0
      string = ((xmlNsPtr)node)->href;
6347
0
      if (string == NULL)
6348
0
    return(0);
6349
0
      if (string[0] == 0)
6350
0
    return(0);
6351
0
      return(string[0] + (string[1] << 8));
6352
0
  case XML_ATTRIBUTE_NODE:
6353
0
      tmp = ((xmlAttrPtr) node)->children;
6354
0
      break;
6355
2.68k
  case XML_ELEMENT_NODE:
6356
2.68k
      tmp = node->children;
6357
2.68k
      break;
6358
0
  default:
6359
0
      return(0);
6360
2.68k
    }
6361
9.57k
    while (tmp != NULL) {
6362
9.00k
  switch (tmp->type) {
6363
0
      case XML_CDATA_SECTION_NODE:
6364
3.05k
      case XML_TEXT_NODE:
6365
3.05k
    string = tmp->content;
6366
3.05k
    break;
6367
5.94k
      default:
6368
5.94k
                string = NULL;
6369
5.94k
    break;
6370
9.00k
  }
6371
9.00k
  if ((string != NULL) && (string[0] != 0)) {
6372
3.05k
      if (len == 1) {
6373
945
    return(ret + (string[0] << 8));
6374
945
      }
6375
2.11k
      if (string[1] == 0) {
6376
945
    len = 1;
6377
945
    ret = string[0];
6378
1.16k
      } else {
6379
1.16k
    return(string[0] + (string[1] << 8));
6380
1.16k
      }
6381
2.11k
  }
6382
  /*
6383
   * Skip to next node
6384
   */
6385
6.89k
        if ((tmp->children != NULL) &&
6386
6.89k
            (tmp->type != XML_DTD_NODE) &&
6387
6.89k
            (tmp->type != XML_ENTITY_REF_NODE) &&
6388
6.89k
            (tmp->children->type != XML_ENTITY_DECL)) {
6389
5.94k
            tmp = tmp->children;
6390
5.94k
            continue;
6391
5.94k
  }
6392
945
  if (tmp == node)
6393
0
      break;
6394
6395
945
  if (tmp->next != NULL) {
6396
945
      tmp = tmp->next;
6397
945
      continue;
6398
945
  }
6399
6400
0
  do {
6401
0
      tmp = tmp->parent;
6402
0
      if (tmp == NULL)
6403
0
    break;
6404
0
      if (tmp == node) {
6405
0
    tmp = NULL;
6406
0
    break;
6407
0
      }
6408
0
      if (tmp->next != NULL) {
6409
0
    tmp = tmp->next;
6410
0
    break;
6411
0
      }
6412
0
  } while (tmp != NULL);
6413
0
    }
6414
570
    return(ret);
6415
2.68k
}
6416
6417
/**
6418
 * xmlXPathStringHash:
6419
 * @string:  a string
6420
 *
6421
 * Function computing the beginning of the string value of the node,
6422
 * used to speed up comparisons
6423
 *
6424
 * Returns an int usable as a hash
6425
 */
6426
static unsigned int
6427
2.67k
xmlXPathStringHash(const xmlChar * string) {
6428
2.67k
    if (string == NULL)
6429
0
  return(0);
6430
2.67k
    if (string[0] == 0)
6431
1.16k
  return(0);
6432
1.51k
    return(string[0] + (string[1] << 8));
6433
2.67k
}
6434
6435
/**
6436
 * xmlXPathCompareNodeSetFloat:
6437
 * @ctxt:  the XPath Parser context
6438
 * @inf:  less than (1) or greater than (0)
6439
 * @strict:  is the comparison strict
6440
 * @arg:  the node set
6441
 * @f:  the value
6442
 *
6443
 * Implement the compare operation between a nodeset and a number
6444
 *     @ns < @val    (1, 1, ...
6445
 *     @ns <= @val   (1, 0, ...
6446
 *     @ns > @val    (0, 1, ...
6447
 *     @ns >= @val   (0, 0, ...
6448
 *
6449
 * If one object to be compared is a node-set and the other is a number,
6450
 * then the comparison will be true if and only if there is a node in the
6451
 * node-set such that the result of performing the comparison on the number
6452
 * to be compared and on the result of converting the string-value of that
6453
 * node to a number using the number function is true.
6454
 *
6455
 * Returns 0 or 1 depending on the results of the test.
6456
 */
6457
static int
6458
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6459
496
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6460
496
    int i, ret = 0;
6461
496
    xmlNodeSetPtr ns;
6462
496
    xmlChar *str2;
6463
6464
496
    if ((f == NULL) || (arg == NULL) ||
6465
496
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6466
0
  xmlXPathReleaseObject(ctxt->context, arg);
6467
0
  xmlXPathReleaseObject(ctxt->context, f);
6468
0
        return(0);
6469
0
    }
6470
496
    ns = arg->nodesetval;
6471
496
    if (ns != NULL) {
6472
496
  for (i = 0;i < ns->nodeNr;i++) {
6473
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6474
0
       if (str2 != NULL) {
6475
0
     valuePush(ctxt,
6476
0
         xmlXPathCacheNewString(ctxt->context, str2));
6477
0
     xmlFree(str2);
6478
0
     xmlXPathNumberFunction(ctxt, 1);
6479
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6480
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6481
0
     if (ret)
6482
0
         break;
6483
0
       }
6484
0
  }
6485
496
    }
6486
496
    xmlXPathReleaseObject(ctxt->context, arg);
6487
496
    xmlXPathReleaseObject(ctxt->context, f);
6488
496
    return(ret);
6489
496
}
6490
6491
/**
6492
 * xmlXPathCompareNodeSetString:
6493
 * @ctxt:  the XPath Parser context
6494
 * @inf:  less than (1) or greater than (0)
6495
 * @strict:  is the comparison strict
6496
 * @arg:  the node set
6497
 * @s:  the value
6498
 *
6499
 * Implement the compare operation between a nodeset and a string
6500
 *     @ns < @val    (1, 1, ...
6501
 *     @ns <= @val   (1, 0, ...
6502
 *     @ns > @val    (0, 1, ...
6503
 *     @ns >= @val   (0, 0, ...
6504
 *
6505
 * If one object to be compared is a node-set and the other is a string,
6506
 * then the comparison will be true if and only if there is a node in
6507
 * the node-set such that the result of performing the comparison on the
6508
 * string-value of the node and the other string is true.
6509
 *
6510
 * Returns 0 or 1 depending on the results of the test.
6511
 */
6512
static int
6513
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6514
352
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6515
352
    int i, ret = 0;
6516
352
    xmlNodeSetPtr ns;
6517
352
    xmlChar *str2;
6518
6519
352
    if ((s == NULL) || (arg == NULL) ||
6520
352
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6521
0
  xmlXPathReleaseObject(ctxt->context, arg);
6522
0
  xmlXPathReleaseObject(ctxt->context, s);
6523
0
        return(0);
6524
0
    }
6525
352
    ns = arg->nodesetval;
6526
352
    if (ns != NULL) {
6527
352
  for (i = 0;i < ns->nodeNr;i++) {
6528
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6529
0
       if (str2 != NULL) {
6530
0
     valuePush(ctxt,
6531
0
         xmlXPathCacheNewString(ctxt->context, str2));
6532
0
     xmlFree(str2);
6533
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6534
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6535
0
     if (ret)
6536
0
         break;
6537
0
       }
6538
0
  }
6539
352
    }
6540
352
    xmlXPathReleaseObject(ctxt->context, arg);
6541
352
    xmlXPathReleaseObject(ctxt->context, s);
6542
352
    return(ret);
6543
352
}
6544
6545
/**
6546
 * xmlXPathCompareNodeSets:
6547
 * @inf:  less than (1) or greater than (0)
6548
 * @strict:  is the comparison strict
6549
 * @arg1:  the first node set object
6550
 * @arg2:  the second node set object
6551
 *
6552
 * Implement the compare operation on nodesets:
6553
 *
6554
 * If both objects to be compared are node-sets, then the comparison
6555
 * will be true if and only if there is a node in the first node-set
6556
 * and a node in the second node-set such that the result of performing
6557
 * the comparison on the string-values of the two nodes is true.
6558
 * ....
6559
 * When neither object to be compared is a node-set and the operator
6560
 * is <=, <, >= or >, then the objects are compared by converting both
6561
 * objects to numbers and comparing the numbers according to IEEE 754.
6562
 * ....
6563
 * The number function converts its argument to a number as follows:
6564
 *  - a string that consists of optional whitespace followed by an
6565
 *    optional minus sign followed by a Number followed by whitespace
6566
 *    is converted to the IEEE 754 number that is nearest (according
6567
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6568
 *    represented by the string; any other string is converted to NaN
6569
 *
6570
 * Conclusion all nodes need to be converted first to their string value
6571
 * and then the comparison must be done when possible
6572
 */
6573
static int
6574
xmlXPathCompareNodeSets(int inf, int strict,
6575
29
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6576
29
    int i, j, init = 0;
6577
29
    double val1;
6578
29
    double *values2;
6579
29
    int ret = 0;
6580
29
    xmlNodeSetPtr ns1;
6581
29
    xmlNodeSetPtr ns2;
6582
6583
29
    if ((arg1 == NULL) ||
6584
29
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6585
0
  xmlXPathFreeObject(arg2);
6586
0
        return(0);
6587
0
    }
6588
29
    if ((arg2 == NULL) ||
6589
29
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6590
0
  xmlXPathFreeObject(arg1);
6591
0
  xmlXPathFreeObject(arg2);
6592
0
        return(0);
6593
0
    }
6594
6595
29
    ns1 = arg1->nodesetval;
6596
29
    ns2 = arg2->nodesetval;
6597
6598
29
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6599
4
  xmlXPathFreeObject(arg1);
6600
4
  xmlXPathFreeObject(arg2);
6601
4
  return(0);
6602
4
    }
6603
25
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6604
25
  xmlXPathFreeObject(arg1);
6605
25
  xmlXPathFreeObject(arg2);
6606
25
  return(0);
6607
25
    }
6608
6609
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6610
0
    if (values2 == NULL) {
6611
        /* TODO: Propagate memory error. */
6612
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6613
0
  xmlXPathFreeObject(arg1);
6614
0
  xmlXPathFreeObject(arg2);
6615
0
  return(0);
6616
0
    }
6617
0
    for (i = 0;i < ns1->nodeNr;i++) {
6618
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6619
0
  if (xmlXPathIsNaN(val1))
6620
0
      continue;
6621
0
  for (j = 0;j < ns2->nodeNr;j++) {
6622
0
      if (init == 0) {
6623
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6624
0
      }
6625
0
      if (xmlXPathIsNaN(values2[j]))
6626
0
    continue;
6627
0
      if (inf && strict)
6628
0
    ret = (val1 < values2[j]);
6629
0
      else if (inf && !strict)
6630
0
    ret = (val1 <= values2[j]);
6631
0
      else if (!inf && strict)
6632
0
    ret = (val1 > values2[j]);
6633
0
      else if (!inf && !strict)
6634
0
    ret = (val1 >= values2[j]);
6635
0
      if (ret)
6636
0
    break;
6637
0
  }
6638
0
  if (ret)
6639
0
      break;
6640
0
  init = 1;
6641
0
    }
6642
0
    xmlFree(values2);
6643
0
    xmlXPathFreeObject(arg1);
6644
0
    xmlXPathFreeObject(arg2);
6645
0
    return(ret);
6646
0
}
6647
6648
/**
6649
 * xmlXPathCompareNodeSetValue:
6650
 * @ctxt:  the XPath Parser context
6651
 * @inf:  less than (1) or greater than (0)
6652
 * @strict:  is the comparison strict
6653
 * @arg:  the node set
6654
 * @val:  the value
6655
 *
6656
 * Implement the compare operation between a nodeset and a value
6657
 *     @ns < @val    (1, 1, ...
6658
 *     @ns <= @val   (1, 0, ...
6659
 *     @ns > @val    (0, 1, ...
6660
 *     @ns >= @val   (0, 0, ...
6661
 *
6662
 * If one object to be compared is a node-set and the other is a boolean,
6663
 * then the comparison will be true if and only if the result of performing
6664
 * the comparison on the boolean and on the result of converting
6665
 * the node-set to a boolean using the boolean function is true.
6666
 *
6667
 * Returns 0 or 1 depending on the results of the test.
6668
 */
6669
static int
6670
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6671
896
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6672
896
    if ((val == NULL) || (arg == NULL) ||
6673
896
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674
0
        return(0);
6675
6676
896
    switch(val->type) {
6677
496
        case XPATH_NUMBER:
6678
496
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6679
0
        case XPATH_NODESET:
6680
0
        case XPATH_XSLT_TREE:
6681
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6682
352
        case XPATH_STRING:
6683
352
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6684
48
        case XPATH_BOOLEAN:
6685
48
      valuePush(ctxt, arg);
6686
48
      xmlXPathBooleanFunction(ctxt, 1);
6687
48
      valuePush(ctxt, val);
6688
48
      return(xmlXPathCompareValues(ctxt, inf, strict));
6689
0
  default:
6690
0
            xmlGenericError(xmlGenericErrorContext,
6691
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6692
0
                    "and object of type %d\n",
6693
0
                    val->type);
6694
0
            xmlXPathReleaseObject(ctxt->context, arg);
6695
0
            xmlXPathReleaseObject(ctxt->context, val);
6696
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6697
896
    }
6698
0
    return(0);
6699
896
}
6700
6701
/**
6702
 * xmlXPathEqualNodeSetString:
6703
 * @arg:  the nodeset object argument
6704
 * @str:  the string to compare to.
6705
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6706
 *
6707
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6708
 * If one object to be compared is a node-set and the other is a string,
6709
 * then the comparison will be true if and only if there is a node in
6710
 * the node-set such that the result of performing the comparison on the
6711
 * string-value of the node and the other string is true.
6712
 *
6713
 * Returns 0 or 1 depending on the results of the test.
6714
 */
6715
static int
6716
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6717
2.68k
{
6718
2.68k
    int i;
6719
2.68k
    xmlNodeSetPtr ns;
6720
2.68k
    xmlChar *str2;
6721
2.68k
    unsigned int hash;
6722
6723
2.68k
    if ((str == NULL) || (arg == NULL) ||
6724
2.68k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6725
0
        return (0);
6726
2.68k
    ns = arg->nodesetval;
6727
    /*
6728
     * A NULL nodeset compared with a string is always false
6729
     * (since there is no node equal, and no node not equal)
6730
     */
6731
2.68k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6732
12
        return (0);
6733
2.67k
    hash = xmlXPathStringHash(str);
6734
3.25k
    for (i = 0; i < ns->nodeNr; i++) {
6735
2.68k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6736
577
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6737
577
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6738
577
                xmlFree(str2);
6739
577
    if (neq)
6740
577
        continue;
6741
0
                return (1);
6742
577
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6743
0
    if (neq)
6744
0
        continue;
6745
0
                return (1);
6746
0
            } else if (neq) {
6747
0
    if (str2 != NULL)
6748
0
        xmlFree(str2);
6749
0
    return (1);
6750
0
      }
6751
0
            if (str2 != NULL)
6752
0
                xmlFree(str2);
6753
2.10k
        } else if (neq)
6754
2.10k
      return (1);
6755
2.68k
    }
6756
571
    return (0);
6757
2.67k
}
6758
6759
/**
6760
 * xmlXPathEqualNodeSetFloat:
6761
 * @arg:  the nodeset object argument
6762
 * @f:  the float to compare to
6763
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6764
 *
6765
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6766
 * If one object to be compared is a node-set and the other is a number,
6767
 * then the comparison will be true if and only if there is a node in
6768
 * the node-set such that the result of performing the comparison on the
6769
 * number to be compared and on the result of converting the string-value
6770
 * of that node to a number using the number function is true.
6771
 *
6772
 * Returns 0 or 1 depending on the results of the test.
6773
 */
6774
static int
6775
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6776
2.60k
    xmlXPathObjectPtr arg, double f, int neq) {
6777
2.60k
  int i, ret=0;
6778
2.60k
  xmlNodeSetPtr ns;
6779
2.60k
  xmlChar *str2;
6780
2.60k
  xmlXPathObjectPtr val;
6781
2.60k
  double v;
6782
6783
2.60k
    if ((arg == NULL) ||
6784
2.60k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6785
0
        return(0);
6786
6787
2.60k
    ns = arg->nodesetval;
6788
2.60k
    if (ns != NULL) {
6789
1.86M
  for (i=0;i<ns->nodeNr;i++) {
6790
1.85M
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6791
1.85M
      if (str2 != NULL) {
6792
1.85M
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6793
1.85M
    xmlFree(str2);
6794
1.85M
    xmlXPathNumberFunction(ctxt, 1);
6795
1.85M
                CHECK_ERROR0;
6796
1.85M
    val = valuePop(ctxt);
6797
1.85M
    v = val->floatval;
6798
1.85M
    xmlXPathReleaseObject(ctxt->context, val);
6799
1.85M
    if (!xmlXPathIsNaN(v)) {
6800
13
        if ((!neq) && (v==f)) {
6801
0
      ret = 1;
6802
0
      break;
6803
13
        } else if ((neq) && (v!=f)) {
6804
0
      ret = 1;
6805
0
      break;
6806
0
        }
6807
1.85M
    } else { /* NaN is unequal to any value */
6808
1.85M
        if (neq)
6809
49.8k
      ret = 1;
6810
1.85M
    }
6811
1.85M
      }
6812
1.85M
  }
6813
2.60k
    }
6814
6815
2.59k
    return(ret);
6816
2.60k
}
6817
6818
6819
/**
6820
 * xmlXPathEqualNodeSets:
6821
 * @arg1:  first nodeset object argument
6822
 * @arg2:  second nodeset object argument
6823
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6824
 *
6825
 * Implement the equal / not equal operation on XPath nodesets:
6826
 * @arg1 == @arg2  or  @arg1 != @arg2
6827
 * If both objects to be compared are node-sets, then the comparison
6828
 * will be true if and only if there is a node in the first node-set and
6829
 * a node in the second node-set such that the result of performing the
6830
 * comparison on the string-values of the two nodes is true.
6831
 *
6832
 * (needless to say, this is a costly operation)
6833
 *
6834
 * Returns 0 or 1 depending on the results of the test.
6835
 */
6836
static int
6837
326
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6838
326
    int i, j;
6839
326
    unsigned int *hashs1;
6840
326
    unsigned int *hashs2;
6841
326
    xmlChar **values1;
6842
326
    xmlChar **values2;
6843
326
    int ret = 0;
6844
326
    xmlNodeSetPtr ns1;
6845
326
    xmlNodeSetPtr ns2;
6846
6847
326
    if ((arg1 == NULL) ||
6848
326
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6849
0
        return(0);
6850
326
    if ((arg2 == NULL) ||
6851
326
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6852
0
        return(0);
6853
6854
326
    ns1 = arg1->nodesetval;
6855
326
    ns2 = arg2->nodesetval;
6856
6857
326
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6858
301
  return(0);
6859
25
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6860
25
  return(0);
6861
6862
    /*
6863
     * for equal, check if there is a node pertaining to both sets
6864
     */
6865
0
    if (neq == 0)
6866
0
  for (i = 0;i < ns1->nodeNr;i++)
6867
0
      for (j = 0;j < ns2->nodeNr;j++)
6868
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6869
0
        return(1);
6870
6871
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6872
0
    if (values1 == NULL) {
6873
        /* TODO: Propagate memory error. */
6874
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6875
0
  return(0);
6876
0
    }
6877
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6878
0
    if (hashs1 == NULL) {
6879
        /* TODO: Propagate memory error. */
6880
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6881
0
  xmlFree(values1);
6882
0
  return(0);
6883
0
    }
6884
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6885
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6886
0
    if (values2 == NULL) {
6887
        /* TODO: Propagate memory error. */
6888
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6889
0
  xmlFree(hashs1);
6890
0
  xmlFree(values1);
6891
0
  return(0);
6892
0
    }
6893
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6894
0
    if (hashs2 == NULL) {
6895
        /* TODO: Propagate memory error. */
6896
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6897
0
  xmlFree(hashs1);
6898
0
  xmlFree(values1);
6899
0
  xmlFree(values2);
6900
0
  return(0);
6901
0
    }
6902
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6903
0
    for (i = 0;i < ns1->nodeNr;i++) {
6904
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6905
0
  for (j = 0;j < ns2->nodeNr;j++) {
6906
0
      if (i == 0)
6907
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6908
0
      if (hashs1[i] != hashs2[j]) {
6909
0
    if (neq) {
6910
0
        ret = 1;
6911
0
        break;
6912
0
    }
6913
0
      }
6914
0
      else {
6915
0
    if (values1[i] == NULL)
6916
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6917
0
    if (values2[j] == NULL)
6918
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6919
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6920
0
    if (ret)
6921
0
        break;
6922
0
      }
6923
0
  }
6924
0
  if (ret)
6925
0
      break;
6926
0
    }
6927
0
    for (i = 0;i < ns1->nodeNr;i++)
6928
0
  if (values1[i] != NULL)
6929
0
      xmlFree(values1[i]);
6930
0
    for (j = 0;j < ns2->nodeNr;j++)
6931
0
  if (values2[j] != NULL)
6932
0
      xmlFree(values2[j]);
6933
0
    xmlFree(values1);
6934
0
    xmlFree(values2);
6935
0
    xmlFree(hashs1);
6936
0
    xmlFree(hashs2);
6937
0
    return(ret);
6938
0
}
6939
6940
static int
6941
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6942
452
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6943
452
    int ret = 0;
6944
    /*
6945
     *At this point we are assured neither arg1 nor arg2
6946
     *is a nodeset, so we can just pick the appropriate routine.
6947
     */
6948
452
    switch (arg1->type) {
6949
0
        case XPATH_UNDEFINED:
6950
#ifdef DEBUG_EXPR
6951
      xmlGenericError(xmlGenericErrorContext,
6952
        "Equal: undefined\n");
6953
#endif
6954
0
      break;
6955
402
        case XPATH_BOOLEAN:
6956
402
      switch (arg2->type) {
6957
0
          case XPATH_UNDEFINED:
6958
#ifdef DEBUG_EXPR
6959
        xmlGenericError(xmlGenericErrorContext,
6960
          "Equal: undefined\n");
6961
#endif
6962
0
        break;
6963
50
    case XPATH_BOOLEAN:
6964
#ifdef DEBUG_EXPR
6965
        xmlGenericError(xmlGenericErrorContext,
6966
          "Equal: %d boolean %d \n",
6967
          arg1->boolval, arg2->boolval);
6968
#endif
6969
50
        ret = (arg1->boolval == arg2->boolval);
6970
50
        break;
6971
0
    case XPATH_NUMBER:
6972
0
        ret = (arg1->boolval ==
6973
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
6974
0
        break;
6975
352
    case XPATH_STRING:
6976
352
        if ((arg2->stringval == NULL) ||
6977
352
      (arg2->stringval[0] == 0)) ret = 0;
6978
0
        else
6979
0
      ret = 1;
6980
352
        ret = (arg1->boolval == ret);
6981
352
        break;
6982
0
    case XPATH_USERS:
6983
#ifdef LIBXML_XPTR_LOCS_ENABLED
6984
    case XPATH_POINT:
6985
    case XPATH_RANGE:
6986
    case XPATH_LOCATIONSET:
6987
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6988
0
        TODO
6989
0
        break;
6990
0
    case XPATH_NODESET:
6991
0
    case XPATH_XSLT_TREE:
6992
0
        break;
6993
402
      }
6994
402
      break;
6995
402
        case XPATH_NUMBER:
6996
0
      switch (arg2->type) {
6997
0
          case XPATH_UNDEFINED:
6998
#ifdef DEBUG_EXPR
6999
        xmlGenericError(xmlGenericErrorContext,
7000
          "Equal: undefined\n");
7001
#endif
7002
0
        break;
7003
0
    case XPATH_BOOLEAN:
7004
0
        ret = (arg2->boolval==
7005
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
7006
0
        break;
7007
0
    case XPATH_STRING:
7008
0
        valuePush(ctxt, arg2);
7009
0
        xmlXPathNumberFunction(ctxt, 1);
7010
0
        arg2 = valuePop(ctxt);
7011
0
                    if (ctxt->error)
7012
0
                        break;
7013
                    /* Falls through. */
7014
0
    case XPATH_NUMBER:
7015
        /* Hand check NaN and Infinity equalities */
7016
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7017
0
          xmlXPathIsNaN(arg2->floatval)) {
7018
0
            ret = 0;
7019
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
7021
0
          ret = 1;
7022
0
      else
7023
0
          ret = 0;
7024
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7026
0
          ret = 1;
7027
0
      else
7028
0
          ret = 0;
7029
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7031
0
          ret = 1;
7032
0
      else
7033
0
          ret = 0;
7034
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7036
0
          ret = 1;
7037
0
      else
7038
0
          ret = 0;
7039
0
        } else {
7040
0
            ret = (arg1->floatval == arg2->floatval);
7041
0
        }
7042
0
        break;
7043
0
    case XPATH_USERS:
7044
#ifdef LIBXML_XPTR_LOCS_ENABLED
7045
    case XPATH_POINT:
7046
    case XPATH_RANGE:
7047
    case XPATH_LOCATIONSET:
7048
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7049
0
        TODO
7050
0
        break;
7051
0
    case XPATH_NODESET:
7052
0
    case XPATH_XSLT_TREE:
7053
0
        break;
7054
0
      }
7055
0
      break;
7056
50
        case XPATH_STRING:
7057
50
      switch (arg2->type) {
7058
0
          case XPATH_UNDEFINED:
7059
#ifdef DEBUG_EXPR
7060
        xmlGenericError(xmlGenericErrorContext,
7061
          "Equal: undefined\n");
7062
#endif
7063
0
        break;
7064
50
    case XPATH_BOOLEAN:
7065
50
        if ((arg1->stringval == NULL) ||
7066
50
      (arg1->stringval[0] == 0)) ret = 0;
7067
50
        else
7068
50
      ret = 1;
7069
50
        ret = (arg2->boolval == ret);
7070
50
        break;
7071
0
    case XPATH_STRING:
7072
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7073
0
        break;
7074
0
    case XPATH_NUMBER:
7075
0
        valuePush(ctxt, arg1);
7076
0
        xmlXPathNumberFunction(ctxt, 1);
7077
0
        arg1 = valuePop(ctxt);
7078
0
                    if (ctxt->error)
7079
0
                        break;
7080
        /* Hand check NaN and Infinity equalities */
7081
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7082
0
          xmlXPathIsNaN(arg2->floatval)) {
7083
0
            ret = 0;
7084
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7085
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7086
0
          ret = 1;
7087
0
      else
7088
0
          ret = 0;
7089
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7090
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7091
0
          ret = 1;
7092
0
      else
7093
0
          ret = 0;
7094
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7095
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7096
0
          ret = 1;
7097
0
      else
7098
0
          ret = 0;
7099
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7100
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7101
0
          ret = 1;
7102
0
      else
7103
0
          ret = 0;
7104
0
        } else {
7105
0
            ret = (arg1->floatval == arg2->floatval);
7106
0
        }
7107
0
        break;
7108
0
    case XPATH_USERS:
7109
#ifdef LIBXML_XPTR_LOCS_ENABLED
7110
    case XPATH_POINT:
7111
    case XPATH_RANGE:
7112
    case XPATH_LOCATIONSET:
7113
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7114
0
        TODO
7115
0
        break;
7116
0
    case XPATH_NODESET:
7117
0
    case XPATH_XSLT_TREE:
7118
0
        break;
7119
50
      }
7120
50
      break;
7121
50
        case XPATH_USERS:
7122
#ifdef LIBXML_XPTR_LOCS_ENABLED
7123
  case XPATH_POINT:
7124
  case XPATH_RANGE:
7125
  case XPATH_LOCATIONSET:
7126
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7127
0
      TODO
7128
0
      break;
7129
0
  case XPATH_NODESET:
7130
0
  case XPATH_XSLT_TREE:
7131
0
      break;
7132
452
    }
7133
452
    xmlXPathReleaseObject(ctxt->context, arg1);
7134
452
    xmlXPathReleaseObject(ctxt->context, arg2);
7135
452
    return(ret);
7136
452
}
7137
7138
/**
7139
 * xmlXPathEqualValues:
7140
 * @ctxt:  the XPath Parser context
7141
 *
7142
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7143
 *
7144
 * Returns 0 or 1 depending on the results of the test.
7145
 */
7146
int
7147
3.43k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7148
3.43k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7149
3.43k
    int ret = 0;
7150
7151
3.43k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7152
3.43k
    arg2 = valuePop(ctxt);
7153
3.43k
    arg1 = valuePop(ctxt);
7154
3.43k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7155
0
  if (arg1 != NULL)
7156
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7157
0
  else
7158
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7159
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7160
0
    }
7161
7162
3.43k
    if (arg1 == arg2) {
7163
#ifdef DEBUG_EXPR
7164
        xmlGenericError(xmlGenericErrorContext,
7165
    "Equal: by pointer\n");
7166
#endif
7167
0
  xmlXPathFreeObject(arg1);
7168
0
        return(1);
7169
0
    }
7170
7171
    /*
7172
     *If either argument is a nodeset, it's a 'special case'
7173
     */
7174
3.43k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7175
3.43k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7176
  /*
7177
   *Hack it to assure arg1 is the nodeset
7178
   */
7179
2.98k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7180
2.17k
    argtmp = arg2;
7181
2.17k
    arg2 = arg1;
7182
2.17k
    arg1 = argtmp;
7183
2.17k
  }
7184
2.98k
  switch (arg2->type) {
7185
0
      case XPATH_UNDEFINED:
7186
#ifdef DEBUG_EXPR
7187
    xmlGenericError(xmlGenericErrorContext,
7188
      "Equal: undefined\n");
7189
#endif
7190
0
    break;
7191
326
      case XPATH_NODESET:
7192
326
      case XPATH_XSLT_TREE:
7193
326
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7194
326
    break;
7195
70
      case XPATH_BOOLEAN:
7196
70
    if ((arg1->nodesetval == NULL) ||
7197
70
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7198
12
    else
7199
12
        ret = 1;
7200
70
    ret = (ret == arg2->boolval);
7201
70
    break;
7202
2.57k
      case XPATH_NUMBER:
7203
2.57k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7204
2.57k
    break;
7205
12
      case XPATH_STRING:
7206
12
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7207
12
    break;
7208
0
      case XPATH_USERS:
7209
#ifdef LIBXML_XPTR_LOCS_ENABLED
7210
      case XPATH_POINT:
7211
      case XPATH_RANGE:
7212
      case XPATH_LOCATIONSET:
7213
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7214
0
    TODO
7215
0
    break;
7216
2.98k
  }
7217
2.98k
  xmlXPathReleaseObject(ctxt->context, arg1);
7218
2.98k
  xmlXPathReleaseObject(ctxt->context, arg2);
7219
2.98k
  return(ret);
7220
2.98k
    }
7221
7222
452
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223
3.43k
}
7224
7225
/**
7226
 * xmlXPathNotEqualValues:
7227
 * @ctxt:  the XPath Parser context
7228
 *
7229
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7230
 *
7231
 * Returns 0 or 1 depending on the results of the test.
7232
 */
7233
int
7234
2.70k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7235
2.70k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7236
2.70k
    int ret = 0;
7237
7238
2.70k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7239
2.70k
    arg2 = valuePop(ctxt);
7240
2.70k
    arg1 = valuePop(ctxt);
7241
2.70k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7242
0
  if (arg1 != NULL)
7243
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7244
0
  else
7245
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7246
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7247
0
    }
7248
7249
2.70k
    if (arg1 == arg2) {
7250
#ifdef DEBUG_EXPR
7251
        xmlGenericError(xmlGenericErrorContext,
7252
    "NotEqual: by pointer\n");
7253
#endif
7254
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7255
0
        return(0);
7256
0
    }
7257
7258
    /*
7259
     *If either argument is a nodeset, it's a 'special case'
7260
     */
7261
2.70k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7262
2.70k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7263
  /*
7264
   *Hack it to assure arg1 is the nodeset
7265
   */
7266
2.70k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7267
2.67k
    argtmp = arg2;
7268
2.67k
    arg2 = arg1;
7269
2.67k
    arg1 = argtmp;
7270
2.67k
  }
7271
2.70k
  switch (arg2->type) {
7272
0
      case XPATH_UNDEFINED:
7273
#ifdef DEBUG_EXPR
7274
    xmlGenericError(xmlGenericErrorContext,
7275
      "NotEqual: undefined\n");
7276
#endif
7277
0
    break;
7278
0
      case XPATH_NODESET:
7279
0
      case XPATH_XSLT_TREE:
7280
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7281
0
    break;
7282
0
      case XPATH_BOOLEAN:
7283
0
    if ((arg1->nodesetval == NULL) ||
7284
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7285
0
    else
7286
0
        ret = 1;
7287
0
    ret = (ret != arg2->boolval);
7288
0
    break;
7289
25
      case XPATH_NUMBER:
7290
25
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7291
25
    break;
7292
2.67k
      case XPATH_STRING:
7293
2.67k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7294
2.67k
    break;
7295
0
      case XPATH_USERS:
7296
#ifdef LIBXML_XPTR_LOCS_ENABLED
7297
      case XPATH_POINT:
7298
      case XPATH_RANGE:
7299
      case XPATH_LOCATIONSET:
7300
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7301
0
    TODO
7302
0
    break;
7303
2.70k
  }
7304
2.70k
  xmlXPathReleaseObject(ctxt->context, arg1);
7305
2.70k
  xmlXPathReleaseObject(ctxt->context, arg2);
7306
2.70k
  return(ret);
7307
2.70k
    }
7308
7309
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7310
2.70k
}
7311
7312
/**
7313
 * xmlXPathCompareValues:
7314
 * @ctxt:  the XPath Parser context
7315
 * @inf:  less than (1) or greater than (0)
7316
 * @strict:  is the comparison strict
7317
 *
7318
 * Implement the compare operation on XPath objects:
7319
 *     @arg1 < @arg2    (1, 1, ...
7320
 *     @arg1 <= @arg2   (1, 0, ...
7321
 *     @arg1 > @arg2    (0, 1, ...
7322
 *     @arg1 >= @arg2   (0, 0, ...
7323
 *
7324
 * When neither object to be compared is a node-set and the operator is
7325
 * <=, <, >=, >, then the objects are compared by converted both objects
7326
 * to numbers and comparing the numbers according to IEEE 754. The <
7327
 * comparison will be true if and only if the first number is less than the
7328
 * second number. The <= comparison will be true if and only if the first
7329
 * number is less than or equal to the second number. The > comparison
7330
 * will be true if and only if the first number is greater than the second
7331
 * number. The >= comparison will be true if and only if the first number
7332
 * is greater than or equal to the second number.
7333
 *
7334
 * Returns 1 if the comparison succeeded, 0 if it failed
7335
 */
7336
int
7337
1.62k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7338
1.62k
    int ret = 0, arg1i = 0, arg2i = 0;
7339
1.62k
    xmlXPathObjectPtr arg1, arg2;
7340
7341
1.62k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7342
1.62k
    arg2 = valuePop(ctxt);
7343
1.62k
    arg1 = valuePop(ctxt);
7344
1.62k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7345
0
  if (arg1 != NULL)
7346
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7347
0
  else
7348
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7349
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7350
0
    }
7351
7352
1.62k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7353
1.62k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7354
  /*
7355
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7356
   * are not freed from within this routine; they will be freed from the
7357
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7358
   */
7359
925
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7360
925
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7361
29
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7362
896
  } else {
7363
896
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7364
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7365
0
                                arg1, arg2);
7366
896
      } else {
7367
896
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7368
896
                                arg2, arg1);
7369
896
      }
7370
896
  }
7371
925
  return(ret);
7372
925
    }
7373
7374
696
    if (arg1->type != XPATH_NUMBER) {
7375
594
  valuePush(ctxt, arg1);
7376
594
  xmlXPathNumberFunction(ctxt, 1);
7377
594
  arg1 = valuePop(ctxt);
7378
594
    }
7379
696
    if (arg2->type != XPATH_NUMBER) {
7380
48
  valuePush(ctxt, arg2);
7381
48
  xmlXPathNumberFunction(ctxt, 1);
7382
48
  arg2 = valuePop(ctxt);
7383
48
    }
7384
696
    if (ctxt->error)
7385
0
        goto error;
7386
    /*
7387
     * Add tests for infinity and nan
7388
     * => feedback on 3.4 for Inf and NaN
7389
     */
7390
    /* Hand check NaN and Infinity comparisons */
7391
696
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7392
2
  ret=0;
7393
694
    } else {
7394
694
  arg1i=xmlXPathIsInf(arg1->floatval);
7395
694
  arg2i=xmlXPathIsInf(arg2->floatval);
7396
694
  if (inf && strict) {
7397
148
      if ((arg1i == -1 && arg2i != -1) ||
7398
148
    (arg2i == 1 && arg1i != 1)) {
7399
50
    ret = 1;
7400
98
      } else if (arg1i == 0 && arg2i == 0) {
7401
48
    ret = (arg1->floatval < arg2->floatval);
7402
50
      } else {
7403
50
    ret = 0;
7404
50
      }
7405
148
  }
7406
546
  else if (inf && !strict) {
7407
50
      if (arg1i == -1 || arg2i == 1) {
7408
0
    ret = 1;
7409
50
      } else if (arg1i == 0 && arg2i == 0) {
7410
50
    ret = (arg1->floatval <= arg2->floatval);
7411
50
      } else {
7412
0
    ret = 0;
7413
0
      }
7414
50
  }
7415
496
  else if (!inf && strict) {
7416
48
      if ((arg1i == 1 && arg2i != 1) ||
7417
48
    (arg2i == -1 && arg1i != -1)) {
7418
0
    ret = 1;
7419
48
      } else if (arg1i == 0 && arg2i == 0) {
7420
48
    ret = (arg1->floatval > arg2->floatval);
7421
48
      } else {
7422
0
    ret = 0;
7423
0
      }
7424
48
  }
7425
448
  else if (!inf && !strict) {
7426
448
      if (arg1i == 1 || arg2i == -1) {
7427
0
    ret = 1;
7428
448
      } else if (arg1i == 0 && arg2i == 0) {
7429
448
    ret = (arg1->floatval >= arg2->floatval);
7430
448
      } else {
7431
0
    ret = 0;
7432
0
      }
7433
448
  }
7434
694
    }
7435
696
error:
7436
696
    xmlXPathReleaseObject(ctxt->context, arg1);
7437
696
    xmlXPathReleaseObject(ctxt->context, arg2);
7438
696
    return(ret);
7439
696
}
7440
7441
/**
7442
 * xmlXPathValueFlipSign:
7443
 * @ctxt:  the XPath Parser context
7444
 *
7445
 * Implement the unary - operation on an XPath object
7446
 * The numeric operators convert their operands to numbers as if
7447
 * by calling the number function.
7448
 */
7449
void
7450
182k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7451
182k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7452
182k
    CAST_TO_NUMBER;
7453
182k
    CHECK_TYPE(XPATH_NUMBER);
7454
182k
    ctxt->value->floatval = -ctxt->value->floatval;
7455
182k
}
7456
7457
/**
7458
 * xmlXPathAddValues:
7459
 * @ctxt:  the XPath Parser context
7460
 *
7461
 * Implement the add operation on XPath objects:
7462
 * The numeric operators convert their operands to numbers as if
7463
 * by calling the number function.
7464
 */
7465
void
7466
2.16k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7467
2.16k
    xmlXPathObjectPtr arg;
7468
2.16k
    double val;
7469
7470
2.16k
    arg = valuePop(ctxt);
7471
2.16k
    if (arg == NULL)
7472
2.16k
  XP_ERROR(XPATH_INVALID_OPERAND);
7473
2.16k
    val = xmlXPathCastToNumber(arg);
7474
2.16k
    xmlXPathReleaseObject(ctxt->context, arg);
7475
2.16k
    CAST_TO_NUMBER;
7476
2.16k
    CHECK_TYPE(XPATH_NUMBER);
7477
2.16k
    ctxt->value->floatval += val;
7478
2.16k
}
7479
7480
/**
7481
 * xmlXPathSubValues:
7482
 * @ctxt:  the XPath Parser context
7483
 *
7484
 * Implement the subtraction operation on XPath objects:
7485
 * The numeric operators convert their operands to numbers as if
7486
 * by calling the number function.
7487
 */
7488
void
7489
920
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7490
920
    xmlXPathObjectPtr arg;
7491
920
    double val;
7492
7493
920
    arg = valuePop(ctxt);
7494
920
    if (arg == NULL)
7495
920
  XP_ERROR(XPATH_INVALID_OPERAND);
7496
920
    val = xmlXPathCastToNumber(arg);
7497
920
    xmlXPathReleaseObject(ctxt->context, arg);
7498
920
    CAST_TO_NUMBER;
7499
920
    CHECK_TYPE(XPATH_NUMBER);
7500
920
    ctxt->value->floatval -= val;
7501
920
}
7502
7503
/**
7504
 * xmlXPathMultValues:
7505
 * @ctxt:  the XPath Parser context
7506
 *
7507
 * Implement the multiply operation on XPath objects:
7508
 * The numeric operators convert their operands to numbers as if
7509
 * by calling the number function.
7510
 */
7511
void
7512
570
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7513
570
    xmlXPathObjectPtr arg;
7514
570
    double val;
7515
7516
570
    arg = valuePop(ctxt);
7517
570
    if (arg == NULL)
7518
570
  XP_ERROR(XPATH_INVALID_OPERAND);
7519
570
    val = xmlXPathCastToNumber(arg);
7520
570
    xmlXPathReleaseObject(ctxt->context, arg);
7521
570
    CAST_TO_NUMBER;
7522
570
    CHECK_TYPE(XPATH_NUMBER);
7523
570
    ctxt->value->floatval *= val;
7524
570
}
7525
7526
/**
7527
 * xmlXPathDivValues:
7528
 * @ctxt:  the XPath Parser context
7529
 *
7530
 * Implement the div operation on XPath objects @arg1 / @arg2:
7531
 * The numeric operators convert their operands to numbers as if
7532
 * by calling the number function.
7533
 */
7534
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7535
void
7536
138
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7537
138
    xmlXPathObjectPtr arg;
7538
138
    double val;
7539
7540
138
    arg = valuePop(ctxt);
7541
138
    if (arg == NULL)
7542
138
  XP_ERROR(XPATH_INVALID_OPERAND);
7543
138
    val = xmlXPathCastToNumber(arg);
7544
138
    xmlXPathReleaseObject(ctxt->context, arg);
7545
138
    CAST_TO_NUMBER;
7546
138
    CHECK_TYPE(XPATH_NUMBER);
7547
138
    ctxt->value->floatval /= val;
7548
138
}
7549
7550
/**
7551
 * xmlXPathModValues:
7552
 * @ctxt:  the XPath Parser context
7553
 *
7554
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7555
 * The numeric operators convert their operands to numbers as if
7556
 * by calling the number function.
7557
 */
7558
void
7559
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7560
0
    xmlXPathObjectPtr arg;
7561
0
    double arg1, arg2;
7562
7563
0
    arg = valuePop(ctxt);
7564
0
    if (arg == NULL)
7565
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7566
0
    arg2 = xmlXPathCastToNumber(arg);
7567
0
    xmlXPathReleaseObject(ctxt->context, arg);
7568
0
    CAST_TO_NUMBER;
7569
0
    CHECK_TYPE(XPATH_NUMBER);
7570
0
    arg1 = ctxt->value->floatval;
7571
0
    if (arg2 == 0)
7572
0
  ctxt->value->floatval = xmlXPathNAN;
7573
0
    else {
7574
0
  ctxt->value->floatval = fmod(arg1, arg2);
7575
0
    }
7576
0
}
7577
7578
/************************************************************************
7579
 *                  *
7580
 *    The traversal functions         *
7581
 *                  *
7582
 ************************************************************************/
7583
7584
/*
7585
 * A traversal function enumerates nodes along an axis.
7586
 * Initially it must be called with NULL, and it indicates
7587
 * termination on the axis by returning NULL.
7588
 */
7589
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7590
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7591
7592
/*
7593
 * xmlXPathTraversalFunctionExt:
7594
 * A traversal function enumerates nodes along an axis.
7595
 * Initially it must be called with NULL, and it indicates
7596
 * termination on the axis by returning NULL.
7597
 * The context node of the traversal is specified via @contextNode.
7598
 */
7599
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7600
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7601
7602
/*
7603
 * xmlXPathNodeSetMergeFunction:
7604
 * Used for merging node sets in xmlXPathCollectAndTest().
7605
 */
7606
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7607
        (xmlNodeSetPtr, xmlNodeSetPtr);
7608
7609
7610
/**
7611
 * xmlXPathNextSelf:
7612
 * @ctxt:  the XPath Parser context
7613
 * @cur:  the current node in the traversal
7614
 *
7615
 * Traversal function for the "self" direction
7616
 * The self axis contains just the context node itself
7617
 *
7618
 * Returns the next element following that axis
7619
 */
7620
xmlNodePtr
7621
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7622
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7623
0
    if (cur == NULL)
7624
0
        return(ctxt->context->node);
7625
0
    return(NULL);
7626
0
}
7627
7628
/**
7629
 * xmlXPathNextChild:
7630
 * @ctxt:  the XPath Parser context
7631
 * @cur:  the current node in the traversal
7632
 *
7633
 * Traversal function for the "child" direction
7634
 * The child axis contains the children of the context node in document order.
7635
 *
7636
 * Returns the next element following that axis
7637
 */
7638
xmlNodePtr
7639
207k
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7640
207k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7641
207k
    if (cur == NULL) {
7642
96.2k
  if (ctxt->context->node == NULL) return(NULL);
7643
96.2k
  switch (ctxt->context->node->type) {
7644
83.4k
            case XML_ELEMENT_NODE:
7645
96.1k
            case XML_TEXT_NODE:
7646
96.1k
            case XML_CDATA_SECTION_NODE:
7647
96.1k
            case XML_ENTITY_REF_NODE:
7648
96.1k
            case XML_ENTITY_NODE:
7649
96.1k
            case XML_PI_NODE:
7650
96.1k
            case XML_COMMENT_NODE:
7651
96.1k
            case XML_NOTATION_NODE:
7652
96.1k
            case XML_DTD_NODE:
7653
96.1k
    return(ctxt->context->node->children);
7654
70
            case XML_DOCUMENT_NODE:
7655
70
            case XML_DOCUMENT_TYPE_NODE:
7656
70
            case XML_DOCUMENT_FRAG_NODE:
7657
70
            case XML_HTML_DOCUMENT_NODE:
7658
70
    return(((xmlDocPtr) ctxt->context->node)->children);
7659
0
      case XML_ELEMENT_DECL:
7660
0
      case XML_ATTRIBUTE_DECL:
7661
0
      case XML_ENTITY_DECL:
7662
0
            case XML_ATTRIBUTE_NODE:
7663
0
      case XML_NAMESPACE_DECL:
7664
0
      case XML_XINCLUDE_START:
7665
0
      case XML_XINCLUDE_END:
7666
0
    return(NULL);
7667
96.2k
  }
7668
0
  return(NULL);
7669
96.2k
    }
7670
111k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7671
111k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7672
0
  return(NULL);
7673
111k
    return(cur->next);
7674
111k
}
7675
7676
/**
7677
 * xmlXPathNextChildElement:
7678
 * @ctxt:  the XPath Parser context
7679
 * @cur:  the current node in the traversal
7680
 *
7681
 * Traversal function for the "child" direction and nodes of type element.
7682
 * The child axis contains the children of the context node in document order.
7683
 *
7684
 * Returns the next element following that axis
7685
 */
7686
static xmlNodePtr
7687
933k
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7688
933k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7689
933k
    if (cur == NULL) {
7690
176k
  cur = ctxt->context->node;
7691
176k
  if (cur == NULL) return(NULL);
7692
  /*
7693
  * Get the first element child.
7694
  */
7695
176k
  switch (cur->type) {
7696
92.0k
            case XML_ELEMENT_NODE:
7697
92.0k
      case XML_DOCUMENT_FRAG_NODE:
7698
92.0k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7699
92.0k
            case XML_ENTITY_NODE:
7700
92.0k
    cur = cur->children;
7701
92.0k
    if (cur != NULL) {
7702
11.6k
        if (cur->type == XML_ELEMENT_NODE)
7703
7.19k
      return(cur);
7704
4.48k
        do {
7705
4.48k
      cur = cur->next;
7706
4.48k
        } while ((cur != NULL) &&
7707
4.48k
      (cur->type != XML_ELEMENT_NODE));
7708
4.45k
        return(cur);
7709
11.6k
    }
7710
80.4k
    return(NULL);
7711
9.71k
            case XML_DOCUMENT_NODE:
7712
9.71k
            case XML_HTML_DOCUMENT_NODE:
7713
9.71k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7714
74.3k
      default:
7715
74.3k
    return(NULL);
7716
176k
  }
7717
0
  return(NULL);
7718
176k
    }
7719
    /*
7720
    * Get the next sibling element node.
7721
    */
7722
757k
    switch (cur->type) {
7723
757k
  case XML_ELEMENT_NODE:
7724
757k
  case XML_TEXT_NODE:
7725
757k
  case XML_ENTITY_REF_NODE:
7726
757k
  case XML_ENTITY_NODE:
7727
757k
  case XML_CDATA_SECTION_NODE:
7728
757k
  case XML_PI_NODE:
7729
757k
  case XML_COMMENT_NODE:
7730
757k
  case XML_XINCLUDE_END:
7731
757k
      break;
7732
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7733
0
  default:
7734
0
      return(NULL);
7735
757k
    }
7736
757k
    if (cur->next != NULL) {
7737
738k
  if (cur->next->type == XML_ELEMENT_NODE)
7738
686k
      return(cur->next);
7739
51.8k
  cur = cur->next;
7740
57.6k
  do {
7741
57.6k
      cur = cur->next;
7742
57.6k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7743
51.8k
  return(cur);
7744
738k
    }
7745
18.9k
    return(NULL);
7746
757k
}
7747
7748
#if 0
7749
/**
7750
 * xmlXPathNextDescendantOrSelfElemParent:
7751
 * @ctxt:  the XPath Parser context
7752
 * @cur:  the current node in the traversal
7753
 *
7754
 * Traversal function for the "descendant-or-self" axis.
7755
 * Additionally it returns only nodes which can be parents of
7756
 * element nodes.
7757
 *
7758
 *
7759
 * Returns the next element following that axis
7760
 */
7761
static xmlNodePtr
7762
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7763
               xmlNodePtr contextNode)
7764
{
7765
    if (cur == NULL) {
7766
  if (contextNode == NULL)
7767
      return(NULL);
7768
  switch (contextNode->type) {
7769
      case XML_ELEMENT_NODE:
7770
      case XML_XINCLUDE_START:
7771
      case XML_DOCUMENT_FRAG_NODE:
7772
      case XML_DOCUMENT_NODE:
7773
      case XML_HTML_DOCUMENT_NODE:
7774
    return(contextNode);
7775
      default:
7776
    return(NULL);
7777
  }
7778
  return(NULL);
7779
    } else {
7780
  xmlNodePtr start = cur;
7781
7782
  while (cur != NULL) {
7783
      switch (cur->type) {
7784
    case XML_ELEMENT_NODE:
7785
    /* TODO: OK to have XInclude here? */
7786
    case XML_XINCLUDE_START:
7787
    case XML_DOCUMENT_FRAG_NODE:
7788
        if (cur != start)
7789
      return(cur);
7790
        if (cur->children != NULL) {
7791
      cur = cur->children;
7792
      continue;
7793
        }
7794
        break;
7795
    /* Not sure if we need those here. */
7796
    case XML_DOCUMENT_NODE:
7797
    case XML_HTML_DOCUMENT_NODE:
7798
        if (cur != start)
7799
      return(cur);
7800
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7801
    default:
7802
        break;
7803
      }
7804
7805
next_sibling:
7806
      if ((cur == NULL) || (cur == contextNode))
7807
    return(NULL);
7808
      if (cur->next != NULL) {
7809
    cur = cur->next;
7810
      } else {
7811
    cur = cur->parent;
7812
    goto next_sibling;
7813
      }
7814
  }
7815
    }
7816
    return(NULL);
7817
}
7818
#endif
7819
7820
/**
7821
 * xmlXPathNextDescendant:
7822
 * @ctxt:  the XPath Parser context
7823
 * @cur:  the current node in the traversal
7824
 *
7825
 * Traversal function for the "descendant" direction
7826
 * the descendant axis contains the descendants of the context node in document
7827
 * order; a descendant is a child or a child of a child and so on.
7828
 *
7829
 * Returns the next element following that axis
7830
 */
7831
xmlNodePtr
7832
5.41M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7833
5.41M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7834
5.41M
    if (cur == NULL) {
7835
6.11k
  if (ctxt->context->node == NULL)
7836
0
      return(NULL);
7837
6.11k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7838
6.11k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7839
0
      return(NULL);
7840
7841
6.11k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7842
3.34k
      return(ctxt->context->doc->children);
7843
2.77k
        return(ctxt->context->node->children);
7844
6.11k
    }
7845
7846
5.41M
    if (cur->type == XML_NAMESPACE_DECL)
7847
0
        return(NULL);
7848
5.41M
    if (cur->children != NULL) {
7849
  /*
7850
   * Do not descend on entities declarations
7851
   */
7852
190k
  if (cur->children->type != XML_ENTITY_DECL) {
7853
190k
      cur = cur->children;
7854
      /*
7855
       * Skip DTDs
7856
       */
7857
190k
      if (cur->type != XML_DTD_NODE)
7858
190k
    return(cur);
7859
190k
  }
7860
190k
    }
7861
7862
5.22M
    if (cur == ctxt->context->node) return(NULL);
7863
7864
5.22M
    while (cur->next != NULL) {
7865
5.14M
  cur = cur->next;
7866
5.14M
  if ((cur->type != XML_ENTITY_DECL) &&
7867
5.14M
      (cur->type != XML_DTD_NODE))
7868
5.14M
      return(cur);
7869
5.14M
    }
7870
7871
196k
    do {
7872
196k
        cur = cur->parent;
7873
196k
  if (cur == NULL) break;
7874
196k
  if (cur == ctxt->context->node) return(NULL);
7875
188k
  if (cur->next != NULL) {
7876
68.3k
      cur = cur->next;
7877
68.3k
      return(cur);
7878
68.3k
  }
7879
188k
    } while (cur != NULL);
7880
0
    return(cur);
7881
76.0k
}
7882
7883
/**
7884
 * xmlXPathNextDescendantOrSelf:
7885
 * @ctxt:  the XPath Parser context
7886
 * @cur:  the current node in the traversal
7887
 *
7888
 * Traversal function for the "descendant-or-self" direction
7889
 * the descendant-or-self axis contains the context node and the descendants
7890
 * of the context node in document order; thus the context node is the first
7891
 * node on the axis, and the first child of the context node is the second node
7892
 * on the axis
7893
 *
7894
 * Returns the next element following that axis
7895
 */
7896
xmlNodePtr
7897
3.29M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7898
3.29M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7899
3.29M
    if (cur == NULL)
7900
5.24k
        return(ctxt->context->node);
7901
7902
3.29M
    if (ctxt->context->node == NULL)
7903
0
        return(NULL);
7904
3.29M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7905
3.29M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7906
3.49k
        return(NULL);
7907
7908
3.28M
    return(xmlXPathNextDescendant(ctxt, cur));
7909
3.29M
}
7910
7911
/**
7912
 * xmlXPathNextParent:
7913
 * @ctxt:  the XPath Parser context
7914
 * @cur:  the current node in the traversal
7915
 *
7916
 * Traversal function for the "parent" direction
7917
 * The parent axis contains the parent of the context node, if there is one.
7918
 *
7919
 * Returns the next element following that axis
7920
 */
7921
xmlNodePtr
7922
1.04M
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7923
1.04M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7924
    /*
7925
     * the parent of an attribute or namespace node is the element
7926
     * to which the attribute or namespace node is attached
7927
     * Namespace handling !!!
7928
     */
7929
1.04M
    if (cur == NULL) {
7930
523k
  if (ctxt->context->node == NULL) return(NULL);
7931
523k
  switch (ctxt->context->node->type) {
7932
372k
            case XML_ELEMENT_NODE:
7933
507k
            case XML_TEXT_NODE:
7934
507k
            case XML_CDATA_SECTION_NODE:
7935
507k
            case XML_ENTITY_REF_NODE:
7936
507k
            case XML_ENTITY_NODE:
7937
514k
            case XML_PI_NODE:
7938
521k
            case XML_COMMENT_NODE:
7939
521k
            case XML_NOTATION_NODE:
7940
521k
            case XML_DTD_NODE:
7941
521k
      case XML_ELEMENT_DECL:
7942
521k
      case XML_ATTRIBUTE_DECL:
7943
521k
      case XML_XINCLUDE_START:
7944
521k
      case XML_XINCLUDE_END:
7945
521k
      case XML_ENTITY_DECL:
7946
521k
    if (ctxt->context->node->parent == NULL)
7947
0
        return((xmlNodePtr) ctxt->context->doc);
7948
521k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7949
521k
        ((ctxt->context->node->parent->name[0] == ' ') ||
7950
520k
         (xmlStrEqual(ctxt->context->node->parent->name,
7951
520k
         BAD_CAST "fake node libxslt"))))
7952
0
        return(NULL);
7953
521k
    return(ctxt->context->node->parent);
7954
0
            case XML_ATTRIBUTE_NODE: {
7955
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7956
7957
0
    return(att->parent);
7958
521k
      }
7959
1.35k
            case XML_DOCUMENT_NODE:
7960
1.35k
            case XML_DOCUMENT_TYPE_NODE:
7961
1.35k
            case XML_DOCUMENT_FRAG_NODE:
7962
1.35k
            case XML_HTML_DOCUMENT_NODE:
7963
1.35k
                return(NULL);
7964
0
      case XML_NAMESPACE_DECL: {
7965
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7966
7967
0
    if ((ns->next != NULL) &&
7968
0
        (ns->next->type != XML_NAMESPACE_DECL))
7969
0
        return((xmlNodePtr) ns->next);
7970
0
                return(NULL);
7971
0
      }
7972
523k
  }
7973
523k
    }
7974
521k
    return(NULL);
7975
1.04M
}
7976
7977
/**
7978
 * xmlXPathNextAncestor:
7979
 * @ctxt:  the XPath Parser context
7980
 * @cur:  the current node in the traversal
7981
 *
7982
 * Traversal function for the "ancestor" direction
7983
 * the ancestor axis contains the ancestors of the context node; the ancestors
7984
 * of the context node consist of the parent of context node and the parent's
7985
 * parent and so on; the nodes are ordered in reverse document order; thus the
7986
 * parent is the first node on the axis, and the parent's parent is the second
7987
 * node on the axis
7988
 *
7989
 * Returns the next element following that axis
7990
 */
7991
xmlNodePtr
7992
3.14k
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7993
3.14k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7994
    /*
7995
     * the parent of an attribute or namespace node is the element
7996
     * to which the attribute or namespace node is attached
7997
     * !!!!!!!!!!!!!
7998
     */
7999
3.14k
    if (cur == NULL) {
8000
352
  if (ctxt->context->node == NULL) return(NULL);
8001
352
  switch (ctxt->context->node->type) {
8002
352
            case XML_ELEMENT_NODE:
8003
352
            case XML_TEXT_NODE:
8004
352
            case XML_CDATA_SECTION_NODE:
8005
352
            case XML_ENTITY_REF_NODE:
8006
352
            case XML_ENTITY_NODE:
8007
352
            case XML_PI_NODE:
8008
352
            case XML_COMMENT_NODE:
8009
352
      case XML_DTD_NODE:
8010
352
      case XML_ELEMENT_DECL:
8011
352
      case XML_ATTRIBUTE_DECL:
8012
352
      case XML_ENTITY_DECL:
8013
352
            case XML_NOTATION_NODE:
8014
352
      case XML_XINCLUDE_START:
8015
352
      case XML_XINCLUDE_END:
8016
352
    if (ctxt->context->node->parent == NULL)
8017
0
        return((xmlNodePtr) ctxt->context->doc);
8018
352
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8019
352
        ((ctxt->context->node->parent->name[0] == ' ') ||
8020
330
         (xmlStrEqual(ctxt->context->node->parent->name,
8021
330
         BAD_CAST "fake node libxslt"))))
8022
0
        return(NULL);
8023
352
    return(ctxt->context->node->parent);
8024
0
            case XML_ATTRIBUTE_NODE: {
8025
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8026
8027
0
    return(tmp->parent);
8028
352
      }
8029
0
            case XML_DOCUMENT_NODE:
8030
0
            case XML_DOCUMENT_TYPE_NODE:
8031
0
            case XML_DOCUMENT_FRAG_NODE:
8032
0
            case XML_HTML_DOCUMENT_NODE:
8033
0
                return(NULL);
8034
0
      case XML_NAMESPACE_DECL: {
8035
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8036
8037
0
    if ((ns->next != NULL) &&
8038
0
        (ns->next->type != XML_NAMESPACE_DECL))
8039
0
        return((xmlNodePtr) ns->next);
8040
    /* Bad, how did that namespace end up here ? */
8041
0
                return(NULL);
8042
0
      }
8043
352
  }
8044
0
  return(NULL);
8045
352
    }
8046
2.79k
    if (cur == ctxt->context->doc->children)
8047
330
  return((xmlNodePtr) ctxt->context->doc);
8048
2.46k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8049
352
  return(NULL);
8050
2.11k
    switch (cur->type) {
8051
2.11k
  case XML_ELEMENT_NODE:
8052
2.11k
  case XML_TEXT_NODE:
8053
2.11k
  case XML_CDATA_SECTION_NODE:
8054
2.11k
  case XML_ENTITY_REF_NODE:
8055
2.11k
  case XML_ENTITY_NODE:
8056
2.11k
  case XML_PI_NODE:
8057
2.11k
  case XML_COMMENT_NODE:
8058
2.11k
  case XML_NOTATION_NODE:
8059
2.11k
  case XML_DTD_NODE:
8060
2.11k
        case XML_ELEMENT_DECL:
8061
2.11k
        case XML_ATTRIBUTE_DECL:
8062
2.11k
        case XML_ENTITY_DECL:
8063
2.11k
  case XML_XINCLUDE_START:
8064
2.11k
  case XML_XINCLUDE_END:
8065
2.11k
      if (cur->parent == NULL)
8066
0
    return(NULL);
8067
2.11k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8068
2.11k
    ((cur->parent->name[0] == ' ') ||
8069
2.11k
     (xmlStrEqual(cur->parent->name,
8070
2.11k
            BAD_CAST "fake node libxslt"))))
8071
0
    return(NULL);
8072
2.11k
      return(cur->parent);
8073
0
  case XML_ATTRIBUTE_NODE: {
8074
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8075
8076
0
      return(att->parent);
8077
2.11k
  }
8078
0
  case XML_NAMESPACE_DECL: {
8079
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8080
8081
0
      if ((ns->next != NULL) &&
8082
0
          (ns->next->type != XML_NAMESPACE_DECL))
8083
0
          return((xmlNodePtr) ns->next);
8084
      /* Bad, how did that namespace end up here ? */
8085
0
            return(NULL);
8086
0
  }
8087
0
  case XML_DOCUMENT_NODE:
8088
0
  case XML_DOCUMENT_TYPE_NODE:
8089
0
  case XML_DOCUMENT_FRAG_NODE:
8090
0
  case XML_HTML_DOCUMENT_NODE:
8091
0
      return(NULL);
8092
2.11k
    }
8093
0
    return(NULL);
8094
2.11k
}
8095
8096
/**
8097
 * xmlXPathNextAncestorOrSelf:
8098
 * @ctxt:  the XPath Parser context
8099
 * @cur:  the current node in the traversal
8100
 *
8101
 * Traversal function for the "ancestor-or-self" direction
8102
 * he ancestor-or-self axis contains the context node and ancestors of
8103
 * the context node in reverse document order; thus the context node is
8104
 * the first node on the axis, and the context node's parent the second;
8105
 * parent here is defined the same as with the parent axis.
8106
 *
8107
 * Returns the next element following that axis
8108
 */
8109
xmlNodePtr
8110
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8111
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8112
0
    if (cur == NULL)
8113
0
        return(ctxt->context->node);
8114
0
    return(xmlXPathNextAncestor(ctxt, cur));
8115
0
}
8116
8117
/**
8118
 * xmlXPathNextFollowingSibling:
8119
 * @ctxt:  the XPath Parser context
8120
 * @cur:  the current node in the traversal
8121
 *
8122
 * Traversal function for the "following-sibling" direction
8123
 * The following-sibling axis contains the following siblings of the context
8124
 * node in document order.
8125
 *
8126
 * Returns the next element following that axis
8127
 */
8128
xmlNodePtr
8129
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8130
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8131
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8132
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8133
0
  return(NULL);
8134
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8135
0
        return(NULL);
8136
0
    if (cur == NULL)
8137
0
        return(ctxt->context->node->next);
8138
0
    return(cur->next);
8139
0
}
8140
8141
/**
8142
 * xmlXPathNextPrecedingSibling:
8143
 * @ctxt:  the XPath Parser context
8144
 * @cur:  the current node in the traversal
8145
 *
8146
 * Traversal function for the "preceding-sibling" direction
8147
 * The preceding-sibling axis contains the preceding siblings of the context
8148
 * node in reverse document order; the first preceding sibling is first on the
8149
 * axis; the sibling preceding that node is the second on the axis and so on.
8150
 *
8151
 * Returns the next element following that axis
8152
 */
8153
xmlNodePtr
8154
132k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8155
132k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8156
132k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8157
132k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8158
0
  return(NULL);
8159
132k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8160
0
        return(NULL);
8161
132k
    if (cur == NULL)
8162
11.3k
        return(ctxt->context->node->prev);
8163
121k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8164
0
  cur = cur->prev;
8165
0
  if (cur == NULL)
8166
0
      return(ctxt->context->node->prev);
8167
0
    }
8168
121k
    return(cur->prev);
8169
121k
}
8170
8171
/**
8172
 * xmlXPathNextFollowing:
8173
 * @ctxt:  the XPath Parser context
8174
 * @cur:  the current node in the traversal
8175
 *
8176
 * Traversal function for the "following" direction
8177
 * The following axis contains all nodes in the same document as the context
8178
 * node that are after the context node in document order, excluding any
8179
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8180
 * are ordered in document order
8181
 *
8182
 * Returns the next element following that axis
8183
 */
8184
xmlNodePtr
8185
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8186
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8187
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8188
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8189
0
        return(cur->children);
8190
8191
0
    if (cur == NULL) {
8192
0
        cur = ctxt->context->node;
8193
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8194
0
            cur = cur->parent;
8195
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8196
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8197
8198
0
            if ((ns->next == NULL) ||
8199
0
                (ns->next->type == XML_NAMESPACE_DECL))
8200
0
                return (NULL);
8201
0
            cur = (xmlNodePtr) ns->next;
8202
0
        }
8203
0
    }
8204
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8205
0
    if (cur->next != NULL) return(cur->next) ;
8206
0
    do {
8207
0
        cur = cur->parent;
8208
0
        if (cur == NULL) break;
8209
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8210
0
        if (cur->next != NULL) return(cur->next);
8211
0
    } while (cur != NULL);
8212
0
    return(cur);
8213
0
}
8214
8215
/*
8216
 * xmlXPathIsAncestor:
8217
 * @ancestor:  the ancestor node
8218
 * @node:  the current node
8219
 *
8220
 * Check that @ancestor is a @node's ancestor
8221
 *
8222
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8223
 */
8224
static int
8225
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8226
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8227
0
    if (node->type == XML_NAMESPACE_DECL)
8228
0
        return(0);
8229
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8230
0
        return(0);
8231
    /* nodes need to be in the same document */
8232
0
    if (ancestor->doc != node->doc) return(0);
8233
    /* avoid searching if ancestor or node is the root node */
8234
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8235
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8236
0
    while (node->parent != NULL) {
8237
0
        if (node->parent == ancestor)
8238
0
            return(1);
8239
0
  node = node->parent;
8240
0
    }
8241
0
    return(0);
8242
0
}
8243
8244
/**
8245
 * xmlXPathNextPreceding:
8246
 * @ctxt:  the XPath Parser context
8247
 * @cur:  the current node in the traversal
8248
 *
8249
 * Traversal function for the "preceding" direction
8250
 * the preceding axis contains all nodes in the same document as the context
8251
 * node that are before the context node in document order, excluding any
8252
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253
 * ordered in reverse document order
8254
 *
8255
 * Returns the next element following that axis
8256
 */
8257
xmlNodePtr
8258
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8259
0
{
8260
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8261
0
    if (cur == NULL) {
8262
0
        cur = ctxt->context->node;
8263
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8264
0
            cur = cur->parent;
8265
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8266
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8267
8268
0
            if ((ns->next == NULL) ||
8269
0
                (ns->next->type == XML_NAMESPACE_DECL))
8270
0
                return (NULL);
8271
0
            cur = (xmlNodePtr) ns->next;
8272
0
        }
8273
0
    }
8274
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8275
0
  return (NULL);
8276
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8277
0
  cur = cur->prev;
8278
0
    do {
8279
0
        if (cur->prev != NULL) {
8280
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8281
0
            return (cur);
8282
0
        }
8283
8284
0
        cur = cur->parent;
8285
0
        if (cur == NULL)
8286
0
            return (NULL);
8287
0
        if (cur == ctxt->context->doc->children)
8288
0
            return (NULL);
8289
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8290
0
    return (cur);
8291
0
}
8292
8293
/**
8294
 * xmlXPathNextPrecedingInternal:
8295
 * @ctxt:  the XPath Parser context
8296
 * @cur:  the current node in the traversal
8297
 *
8298
 * Traversal function for the "preceding" direction
8299
 * the preceding axis contains all nodes in the same document as the context
8300
 * node that are before the context node in document order, excluding any
8301
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8302
 * ordered in reverse document order
8303
 * This is a faster implementation but internal only since it requires a
8304
 * state kept in the parser context: ctxt->ancestor.
8305
 *
8306
 * Returns the next element following that axis
8307
 */
8308
static xmlNodePtr
8309
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8310
                              xmlNodePtr cur)
8311
3.92M
{
8312
3.92M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8313
3.92M
    if (cur == NULL) {
8314
5.28k
        cur = ctxt->context->node;
8315
5.28k
        if (cur == NULL)
8316
0
            return (NULL);
8317
5.28k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8318
0
            cur = cur->parent;
8319
5.28k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8320
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8321
8322
0
            if ((ns->next == NULL) ||
8323
0
                (ns->next->type == XML_NAMESPACE_DECL))
8324
0
                return (NULL);
8325
0
            cur = (xmlNodePtr) ns->next;
8326
0
        }
8327
5.28k
        ctxt->ancestor = cur->parent;
8328
5.28k
    }
8329
3.92M
    if (cur->type == XML_NAMESPACE_DECL)
8330
0
        return(NULL);
8331
3.92M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8332
22
  cur = cur->prev;
8333
4.15M
    while (cur->prev == NULL) {
8334
2.02M
        cur = cur->parent;
8335
2.02M
        if (cur == NULL)
8336
1.24k
            return (NULL);
8337
2.02M
        if (cur == ctxt->context->doc->children)
8338
4.02k
            return (NULL);
8339
2.02M
        if (cur != ctxt->ancestor)
8340
1.79M
            return (cur);
8341
230k
        ctxt->ancestor = cur->parent;
8342
230k
    }
8343
2.12M
    cur = cur->prev;
8344
3.92M
    while (cur->last != NULL)
8345
1.79M
        cur = cur->last;
8346
2.12M
    return (cur);
8347
3.92M
}
8348
8349
/**
8350
 * xmlXPathNextNamespace:
8351
 * @ctxt:  the XPath Parser context
8352
 * @cur:  the current attribute in the traversal
8353
 *
8354
 * Traversal function for the "namespace" direction
8355
 * the namespace axis contains the namespace nodes of the context node;
8356
 * the order of nodes on this axis is implementation-defined; the axis will
8357
 * be empty unless the context node is an element
8358
 *
8359
 * We keep the XML namespace node at the end of the list.
8360
 *
8361
 * Returns the next element following that axis
8362
 */
8363
xmlNodePtr
8364
448k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8365
448k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8366
448k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8367
447k
    if (cur == NULL) {
8368
89.3k
        if (ctxt->context->tmpNsList != NULL)
8369
0
      xmlFree(ctxt->context->tmpNsList);
8370
89.3k
  ctxt->context->tmpNsList =
8371
89.3k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8372
89.3k
  ctxt->context->tmpNsNr = 0;
8373
89.3k
  if (ctxt->context->tmpNsList != NULL) {
8374
358k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8375
268k
    ctxt->context->tmpNsNr++;
8376
268k
      }
8377
89.3k
  }
8378
89.3k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8379
89.3k
    }
8380
358k
    if (ctxt->context->tmpNsNr > 0) {
8381
268k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8382
268k
    } else {
8383
89.3k
  if (ctxt->context->tmpNsList != NULL)
8384
89.3k
      xmlFree(ctxt->context->tmpNsList);
8385
89.3k
  ctxt->context->tmpNsList = NULL;
8386
89.3k
  return(NULL);
8387
89.3k
    }
8388
358k
}
8389
8390
/**
8391
 * xmlXPathNextAttribute:
8392
 * @ctxt:  the XPath Parser context
8393
 * @cur:  the current attribute in the traversal
8394
 *
8395
 * Traversal function for the "attribute" direction
8396
 * TODO: support DTD inherited default attributes
8397
 *
8398
 * Returns the next element following that axis
8399
 */
8400
xmlNodePtr
8401
438k
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8402
438k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8403
438k
    if (ctxt->context->node == NULL)
8404
0
  return(NULL);
8405
438k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8406
56.5k
  return(NULL);
8407
382k
    if (cur == NULL) {
8408
268k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8409
0
      return(NULL);
8410
268k
        return((xmlNodePtr)ctxt->context->node->properties);
8411
268k
    }
8412
113k
    return((xmlNodePtr)cur->next);
8413
382k
}
8414
8415
/************************************************************************
8416
 *                  *
8417
 *    NodeTest Functions          *
8418
 *                  *
8419
 ************************************************************************/
8420
8421
#define IS_FUNCTION     200
8422
8423
8424
/************************************************************************
8425
 *                  *
8426
 *    Implicit tree core function library     *
8427
 *                  *
8428
 ************************************************************************/
8429
8430
/**
8431
 * xmlXPathRoot:
8432
 * @ctxt:  the XPath Parser context
8433
 *
8434
 * Initialize the context to the root of the document
8435
 */
8436
void
8437
18.9k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8438
18.9k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8439
0
  return;
8440
18.9k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8441
18.9k
  (xmlNodePtr) ctxt->context->doc));
8442
18.9k
}
8443
8444
/************************************************************************
8445
 *                  *
8446
 *    The explicit core function library      *
8447
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8448
 *                  *
8449
 ************************************************************************/
8450
8451
8452
/**
8453
 * xmlXPathLastFunction:
8454
 * @ctxt:  the XPath Parser context
8455
 * @nargs:  the number of arguments
8456
 *
8457
 * Implement the last() XPath function
8458
 *    number last()
8459
 * The last function returns the number of nodes in the context node list.
8460
 */
8461
void
8462
86.0k
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8463
258k
    CHECK_ARITY(0);
8464
258k
    if (ctxt->context->contextSize >= 0) {
8465
86.0k
  valuePush(ctxt,
8466
86.0k
      xmlXPathCacheNewFloat(ctxt->context,
8467
86.0k
    (double) ctxt->context->contextSize));
8468
#ifdef DEBUG_EXPR
8469
  xmlGenericError(xmlGenericErrorContext,
8470
    "last() : %d\n", ctxt->context->contextSize);
8471
#endif
8472
86.0k
    } else {
8473
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8474
0
    }
8475
258k
}
8476
8477
/**
8478
 * xmlXPathPositionFunction:
8479
 * @ctxt:  the XPath Parser context
8480
 * @nargs:  the number of arguments
8481
 *
8482
 * Implement the position() XPath function
8483
 *    number position()
8484
 * The position function returns the position of the context node in the
8485
 * context node list. The first position is 1, and so the last position
8486
 * will be equal to last().
8487
 */
8488
void
8489
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490
0
    CHECK_ARITY(0);
8491
0
    if (ctxt->context->proximityPosition >= 0) {
8492
0
  valuePush(ctxt,
8493
0
        xmlXPathCacheNewFloat(ctxt->context,
8494
0
    (double) ctxt->context->proximityPosition));
8495
#ifdef DEBUG_EXPR
8496
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8497
    ctxt->context->proximityPosition);
8498
#endif
8499
0
    } else {
8500
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8501
0
    }
8502
0
}
8503
8504
/**
8505
 * xmlXPathCountFunction:
8506
 * @ctxt:  the XPath Parser context
8507
 * @nargs:  the number of arguments
8508
 *
8509
 * Implement the count() XPath function
8510
 *    number count(node-set)
8511
 */
8512
void
8513
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514
0
    xmlXPathObjectPtr cur;
8515
8516
0
    CHECK_ARITY(1);
8517
0
    if ((ctxt->value == NULL) ||
8518
0
  ((ctxt->value->type != XPATH_NODESET) &&
8519
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8520
0
  XP_ERROR(XPATH_INVALID_TYPE);
8521
0
    cur = valuePop(ctxt);
8522
8523
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
8524
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8525
0
    else
8526
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8527
0
      (double) cur->nodesetval->nodeNr));
8528
0
    xmlXPathReleaseObject(ctxt->context, cur);
8529
0
}
8530
8531
/**
8532
 * xmlXPathGetElementsByIds:
8533
 * @doc:  the document
8534
 * @ids:  a whitespace separated list of IDs
8535
 *
8536
 * Selects elements by their unique ID.
8537
 *
8538
 * Returns a node-set of selected elements.
8539
 */
8540
static xmlNodeSetPtr
8541
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8542
0
    xmlNodeSetPtr ret;
8543
0
    const xmlChar *cur = ids;
8544
0
    xmlChar *ID;
8545
0
    xmlAttrPtr attr;
8546
0
    xmlNodePtr elem = NULL;
8547
8548
0
    if (ids == NULL) return(NULL);
8549
8550
0
    ret = xmlXPathNodeSetCreate(NULL);
8551
0
    if (ret == NULL)
8552
0
        return(ret);
8553
8554
0
    while (IS_BLANK_CH(*cur)) cur++;
8555
0
    while (*cur != 0) {
8556
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8557
0
      cur++;
8558
8559
0
        ID = xmlStrndup(ids, cur - ids);
8560
0
  if (ID != NULL) {
8561
      /*
8562
       * We used to check the fact that the value passed
8563
       * was an NCName, but this generated much troubles for
8564
       * me and Aleksey Sanin, people blatantly violated that
8565
       * constraint, like Visa3D spec.
8566
       * if (xmlValidateNCName(ID, 1) == 0)
8567
       */
8568
0
      attr = xmlGetID(doc, ID);
8569
0
      if (attr != NULL) {
8570
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8571
0
        elem = attr->parent;
8572
0
    else if (attr->type == XML_ELEMENT_NODE)
8573
0
        elem = (xmlNodePtr) attr;
8574
0
    else
8575
0
        elem = NULL;
8576
                /* TODO: Check memory error. */
8577
0
    if (elem != NULL)
8578
0
        xmlXPathNodeSetAdd(ret, elem);
8579
0
      }
8580
0
      xmlFree(ID);
8581
0
  }
8582
8583
0
  while (IS_BLANK_CH(*cur)) cur++;
8584
0
  ids = cur;
8585
0
    }
8586
0
    return(ret);
8587
0
}
8588
8589
/**
8590
 * xmlXPathIdFunction:
8591
 * @ctxt:  the XPath Parser context
8592
 * @nargs:  the number of arguments
8593
 *
8594
 * Implement the id() XPath function
8595
 *    node-set id(object)
8596
 * The id function selects elements by their unique ID
8597
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8598
 * then the result is the union of the result of applying id to the
8599
 * string value of each of the nodes in the argument node-set. When the
8600
 * argument to id is of any other type, the argument is converted to a
8601
 * string as if by a call to the string function; the string is split
8602
 * into a whitespace-separated list of tokens (whitespace is any sequence
8603
 * of characters matching the production S); the result is a node-set
8604
 * containing the elements in the same document as the context node that
8605
 * have a unique ID equal to any of the tokens in the list.
8606
 */
8607
void
8608
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8609
0
    xmlChar *tokens;
8610
0
    xmlNodeSetPtr ret;
8611
0
    xmlXPathObjectPtr obj;
8612
8613
0
    CHECK_ARITY(1);
8614
0
    obj = valuePop(ctxt);
8615
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8616
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8617
0
  xmlNodeSetPtr ns;
8618
0
  int i;
8619
8620
        /* TODO: Check memory error. */
8621
0
  ret = xmlXPathNodeSetCreate(NULL);
8622
8623
0
  if (obj->nodesetval != NULL) {
8624
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8625
0
    tokens =
8626
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8627
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8628
                /* TODO: Check memory error. */
8629
0
    ret = xmlXPathNodeSetMerge(ret, ns);
8630
0
    xmlXPathFreeNodeSet(ns);
8631
0
    if (tokens != NULL)
8632
0
        xmlFree(tokens);
8633
0
      }
8634
0
  }
8635
0
  xmlXPathReleaseObject(ctxt->context, obj);
8636
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8637
0
  return;
8638
0
    }
8639
0
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8640
0
    if (obj == NULL) return;
8641
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8642
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8643
0
    xmlXPathReleaseObject(ctxt->context, obj);
8644
0
    return;
8645
0
}
8646
8647
/**
8648
 * xmlXPathLocalNameFunction:
8649
 * @ctxt:  the XPath Parser context
8650
 * @nargs:  the number of arguments
8651
 *
8652
 * Implement the local-name() XPath function
8653
 *    string local-name(node-set?)
8654
 * The local-name function returns a string containing the local part
8655
 * of the name of the node in the argument node-set that is first in
8656
 * document order. If the node-set is empty or the first node has no
8657
 * name, an empty string is returned. If the argument is omitted it
8658
 * defaults to the context node.
8659
 */
8660
void
8661
330
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8662
330
    xmlXPathObjectPtr cur;
8663
8664
330
    if (ctxt == NULL) return;
8665
8666
330
    if (nargs == 0) {
8667
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8668
0
      ctxt->context->node));
8669
0
  nargs = 1;
8670
0
    }
8671
8672
990
    CHECK_ARITY(1);
8673
990
    if ((ctxt->value == NULL) ||
8674
330
  ((ctxt->value->type != XPATH_NODESET) &&
8675
330
   (ctxt->value->type != XPATH_XSLT_TREE)))
8676
330
  XP_ERROR(XPATH_INVALID_TYPE);
8677
330
    cur = valuePop(ctxt);
8678
8679
330
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8680
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8681
330
    } else {
8682
330
  int i = 0; /* Should be first in document order !!!!! */
8683
330
  switch (cur->nodesetval->nodeTab[i]->type) {
8684
0
  case XML_ELEMENT_NODE:
8685
0
  case XML_ATTRIBUTE_NODE:
8686
0
  case XML_PI_NODE:
8687
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8688
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8689
0
      else
8690
0
    valuePush(ctxt,
8691
0
          xmlXPathCacheNewString(ctxt->context,
8692
0
      cur->nodesetval->nodeTab[i]->name));
8693
0
      break;
8694
0
  case XML_NAMESPACE_DECL:
8695
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8696
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8697
0
      break;
8698
330
  default:
8699
330
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8700
330
  }
8701
330
    }
8702
330
    xmlXPathReleaseObject(ctxt->context, cur);
8703
330
}
8704
8705
/**
8706
 * xmlXPathNamespaceURIFunction:
8707
 * @ctxt:  the XPath Parser context
8708
 * @nargs:  the number of arguments
8709
 *
8710
 * Implement the namespace-uri() XPath function
8711
 *    string namespace-uri(node-set?)
8712
 * The namespace-uri function returns a string containing the
8713
 * namespace URI of the expanded name of the node in the argument
8714
 * node-set that is first in document order. If the node-set is empty,
8715
 * the first node has no name, or the expanded name has no namespace
8716
 * URI, an empty string is returned. If the argument is omitted it
8717
 * defaults to the context node.
8718
 */
8719
void
8720
1
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8721
1
    xmlXPathObjectPtr cur;
8722
8723
1
    if (ctxt == NULL) return;
8724
8725
1
    if (nargs == 0) {
8726
1
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8727
1
      ctxt->context->node));
8728
1
  nargs = 1;
8729
1
    }
8730
3
    CHECK_ARITY(1);
8731
3
    if ((ctxt->value == NULL) ||
8732
1
  ((ctxt->value->type != XPATH_NODESET) &&
8733
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
8734
1
  XP_ERROR(XPATH_INVALID_TYPE);
8735
1
    cur = valuePop(ctxt);
8736
8737
1
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8738
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8739
1
    } else {
8740
1
  int i = 0; /* Should be first in document order !!!!! */
8741
1
  switch (cur->nodesetval->nodeTab[i]->type) {
8742
0
  case XML_ELEMENT_NODE:
8743
0
  case XML_ATTRIBUTE_NODE:
8744
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8745
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8746
0
      else
8747
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8748
0
        cur->nodesetval->nodeTab[i]->ns->href));
8749
0
      break;
8750
1
  default:
8751
1
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8752
1
  }
8753
1
    }
8754
1
    xmlXPathReleaseObject(ctxt->context, cur);
8755
1
}
8756
8757
/**
8758
 * xmlXPathNameFunction:
8759
 * @ctxt:  the XPath Parser context
8760
 * @nargs:  the number of arguments
8761
 *
8762
 * Implement the name() XPath function
8763
 *    string name(node-set?)
8764
 * The name function returns a string containing a QName representing
8765
 * the name of the node in the argument node-set that is first in document
8766
 * order. The QName must represent the name with respect to the namespace
8767
 * declarations in effect on the node whose name is being represented.
8768
 * Typically, this will be the form in which the name occurred in the XML
8769
 * source. This need not be the case if there are namespace declarations
8770
 * in effect on the node that associate multiple prefixes with the same
8771
 * namespace. However, an implementation may include information about
8772
 * the original prefix in its representation of nodes; in this case, an
8773
 * implementation can ensure that the returned string is always the same
8774
 * as the QName used in the XML source. If the argument it omitted it
8775
 * defaults to the context node.
8776
 * Libxml keep the original prefix so the "real qualified name" used is
8777
 * returned.
8778
 */
8779
static void
8780
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8781
352
{
8782
352
    xmlXPathObjectPtr cur;
8783
8784
352
    if (nargs == 0) {
8785
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8786
0
      ctxt->context->node));
8787
0
        nargs = 1;
8788
0
    }
8789
8790
1.05k
    CHECK_ARITY(1);
8791
1.05k
    if ((ctxt->value == NULL) ||
8792
352
        ((ctxt->value->type != XPATH_NODESET) &&
8793
352
         (ctxt->value->type != XPATH_XSLT_TREE)))
8794
352
        XP_ERROR(XPATH_INVALID_TYPE);
8795
352
    cur = valuePop(ctxt);
8796
8797
352
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8798
22
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799
330
    } else {
8800
330
        int i = 0;              /* Should be first in document order !!!!! */
8801
8802
330
        switch (cur->nodesetval->nodeTab[i]->type) {
8803
0
            case XML_ELEMENT_NODE:
8804
0
            case XML_ATTRIBUTE_NODE:
8805
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8806
0
        valuePush(ctxt,
8807
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8808
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8809
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8810
0
        valuePush(ctxt,
8811
0
            xmlXPathCacheNewString(ctxt->context,
8812
0
          cur->nodesetval->nodeTab[i]->name));
8813
0
    } else {
8814
0
        xmlChar *fullname;
8815
8816
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8817
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8818
0
             NULL, 0);
8819
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8820
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8821
0
        if (fullname == NULL)
8822
0
                        xmlXPathPErrMemory(ctxt, NULL);
8823
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8824
0
      ctxt->context, fullname));
8825
0
                }
8826
0
                break;
8827
330
            default:
8828
330
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8829
330
        cur->nodesetval->nodeTab[i]));
8830
330
                xmlXPathLocalNameFunction(ctxt, 1);
8831
330
        }
8832
330
    }
8833
352
    xmlXPathReleaseObject(ctxt->context, cur);
8834
352
}
8835
8836
8837
/**
8838
 * xmlXPathStringFunction:
8839
 * @ctxt:  the XPath Parser context
8840
 * @nargs:  the number of arguments
8841
 *
8842
 * Implement the string() XPath function
8843
 *    string string(object?)
8844
 * The string function converts an object to a string as follows:
8845
 *    - A node-set is converted to a string by returning the value of
8846
 *      the node in the node-set that is first in document order.
8847
 *      If the node-set is empty, an empty string is returned.
8848
 *    - A number is converted to a string as follows
8849
 *      + NaN is converted to the string NaN
8850
 *      + positive zero is converted to the string 0
8851
 *      + negative zero is converted to the string 0
8852
 *      + positive infinity is converted to the string Infinity
8853
 *      + negative infinity is converted to the string -Infinity
8854
 *      + if the number is an integer, the number is represented in
8855
 *        decimal form as a Number with no decimal point and no leading
8856
 *        zeros, preceded by a minus sign (-) if the number is negative
8857
 *      + otherwise, the number is represented in decimal form as a
8858
 *        Number including a decimal point with at least one digit
8859
 *        before the decimal point and at least one digit after the
8860
 *        decimal point, preceded by a minus sign (-) if the number
8861
 *        is negative; there must be no leading zeros before the decimal
8862
 *        point apart possibly from the one required digit immediately
8863
 *        before the decimal point; beyond the one required digit
8864
 *        after the decimal point there must be as many, but only as
8865
 *        many, more digits as are needed to uniquely distinguish the
8866
 *        number from all other IEEE 754 numeric values.
8867
 *    - The boolean false value is converted to the string false.
8868
 *      The boolean true value is converted to the string true.
8869
 *
8870
 * If the argument is omitted, it defaults to a node-set with the
8871
 * context node as its only member.
8872
 */
8873
void
8874
66.3k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8875
66.3k
    xmlXPathObjectPtr cur;
8876
8877
66.3k
    if (ctxt == NULL) return;
8878
66.3k
    if (nargs == 0) {
8879
1
    valuePush(ctxt,
8880
1
  xmlXPathCacheWrapString(ctxt->context,
8881
1
      xmlXPathCastNodeToString(ctxt->context->node)));
8882
1
  return;
8883
1
    }
8884
8885
265k
    CHECK_ARITY(1);
8886
265k
    cur = valuePop(ctxt);
8887
265k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8888
66.3k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8889
66.3k
}
8890
8891
/**
8892
 * xmlXPathStringLengthFunction:
8893
 * @ctxt:  the XPath Parser context
8894
 * @nargs:  the number of arguments
8895
 *
8896
 * Implement the string-length() XPath function
8897
 *    number string-length(string?)
8898
 * The string-length returns the number of characters in the string
8899
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8900
 * the context node converted to a string, in other words the value
8901
 * of the context node.
8902
 */
8903
void
8904
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905
0
    xmlXPathObjectPtr cur;
8906
8907
0
    if (nargs == 0) {
8908
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8909
0
      return;
8910
0
  if (ctxt->context->node == NULL) {
8911
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8912
0
  } else {
8913
0
      xmlChar *content;
8914
8915
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8916
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8917
0
    xmlUTF8Strlen(content)));
8918
0
      xmlFree(content);
8919
0
  }
8920
0
  return;
8921
0
    }
8922
0
    CHECK_ARITY(1);
8923
0
    CAST_TO_STRING;
8924
0
    CHECK_TYPE(XPATH_STRING);
8925
0
    cur = valuePop(ctxt);
8926
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8927
0
  xmlUTF8Strlen(cur->stringval)));
8928
0
    xmlXPathReleaseObject(ctxt->context, cur);
8929
0
}
8930
8931
/**
8932
 * xmlXPathConcatFunction:
8933
 * @ctxt:  the XPath Parser context
8934
 * @nargs:  the number of arguments
8935
 *
8936
 * Implement the concat() XPath function
8937
 *    string concat(string, string, string*)
8938
 * The concat function returns the concatenation of its arguments.
8939
 */
8940
void
8941
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8942
0
    xmlXPathObjectPtr cur, newobj;
8943
0
    xmlChar *tmp;
8944
8945
0
    if (ctxt == NULL) return;
8946
0
    if (nargs < 2) {
8947
0
  CHECK_ARITY(2);
8948
0
    }
8949
8950
0
    CAST_TO_STRING;
8951
0
    cur = valuePop(ctxt);
8952
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8953
0
  xmlXPathReleaseObject(ctxt->context, cur);
8954
0
  return;
8955
0
    }
8956
0
    nargs--;
8957
8958
0
    while (nargs > 0) {
8959
0
  CAST_TO_STRING;
8960
0
  newobj = valuePop(ctxt);
8961
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8962
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8963
0
      xmlXPathReleaseObject(ctxt->context, cur);
8964
0
      XP_ERROR(XPATH_INVALID_TYPE);
8965
0
  }
8966
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8967
0
  newobj->stringval = cur->stringval;
8968
0
  cur->stringval = tmp;
8969
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8970
0
  nargs--;
8971
0
    }
8972
0
    valuePush(ctxt, cur);
8973
0
}
8974
8975
/**
8976
 * xmlXPathContainsFunction:
8977
 * @ctxt:  the XPath Parser context
8978
 * @nargs:  the number of arguments
8979
 *
8980
 * Implement the contains() XPath function
8981
 *    boolean contains(string, string)
8982
 * The contains function returns true if the first argument string
8983
 * contains the second argument string, and otherwise returns false.
8984
 */
8985
void
8986
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8987
0
    xmlXPathObjectPtr hay, needle;
8988
8989
0
    CHECK_ARITY(2);
8990
0
    CAST_TO_STRING;
8991
0
    CHECK_TYPE(XPATH_STRING);
8992
0
    needle = valuePop(ctxt);
8993
0
    CAST_TO_STRING;
8994
0
    hay = valuePop(ctxt);
8995
8996
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8997
0
  xmlXPathReleaseObject(ctxt->context, hay);
8998
0
  xmlXPathReleaseObject(ctxt->context, needle);
8999
0
  XP_ERROR(XPATH_INVALID_TYPE);
9000
0
    }
9001
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9002
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9003
0
    else
9004
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9005
0
    xmlXPathReleaseObject(ctxt->context, hay);
9006
0
    xmlXPathReleaseObject(ctxt->context, needle);
9007
0
}
9008
9009
/**
9010
 * xmlXPathStartsWithFunction:
9011
 * @ctxt:  the XPath Parser context
9012
 * @nargs:  the number of arguments
9013
 *
9014
 * Implement the starts-with() XPath function
9015
 *    boolean starts-with(string, string)
9016
 * The starts-with function returns true if the first argument string
9017
 * starts with the second argument string, and otherwise returns false.
9018
 */
9019
void
9020
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9021
0
    xmlXPathObjectPtr hay, needle;
9022
0
    int n;
9023
9024
0
    CHECK_ARITY(2);
9025
0
    CAST_TO_STRING;
9026
0
    CHECK_TYPE(XPATH_STRING);
9027
0
    needle = valuePop(ctxt);
9028
0
    CAST_TO_STRING;
9029
0
    hay = valuePop(ctxt);
9030
9031
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9032
0
  xmlXPathReleaseObject(ctxt->context, hay);
9033
0
  xmlXPathReleaseObject(ctxt->context, needle);
9034
0
  XP_ERROR(XPATH_INVALID_TYPE);
9035
0
    }
9036
0
    n = xmlStrlen(needle->stringval);
9037
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9038
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9039
0
    else
9040
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9041
0
    xmlXPathReleaseObject(ctxt->context, hay);
9042
0
    xmlXPathReleaseObject(ctxt->context, needle);
9043
0
}
9044
9045
/**
9046
 * xmlXPathSubstringFunction:
9047
 * @ctxt:  the XPath Parser context
9048
 * @nargs:  the number of arguments
9049
 *
9050
 * Implement the substring() XPath function
9051
 *    string substring(string, number, number?)
9052
 * The substring function returns the substring of the first argument
9053
 * starting at the position specified in the second argument with
9054
 * length specified in the third argument. For example,
9055
 * substring("12345",2,3) returns "234". If the third argument is not
9056
 * specified, it returns the substring starting at the position specified
9057
 * in the second argument and continuing to the end of the string. For
9058
 * example, substring("12345",2) returns "2345".  More precisely, each
9059
 * character in the string (see [3.6 Strings]) is considered to have a
9060
 * numeric position: the position of the first character is 1, the position
9061
 * of the second character is 2 and so on. The returned substring contains
9062
 * those characters for which the position of the character is greater than
9063
 * or equal to the second argument and, if the third argument is specified,
9064
 * less than the sum of the second and third arguments; the comparisons
9065
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9066
 *  - substring("12345", 1.5, 2.6) returns "234"
9067
 *  - substring("12345", 0, 3) returns "12"
9068
 *  - substring("12345", 0 div 0, 3) returns ""
9069
 *  - substring("12345", 1, 0 div 0) returns ""
9070
 *  - substring("12345", -42, 1 div 0) returns "12345"
9071
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9072
 */
9073
void
9074
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9075
0
    xmlXPathObjectPtr str, start, len;
9076
0
    double le=0, in;
9077
0
    int i = 1, j = INT_MAX;
9078
9079
0
    if (nargs < 2) {
9080
0
  CHECK_ARITY(2);
9081
0
    }
9082
0
    if (nargs > 3) {
9083
0
  CHECK_ARITY(3);
9084
0
    }
9085
    /*
9086
     * take care of possible last (position) argument
9087
    */
9088
0
    if (nargs == 3) {
9089
0
  CAST_TO_NUMBER;
9090
0
  CHECK_TYPE(XPATH_NUMBER);
9091
0
  len = valuePop(ctxt);
9092
0
  le = len->floatval;
9093
0
  xmlXPathReleaseObject(ctxt->context, len);
9094
0
    }
9095
9096
0
    CAST_TO_NUMBER;
9097
0
    CHECK_TYPE(XPATH_NUMBER);
9098
0
    start = valuePop(ctxt);
9099
0
    in = start->floatval;
9100
0
    xmlXPathReleaseObject(ctxt->context, start);
9101
0
    CAST_TO_STRING;
9102
0
    CHECK_TYPE(XPATH_STRING);
9103
0
    str = valuePop(ctxt);
9104
9105
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9106
0
        i = INT_MAX;
9107
0
    } else if (in >= 1.0) {
9108
0
        i = (int)in;
9109
0
        if (in - floor(in) >= 0.5)
9110
0
            i += 1;
9111
0
    }
9112
9113
0
    if (nargs == 3) {
9114
0
        double rin, rle, end;
9115
9116
0
        rin = floor(in);
9117
0
        if (in - rin >= 0.5)
9118
0
            rin += 1.0;
9119
9120
0
        rle = floor(le);
9121
0
        if (le - rle >= 0.5)
9122
0
            rle += 1.0;
9123
9124
0
        end = rin + rle;
9125
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9126
0
            j = 1;
9127
0
        } else if (end < INT_MAX) {
9128
0
            j = (int)end;
9129
0
        }
9130
0
    }
9131
9132
0
    if (i < j) {
9133
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9134
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9135
0
  xmlFree(ret);
9136
0
    } else {
9137
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9138
0
    }
9139
9140
0
    xmlXPathReleaseObject(ctxt->context, str);
9141
0
}
9142
9143
/**
9144
 * xmlXPathSubstringBeforeFunction:
9145
 * @ctxt:  the XPath Parser context
9146
 * @nargs:  the number of arguments
9147
 *
9148
 * Implement the substring-before() XPath function
9149
 *    string substring-before(string, string)
9150
 * The substring-before function returns the substring of the first
9151
 * argument string that precedes the first occurrence of the second
9152
 * argument string in the first argument string, or the empty string
9153
 * if the first argument string does not contain the second argument
9154
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9155
 */
9156
void
9157
12
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9158
12
  xmlXPathObjectPtr str;
9159
12
  xmlXPathObjectPtr find;
9160
12
  xmlBufPtr target;
9161
12
  const xmlChar *point;
9162
12
  int offset;
9163
9164
36
  CHECK_ARITY(2);
9165
36
  CAST_TO_STRING;
9166
36
  find = valuePop(ctxt);
9167
36
  CAST_TO_STRING;
9168
36
  str = valuePop(ctxt);
9169
9170
36
  target = xmlBufCreate();
9171
36
  if (target) {
9172
12
    point = xmlStrstr(str->stringval, find->stringval);
9173
12
    if (point) {
9174
12
      offset = point - str->stringval;
9175
12
      xmlBufAdd(target, str->stringval, offset);
9176
12
    }
9177
12
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9178
12
  xmlBufContent(target)));
9179
12
    xmlBufFree(target);
9180
12
  }
9181
36
  xmlXPathReleaseObject(ctxt->context, str);
9182
36
  xmlXPathReleaseObject(ctxt->context, find);
9183
36
}
9184
9185
/**
9186
 * xmlXPathSubstringAfterFunction:
9187
 * @ctxt:  the XPath Parser context
9188
 * @nargs:  the number of arguments
9189
 *
9190
 * Implement the substring-after() XPath function
9191
 *    string substring-after(string, string)
9192
 * The substring-after function returns the substring of the first
9193
 * argument string that follows the first occurrence of the second
9194
 * argument string in the first argument string, or the empty stringi
9195
 * if the first argument string does not contain the second argument
9196
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9197
 * and substring-after("1999/04/01","19") returns 99/04/01.
9198
 */
9199
void
9200
1.48k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9201
1.48k
  xmlXPathObjectPtr str;
9202
1.48k
  xmlXPathObjectPtr find;
9203
1.48k
  xmlBufPtr target;
9204
1.48k
  const xmlChar *point;
9205
1.48k
  int offset;
9206
9207
4.45k
  CHECK_ARITY(2);
9208
4.45k
  CAST_TO_STRING;
9209
4.45k
  find = valuePop(ctxt);
9210
4.45k
  CAST_TO_STRING;
9211
4.45k
  str = valuePop(ctxt);
9212
9213
4.45k
  target = xmlBufCreate();
9214
4.45k
  if (target) {
9215
1.48k
    point = xmlStrstr(str->stringval, find->stringval);
9216
1.48k
    if (point) {
9217
0
      offset = point - str->stringval + xmlStrlen(find->stringval);
9218
0
      xmlBufAdd(target, &str->stringval[offset],
9219
0
       xmlStrlen(str->stringval) - offset);
9220
0
    }
9221
1.48k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9222
1.48k
  xmlBufContent(target)));
9223
1.48k
    xmlBufFree(target);
9224
1.48k
  }
9225
4.45k
  xmlXPathReleaseObject(ctxt->context, str);
9226
4.45k
  xmlXPathReleaseObject(ctxt->context, find);
9227
4.45k
}
9228
9229
/**
9230
 * xmlXPathNormalizeFunction:
9231
 * @ctxt:  the XPath Parser context
9232
 * @nargs:  the number of arguments
9233
 *
9234
 * Implement the normalize-space() XPath function
9235
 *    string normalize-space(string?)
9236
 * The normalize-space function returns the argument string with white
9237
 * space normalized by stripping leading and trailing whitespace
9238
 * and replacing sequences of whitespace characters by a single
9239
 * space. Whitespace characters are the same allowed by the S production
9240
 * in XML. If the argument is omitted, it defaults to the context
9241
 * node converted to a string, in other words the value of the context node.
9242
 */
9243
void
9244
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245
0
    xmlChar *source, *target;
9246
0
    int blank;
9247
9248
0
    if (ctxt == NULL) return;
9249
0
    if (nargs == 0) {
9250
        /* Use current context node */
9251
0
        valuePush(ctxt,
9252
0
            xmlXPathCacheWrapString(ctxt->context,
9253
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9254
0
        nargs = 1;
9255
0
    }
9256
9257
0
    CHECK_ARITY(1);
9258
0
    CAST_TO_STRING;
9259
0
    CHECK_TYPE(XPATH_STRING);
9260
0
    source = ctxt->value->stringval;
9261
0
    if (source == NULL)
9262
0
        return;
9263
0
    target = source;
9264
9265
    /* Skip leading whitespaces */
9266
0
    while (IS_BLANK_CH(*source))
9267
0
        source++;
9268
9269
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9270
0
    blank = 0;
9271
0
    while (*source) {
9272
0
        if (IS_BLANK_CH(*source)) {
9273
0
      blank = 1;
9274
0
        } else {
9275
0
            if (blank) {
9276
0
                *target++ = 0x20;
9277
0
                blank = 0;
9278
0
            }
9279
0
            *target++ = *source;
9280
0
        }
9281
0
        source++;
9282
0
    }
9283
0
    *target = 0;
9284
0
}
9285
9286
/**
9287
 * xmlXPathTranslateFunction:
9288
 * @ctxt:  the XPath Parser context
9289
 * @nargs:  the number of arguments
9290
 *
9291
 * Implement the translate() XPath function
9292
 *    string translate(string, string, string)
9293
 * The translate function returns the first argument string with
9294
 * occurrences of characters in the second argument string replaced
9295
 * by the character at the corresponding position in the third argument
9296
 * string. For example, translate("bar","abc","ABC") returns the string
9297
 * BAr. If there is a character in the second argument string with no
9298
 * character at a corresponding position in the third argument string
9299
 * (because the second argument string is longer than the third argument
9300
 * string), then occurrences of that character in the first argument
9301
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9302
 * returns "AAA". If a character occurs more than once in second
9303
 * argument string, then the first occurrence determines the replacement
9304
 * character. If the third argument string is longer than the second
9305
 * argument string, then excess characters are ignored.
9306
 */
9307
void
9308
46
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9309
46
    xmlXPathObjectPtr str;
9310
46
    xmlXPathObjectPtr from;
9311
46
    xmlXPathObjectPtr to;
9312
46
    xmlBufPtr target;
9313
46
    int offset, max;
9314
46
    int ch;
9315
46
    const xmlChar *point;
9316
46
    xmlChar *cptr;
9317
9318
138
    CHECK_ARITY(3);
9319
9320
138
    CAST_TO_STRING;
9321
138
    to = valuePop(ctxt);
9322
138
    CAST_TO_STRING;
9323
138
    from = valuePop(ctxt);
9324
138
    CAST_TO_STRING;
9325
138
    str = valuePop(ctxt);
9326
9327
138
    target = xmlBufCreate();
9328
138
    if (target) {
9329
46
  max = xmlUTF8Strlen(to->stringval);
9330
1.42M
  for (cptr = str->stringval; (ch=*cptr); ) {
9331
1.42M
      offset = xmlUTF8Strloc(from->stringval, cptr);
9332
1.42M
      if (offset >= 0) {
9333
600
    if (offset < max) {
9334
0
        point = xmlUTF8Strpos(to->stringval, offset);
9335
0
        if (point)
9336
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9337
0
    }
9338
600
      } else
9339
1.42M
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9340
9341
      /* Step to next character in input */
9342
1.42M
      cptr++;
9343
1.42M
      if ( ch & 0x80 ) {
9344
    /* if not simple ascii, verify proper format */
9345
620k
    if ( (ch & 0xc0) != 0xc0 ) {
9346
14
        xmlGenericError(xmlGenericErrorContext,
9347
14
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9348
                    /* not asserting an XPath error is probably better */
9349
14
        break;
9350
14
    }
9351
    /* then skip over remaining bytes for this char */
9352
1.86M
    while ( (ch <<= 1) & 0x80 )
9353
1.23M
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9354
0
      xmlGenericError(xmlGenericErrorContext,
9355
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9356
                        /* not asserting an XPath error is probably better */
9357
0
      break;
9358
0
        }
9359
620k
    if (ch & 0x80) /* must have had error encountered */
9360
0
        break;
9361
620k
      }
9362
1.42M
  }
9363
46
    }
9364
138
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9365
138
  xmlBufContent(target)));
9366
138
    xmlBufFree(target);
9367
138
    xmlXPathReleaseObject(ctxt->context, str);
9368
138
    xmlXPathReleaseObject(ctxt->context, from);
9369
138
    xmlXPathReleaseObject(ctxt->context, to);
9370
138
}
9371
9372
/**
9373
 * xmlXPathBooleanFunction:
9374
 * @ctxt:  the XPath Parser context
9375
 * @nargs:  the number of arguments
9376
 *
9377
 * Implement the boolean() XPath function
9378
 *    boolean boolean(object)
9379
 * The boolean function converts its argument to a boolean as follows:
9380
 *    - a number is true if and only if it is neither positive or
9381
 *      negative zero nor NaN
9382
 *    - a node-set is true if and only if it is non-empty
9383
 *    - a string is true if and only if its length is non-zero
9384
 */
9385
void
9386
3.26k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9387
3.26k
    xmlXPathObjectPtr cur;
9388
9389
9.78k
    CHECK_ARITY(1);
9390
9.78k
    cur = valuePop(ctxt);
9391
9.78k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9392
3.26k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9393
3.26k
    valuePush(ctxt, cur);
9394
3.26k
}
9395
9396
/**
9397
 * xmlXPathNotFunction:
9398
 * @ctxt:  the XPath Parser context
9399
 * @nargs:  the number of arguments
9400
 *
9401
 * Implement the not() XPath function
9402
 *    boolean not(boolean)
9403
 * The not function returns true if its argument is false,
9404
 * and false otherwise.
9405
 */
9406
void
9407
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9408
0
    CHECK_ARITY(1);
9409
0
    CAST_TO_BOOLEAN;
9410
0
    CHECK_TYPE(XPATH_BOOLEAN);
9411
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9412
0
}
9413
9414
/**
9415
 * xmlXPathTrueFunction:
9416
 * @ctxt:  the XPath Parser context
9417
 * @nargs:  the number of arguments
9418
 *
9419
 * Implement the true() XPath function
9420
 *    boolean true()
9421
 */
9422
void
9423
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9424
0
    CHECK_ARITY(0);
9425
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9426
0
}
9427
9428
/**
9429
 * xmlXPathFalseFunction:
9430
 * @ctxt:  the XPath Parser context
9431
 * @nargs:  the number of arguments
9432
 *
9433
 * Implement the false() XPath function
9434
 *    boolean false()
9435
 */
9436
void
9437
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438
0
    CHECK_ARITY(0);
9439
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9440
0
}
9441
9442
/**
9443
 * xmlXPathLangFunction:
9444
 * @ctxt:  the XPath Parser context
9445
 * @nargs:  the number of arguments
9446
 *
9447
 * Implement the lang() XPath function
9448
 *    boolean lang(string)
9449
 * The lang function returns true or false depending on whether the
9450
 * language of the context node as specified by xml:lang attributes
9451
 * is the same as or is a sublanguage of the language specified by
9452
 * the argument string. The language of the context node is determined
9453
 * by the value of the xml:lang attribute on the context node, or, if
9454
 * the context node has no xml:lang attribute, by the value of the
9455
 * xml:lang attribute on the nearest ancestor of the context node that
9456
 * has an xml:lang attribute. If there is no such attribute, then lang
9457
 * returns false. If there is such an attribute, then lang returns
9458
 * true if the attribute value is equal to the argument ignoring case,
9459
 * or if there is some suffix starting with - such that the attribute
9460
 * value is equal to the argument ignoring that suffix of the attribute
9461
 * value and ignoring case.
9462
 */
9463
void
9464
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9465
0
    xmlXPathObjectPtr val = NULL;
9466
0
    const xmlChar *theLang = NULL;
9467
0
    const xmlChar *lang;
9468
0
    int ret = 0;
9469
0
    int i;
9470
9471
0
    CHECK_ARITY(1);
9472
0
    CAST_TO_STRING;
9473
0
    CHECK_TYPE(XPATH_STRING);
9474
0
    val = valuePop(ctxt);
9475
0
    lang = val->stringval;
9476
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9477
0
    if ((theLang != NULL) && (lang != NULL)) {
9478
0
        for (i = 0;lang[i] != 0;i++)
9479
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9480
0
          goto not_equal;
9481
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9482
0
      ret = 1;
9483
0
    }
9484
0
not_equal:
9485
0
    if (theLang != NULL)
9486
0
  xmlFree((void *)theLang);
9487
9488
0
    xmlXPathReleaseObject(ctxt->context, val);
9489
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9490
0
}
9491
9492
/**
9493
 * xmlXPathNumberFunction:
9494
 * @ctxt:  the XPath Parser context
9495
 * @nargs:  the number of arguments
9496
 *
9497
 * Implement the number() XPath function
9498
 *    number number(object?)
9499
 */
9500
void
9501
2.04M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9502
2.04M
    xmlXPathObjectPtr cur;
9503
2.04M
    double res;
9504
9505
2.04M
    if (ctxt == NULL) return;
9506
2.04M
    if (nargs == 0) {
9507
0
  if (ctxt->context->node == NULL) {
9508
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9509
0
  } else {
9510
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9511
9512
0
      res = xmlXPathStringEvalNumber(content);
9513
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9514
0
      xmlFree(content);
9515
0
  }
9516
0
  return;
9517
0
    }
9518
9519
8.18M
    CHECK_ARITY(1);
9520
8.18M
    cur = valuePop(ctxt);
9521
8.18M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9522
8.18M
}
9523
9524
/**
9525
 * xmlXPathSumFunction:
9526
 * @ctxt:  the XPath Parser context
9527
 * @nargs:  the number of arguments
9528
 *
9529
 * Implement the sum() XPath function
9530
 *    number sum(node-set)
9531
 * The sum function returns the sum of the values of the nodes in
9532
 * the argument node-set.
9533
 */
9534
void
9535
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9536
0
    xmlXPathObjectPtr cur;
9537
0
    int i;
9538
0
    double res = 0.0;
9539
9540
0
    CHECK_ARITY(1);
9541
0
    if ((ctxt->value == NULL) ||
9542
0
  ((ctxt->value->type != XPATH_NODESET) &&
9543
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
9544
0
  XP_ERROR(XPATH_INVALID_TYPE);
9545
0
    cur = valuePop(ctxt);
9546
9547
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9548
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9549
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9550
0
  }
9551
0
    }
9552
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9553
0
    xmlXPathReleaseObject(ctxt->context, cur);
9554
0
}
9555
9556
/**
9557
 * xmlXPathFloorFunction:
9558
 * @ctxt:  the XPath Parser context
9559
 * @nargs:  the number of arguments
9560
 *
9561
 * Implement the floor() XPath function
9562
 *    number floor(number)
9563
 * The floor function returns the largest (closest to positive infinity)
9564
 * number that is not greater than the argument and that is an integer.
9565
 */
9566
void
9567
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9568
0
    CHECK_ARITY(1);
9569
0
    CAST_TO_NUMBER;
9570
0
    CHECK_TYPE(XPATH_NUMBER);
9571
9572
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9573
0
}
9574
9575
/**
9576
 * xmlXPathCeilingFunction:
9577
 * @ctxt:  the XPath Parser context
9578
 * @nargs:  the number of arguments
9579
 *
9580
 * Implement the ceiling() XPath function
9581
 *    number ceiling(number)
9582
 * The ceiling function returns the smallest (closest to negative infinity)
9583
 * number that is not less than the argument and that is an integer.
9584
 */
9585
void
9586
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9587
0
    CHECK_ARITY(1);
9588
0
    CAST_TO_NUMBER;
9589
0
    CHECK_TYPE(XPATH_NUMBER);
9590
9591
#ifdef _AIX
9592
    /* Work around buggy ceil() function on AIX */
9593
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9594
#else
9595
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9596
0
#endif
9597
0
}
9598
9599
/**
9600
 * xmlXPathRoundFunction:
9601
 * @ctxt:  the XPath Parser context
9602
 * @nargs:  the number of arguments
9603
 *
9604
 * Implement the round() XPath function
9605
 *    number round(number)
9606
 * The round function returns the number that is closest to the
9607
 * argument and that is an integer. If there are two such numbers,
9608
 * then the one that is closest to positive infinity is returned.
9609
 */
9610
void
9611
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612
0
    double f;
9613
9614
0
    CHECK_ARITY(1);
9615
0
    CAST_TO_NUMBER;
9616
0
    CHECK_TYPE(XPATH_NUMBER);
9617
9618
0
    f = ctxt->value->floatval;
9619
9620
0
    if ((f >= -0.5) && (f < 0.5)) {
9621
        /* Handles negative zero. */
9622
0
        ctxt->value->floatval *= 0.0;
9623
0
    }
9624
0
    else {
9625
0
        double rounded = floor(f);
9626
0
        if (f - rounded >= 0.5)
9627
0
            rounded += 1.0;
9628
0
        ctxt->value->floatval = rounded;
9629
0
    }
9630
0
}
9631
9632
/************************************************************************
9633
 *                  *
9634
 *      The Parser          *
9635
 *                  *
9636
 ************************************************************************/
9637
9638
/*
9639
 * a few forward declarations since we use a recursive call based
9640
 * implementation.
9641
 */
9642
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9643
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9644
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9645
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9646
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9647
                                    int qualified);
9648
9649
/**
9650
 * xmlXPathCurrentChar:
9651
 * @ctxt:  the XPath parser context
9652
 * @cur:  pointer to the beginning of the char
9653
 * @len:  pointer to the length of the char read
9654
 *
9655
 * The current char value, if using UTF-8 this may actually span multiple
9656
 * bytes in the input buffer.
9657
 *
9658
 * Returns the current char value and its length
9659
 */
9660
9661
static int
9662
25.8M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9663
25.8M
    unsigned char c;
9664
25.8M
    unsigned int val;
9665
25.8M
    const xmlChar *cur;
9666
9667
25.8M
    if (ctxt == NULL)
9668
0
  return(0);
9669
25.8M
    cur = ctxt->cur;
9670
9671
    /*
9672
     * We are supposed to handle UTF8, check it's valid
9673
     * From rfc2044: encoding of the Unicode values on UTF-8:
9674
     *
9675
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9676
     * 0000 0000-0000 007F   0xxxxxxx
9677
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9678
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9679
     *
9680
     * Check for the 0x110000 limit too
9681
     */
9682
25.8M
    c = *cur;
9683
25.8M
    if (c & 0x80) {
9684
4.54k
  if ((cur[1] & 0xc0) != 0x80)
9685
2.56k
      goto encoding_error;
9686
1.97k
  if ((c & 0xe0) == 0xe0) {
9687
9688
6
      if ((cur[2] & 0xc0) != 0x80)
9689
0
    goto encoding_error;
9690
6
      if ((c & 0xf0) == 0xf0) {
9691
1
    if (((c & 0xf8) != 0xf0) ||
9692
1
        ((cur[3] & 0xc0) != 0x80))
9693
0
        goto encoding_error;
9694
    /* 4-byte code */
9695
1
    *len = 4;
9696
1
    val = (cur[0] & 0x7) << 18;
9697
1
    val |= (cur[1] & 0x3f) << 12;
9698
1
    val |= (cur[2] & 0x3f) << 6;
9699
1
    val |= cur[3] & 0x3f;
9700
5
      } else {
9701
        /* 3-byte code */
9702
5
    *len = 3;
9703
5
    val = (cur[0] & 0xf) << 12;
9704
5
    val |= (cur[1] & 0x3f) << 6;
9705
5
    val |= cur[2] & 0x3f;
9706
5
      }
9707
1.97k
  } else {
9708
    /* 2-byte code */
9709
1.97k
      *len = 2;
9710
1.97k
      val = (cur[0] & 0x1f) << 6;
9711
1.97k
      val |= cur[1] & 0x3f;
9712
1.97k
  }
9713
1.97k
  if (!IS_CHAR(val)) {
9714
1
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9715
0
  }
9716
1.97k
  return(val);
9717
25.8M
    } else {
9718
  /* 1-byte code */
9719
25.8M
  *len = 1;
9720
25.8M
  return(*cur);
9721
25.8M
    }
9722
2.56k
encoding_error:
9723
    /*
9724
     * If we detect an UTF8 error that probably means that the
9725
     * input encoding didn't get properly advertised in the
9726
     * declaration header. Report the error and switch the encoding
9727
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9728
     * encoding !)
9729
     */
9730
2.56k
    *len = 0;
9731
2.56k
    XP_ERROR0(XPATH_ENCODING_ERROR);
9732
0
}
9733
9734
/**
9735
 * xmlXPathParseNCName:
9736
 * @ctxt:  the XPath Parser context
9737
 *
9738
 * parse an XML namespace non qualified name.
9739
 *
9740
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9741
 *
9742
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9743
 *                       CombiningChar | Extender
9744
 *
9745
 * Returns the namespace name or NULL
9746
 */
9747
9748
xmlChar *
9749
4.70M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9750
4.70M
    const xmlChar *in;
9751
4.70M
    xmlChar *ret;
9752
4.70M
    int count = 0;
9753
9754
4.70M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9755
    /*
9756
     * Accelerator for simple ASCII names
9757
     */
9758
4.70M
    in = ctxt->cur;
9759
4.70M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9760
4.70M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9761
4.70M
  (*in == '_')) {
9762
4.70M
  in++;
9763
10.7M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9764
10.7M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9765
10.7M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9766
10.7M
         (*in == '_') || (*in == '.') ||
9767
10.7M
         (*in == '-'))
9768
6.01M
      in++;
9769
4.70M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9770
4.70M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9771
4.70M
            (*in == '@') || (*in == '*')) {
9772
494k
      count = in - ctxt->cur;
9773
494k
      if (count == 0)
9774
0
    return(NULL);
9775
494k
      ret = xmlStrndup(ctxt->cur, count);
9776
494k
      ctxt->cur = in;
9777
494k
      return(ret);
9778
494k
  }
9779
4.70M
    }
9780
4.21M
    return(xmlXPathParseNameComplex(ctxt, 0));
9781
4.70M
}
9782
9783
9784
/**
9785
 * xmlXPathParseQName:
9786
 * @ctxt:  the XPath Parser context
9787
 * @prefix:  a xmlChar **
9788
 *
9789
 * parse an XML qualified name
9790
 *
9791
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9792
 *
9793
 * [NS 6] Prefix ::= NCName
9794
 *
9795
 * [NS 7] LocalPart ::= NCName
9796
 *
9797
 * Returns the function returns the local part, and prefix is updated
9798
 *   to get the Prefix if any.
9799
 */
9800
9801
static xmlChar *
9802
629
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9803
629
    xmlChar *ret = NULL;
9804
9805
629
    *prefix = NULL;
9806
629
    ret = xmlXPathParseNCName(ctxt);
9807
629
    if (ret && CUR == ':') {
9808
239
        *prefix = ret;
9809
239
  NEXT;
9810
239
  ret = xmlXPathParseNCName(ctxt);
9811
239
    }
9812
629
    return(ret);
9813
629
}
9814
9815
/**
9816
 * xmlXPathParseName:
9817
 * @ctxt:  the XPath Parser context
9818
 *
9819
 * parse an XML name
9820
 *
9821
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9822
 *                  CombiningChar | Extender
9823
 *
9824
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9825
 *
9826
 * Returns the namespace name or NULL
9827
 */
9828
9829
xmlChar *
9830
6
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9831
6
    const xmlChar *in;
9832
6
    xmlChar *ret;
9833
6
    size_t count = 0;
9834
9835
6
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9836
    /*
9837
     * Accelerator for simple ASCII names
9838
     */
9839
6
    in = ctxt->cur;
9840
6
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9841
6
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9842
6
  (*in == '_') || (*in == ':')) {
9843
6
  in++;
9844
410k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9845
410k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9846
410k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9847
410k
         (*in == '_') || (*in == '-') ||
9848
410k
         (*in == ':') || (*in == '.'))
9849
410k
      in++;
9850
6
  if ((*in > 0) && (*in < 0x80)) {
9851
6
      count = in - ctxt->cur;
9852
6
            if (count > XML_MAX_NAME_LENGTH) {
9853
3
                ctxt->cur = in;
9854
3
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9855
0
            }
9856
3
      ret = xmlStrndup(ctxt->cur, count);
9857
3
      ctxt->cur = in;
9858
3
      return(ret);
9859
6
  }
9860
6
    }
9861
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9862
6
}
9863
9864
static xmlChar *
9865
4.21M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9866
4.21M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9867
4.21M
    int len = 0, l;
9868
4.21M
    int c;
9869
9870
    /*
9871
     * Handler for more complex cases
9872
     */
9873
4.21M
    c = CUR_CHAR(l);
9874
4.21M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9875
4.21M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9876
4.21M
        (c == '*') || /* accelerators */
9877
4.21M
  (!IS_LETTER(c) && (c != '_') &&
9878
4.21M
         ((!qualified) || (c != ':')))) {
9879
382
  return(NULL);
9880
382
    }
9881
9882
8.44M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9883
8.44M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9884
8.44M
            (c == '.') || (c == '-') ||
9885
8.44M
      (c == '_') || ((qualified) && (c == ':')) ||
9886
8.44M
      (IS_COMBINING(c)) ||
9887
8.44M
      (IS_EXTENDER(c)))) {
9888
4.23M
  COPY_BUF(l,buf,len,c);
9889
4.23M
  NEXTL(l);
9890
4.23M
  c = CUR_CHAR(l);
9891
4.23M
  if (len >= XML_MAX_NAMELEN) {
9892
      /*
9893
       * Okay someone managed to make a huge name, so he's ready to pay
9894
       * for the processing speed.
9895
       */
9896
55
      xmlChar *buffer;
9897
55
      int max = len * 2;
9898
9899
55
            if (len > XML_MAX_NAME_LENGTH) {
9900
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9901
0
            }
9902
55
      buffer = (xmlChar *) xmlMallocAtomic(max);
9903
55
      if (buffer == NULL) {
9904
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9905
0
      }
9906
55
      memcpy(buffer, buf, len);
9907
2.46M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9908
2.46M
       (c == '.') || (c == '-') ||
9909
2.46M
       (c == '_') || ((qualified) && (c == ':')) ||
9910
2.46M
       (IS_COMBINING(c)) ||
9911
2.46M
       (IS_EXTENDER(c))) {
9912
2.46M
    if (len + 10 > max) {
9913
459
                    xmlChar *tmp;
9914
459
                    if (max > XML_MAX_NAME_LENGTH) {
9915
46
                        xmlFree(buffer);
9916
46
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9917
0
                    }
9918
413
        max *= 2;
9919
413
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9920
413
        if (tmp == NULL) {
9921
0
                        xmlFree(buffer);
9922
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9923
0
        }
9924
413
                    buffer = tmp;
9925
413
    }
9926
2.46M
    COPY_BUF(l,buffer,len,c);
9927
2.46M
    NEXTL(l);
9928
2.46M
    c = CUR_CHAR(l);
9929
2.46M
      }
9930
9
      buffer[len] = 0;
9931
9
      return(buffer);
9932
55
  }
9933
4.23M
    }
9934
4.21M
    if (len == 0)
9935
0
  return(NULL);
9936
4.21M
    return(xmlStrndup(buf, len));
9937
4.21M
}
9938
9939
298
#define MAX_FRAC 20
9940
9941
/**
9942
 * xmlXPathStringEvalNumber:
9943
 * @str:  A string to scan
9944
 *
9945
 *  [30a]  Float  ::= Number ('e' Digits?)?
9946
 *
9947
 *  [30]   Number ::=   Digits ('.' Digits?)?
9948
 *                    | '.' Digits
9949
 *  [31]   Digits ::=   [0-9]+
9950
 *
9951
 * Compile a Number in the string
9952
 * In complement of the Number expression, this function also handles
9953
 * negative values : '-' Number.
9954
 *
9955
 * Returns the double value.
9956
 */
9957
double
9958
2.10M
xmlXPathStringEvalNumber(const xmlChar *str) {
9959
2.10M
    const xmlChar *cur = str;
9960
2.10M
    double ret;
9961
2.10M
    int ok = 0;
9962
2.10M
    int isneg = 0;
9963
2.10M
    int exponent = 0;
9964
2.10M
    int is_exponent_negative = 0;
9965
2.10M
#ifdef __GNUC__
9966
2.10M
    unsigned long tmp = 0;
9967
2.10M
    double temp;
9968
2.10M
#endif
9969
2.10M
    if (cur == NULL) return(0);
9970
2.10M
    while (IS_BLANK_CH(*cur)) cur++;
9971
2.10M
    if (*cur == '-') {
9972
48
  isneg = 1;
9973
48
  cur++;
9974
48
    }
9975
2.10M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9976
2.10M
        return(xmlXPathNAN);
9977
2.10M
    }
9978
9979
448
#ifdef __GNUC__
9980
    /*
9981
     * tmp/temp is a workaround against a gcc compiler bug
9982
     * http://veillard.com/gcc.bug
9983
     */
9984
448
    ret = 0;
9985
1.44k
    while ((*cur >= '0') && (*cur <= '9')) {
9986
1.00k
  ret = ret * 10;
9987
1.00k
  tmp = (*cur - '0');
9988
1.00k
  ok = 1;
9989
1.00k
  cur++;
9990
1.00k
  temp = (double) tmp;
9991
1.00k
  ret = ret + temp;
9992
1.00k
    }
9993
#else
9994
    ret = 0;
9995
    while ((*cur >= '0') && (*cur <= '9')) {
9996
  ret = ret * 10 + (*cur - '0');
9997
  ok = 1;
9998
  cur++;
9999
    }
10000
#endif
10001
10002
448
    if (*cur == '.') {
10003
0
  int v, frac = 0, max;
10004
0
  double fraction = 0;
10005
10006
0
        cur++;
10007
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10008
0
      return(xmlXPathNAN);
10009
0
  }
10010
0
        while (*cur == '0') {
10011
0
      frac = frac + 1;
10012
0
      cur++;
10013
0
        }
10014
0
        max = frac + MAX_FRAC;
10015
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10016
0
      v = (*cur - '0');
10017
0
      fraction = fraction * 10 + v;
10018
0
      frac = frac + 1;
10019
0
      cur++;
10020
0
  }
10021
0
  fraction /= pow(10.0, frac);
10022
0
  ret = ret + fraction;
10023
0
  while ((*cur >= '0') && (*cur <= '9'))
10024
0
      cur++;
10025
0
    }
10026
448
    if ((*cur == 'e') || (*cur == 'E')) {
10027
0
      cur++;
10028
0
      if (*cur == '-') {
10029
0
  is_exponent_negative = 1;
10030
0
  cur++;
10031
0
      } else if (*cur == '+') {
10032
0
        cur++;
10033
0
      }
10034
0
      while ((*cur >= '0') && (*cur <= '9')) {
10035
0
        if (exponent < 1000000)
10036
0
    exponent = exponent * 10 + (*cur - '0');
10037
0
  cur++;
10038
0
      }
10039
0
    }
10040
448
    while (IS_BLANK_CH(*cur)) cur++;
10041
448
    if (*cur != 0) return(xmlXPathNAN);
10042
448
    if (isneg) ret = -ret;
10043
448
    if (is_exponent_negative) exponent = -exponent;
10044
448
    ret *= pow(10.0, (double)exponent);
10045
448
    return(ret);
10046
448
}
10047
10048
/**
10049
 * xmlXPathCompNumber:
10050
 * @ctxt:  the XPath Parser context
10051
 *
10052
 *  [30]   Number ::=   Digits ('.' Digits?)?
10053
 *                    | '.' Digits
10054
 *  [31]   Digits ::=   [0-9]+
10055
 *
10056
 * Compile a Number, then push it on the stack
10057
 *
10058
 */
10059
static void
10060
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10061
6.74k
{
10062
6.74k
    double ret = 0.0;
10063
6.74k
    int ok = 0;
10064
6.74k
    int exponent = 0;
10065
6.74k
    int is_exponent_negative = 0;
10066
6.74k
    xmlXPathObjectPtr num;
10067
6.74k
#ifdef __GNUC__
10068
6.74k
    unsigned long tmp = 0;
10069
6.74k
    double temp;
10070
6.74k
#endif
10071
10072
6.74k
    CHECK_ERROR;
10073
6.74k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10074
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10075
0
    }
10076
6.74k
#ifdef __GNUC__
10077
    /*
10078
     * tmp/temp is a workaround against a gcc compiler bug
10079
     * http://veillard.com/gcc.bug
10080
     */
10081
6.74k
    ret = 0;
10082
17.2k
    while ((CUR >= '0') && (CUR <= '9')) {
10083
10.4k
  ret = ret * 10;
10084
10.4k
  tmp = (CUR - '0');
10085
10.4k
        ok = 1;
10086
10.4k
        NEXT;
10087
10.4k
  temp = (double) tmp;
10088
10.4k
  ret = ret + temp;
10089
10.4k
    }
10090
#else
10091
    ret = 0;
10092
    while ((CUR >= '0') && (CUR <= '9')) {
10093
  ret = ret * 10 + (CUR - '0');
10094
  ok = 1;
10095
  NEXT;
10096
    }
10097
#endif
10098
6.74k
    if (CUR == '.') {
10099
298
  int v, frac = 0, max;
10100
298
  double fraction = 0;
10101
10102
298
        NEXT;
10103
298
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10104
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10105
0
        }
10106
571
        while (CUR == '0') {
10107
273
            frac = frac + 1;
10108
273
            NEXT;
10109
273
        }
10110
298
        max = frac + MAX_FRAC;
10111
298
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10112
0
      v = (CUR - '0');
10113
0
      fraction = fraction * 10 + v;
10114
0
      frac = frac + 1;
10115
0
            NEXT;
10116
0
        }
10117
298
        fraction /= pow(10.0, frac);
10118
298
        ret = ret + fraction;
10119
298
        while ((CUR >= '0') && (CUR <= '9'))
10120
0
            NEXT;
10121
298
    }
10122
6.74k
    if ((CUR == 'e') || (CUR == 'E')) {
10123
198
        NEXT;
10124
198
        if (CUR == '-') {
10125
0
            is_exponent_negative = 1;
10126
0
            NEXT;
10127
198
        } else if (CUR == '+') {
10128
0
      NEXT;
10129
0
  }
10130
230
        while ((CUR >= '0') && (CUR <= '9')) {
10131
32
            if (exponent < 1000000)
10132
32
                exponent = exponent * 10 + (CUR - '0');
10133
32
            NEXT;
10134
32
        }
10135
198
        if (is_exponent_negative)
10136
0
            exponent = -exponent;
10137
198
        ret *= pow(10.0, (double) exponent);
10138
198
    }
10139
6.74k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10140
6.74k
    if (num == NULL) {
10141
0
  ctxt->error = XPATH_MEMORY_ERROR;
10142
6.74k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10143
6.74k
                              NULL) == -1) {
10144
0
        xmlXPathReleaseObject(ctxt->context, num);
10145
0
    }
10146
6.74k
}
10147
10148
/**
10149
 * xmlXPathParseLiteral:
10150
 * @ctxt:  the XPath Parser context
10151
 *
10152
 * Parse a Literal
10153
 *
10154
 *  [29]   Literal ::=   '"' [^"]* '"'
10155
 *                    | "'" [^']* "'"
10156
 *
10157
 * Returns the value found or NULL in case of error
10158
 */
10159
static xmlChar *
10160
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10161
0
    const xmlChar *q;
10162
0
    xmlChar *ret = NULL;
10163
10164
0
    if (CUR == '"') {
10165
0
        NEXT;
10166
0
  q = CUR_PTR;
10167
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10168
0
      NEXT;
10169
0
  if (!IS_CHAR_CH(CUR)) {
10170
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10171
0
  } else {
10172
0
      ret = xmlStrndup(q, CUR_PTR - q);
10173
0
      NEXT;
10174
0
        }
10175
0
    } else if (CUR == '\'') {
10176
0
        NEXT;
10177
0
  q = CUR_PTR;
10178
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10179
0
      NEXT;
10180
0
  if (!IS_CHAR_CH(CUR)) {
10181
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10182
0
  } else {
10183
0
      ret = xmlStrndup(q, CUR_PTR - q);
10184
0
      NEXT;
10185
0
        }
10186
0
    } else {
10187
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10188
0
    }
10189
0
    return(ret);
10190
0
}
10191
10192
/**
10193
 * xmlXPathCompLiteral:
10194
 * @ctxt:  the XPath Parser context
10195
 *
10196
 * Parse a Literal and push it on the stack.
10197
 *
10198
 *  [29]   Literal ::=   '"' [^"]* '"'
10199
 *                    | "'" [^']* "'"
10200
 *
10201
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10202
 */
10203
static void
10204
390
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10205
390
    const xmlChar *q;
10206
390
    xmlChar *ret = NULL;
10207
390
    xmlXPathObjectPtr lit;
10208
10209
390
    if (CUR == '"') {
10210
0
        NEXT;
10211
0
  q = CUR_PTR;
10212
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10213
0
      NEXT;
10214
0
  if (!IS_CHAR_CH(CUR)) {
10215
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10216
0
  } else {
10217
0
      ret = xmlStrndup(q, CUR_PTR - q);
10218
0
      NEXT;
10219
0
        }
10220
390
    } else if (CUR == '\'') {
10221
390
        NEXT;
10222
390
  q = CUR_PTR;
10223
4.26M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10224
4.26M
      NEXT;
10225
390
  if (!IS_CHAR_CH(CUR)) {
10226
103
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10227
287
  } else {
10228
287
      ret = xmlStrndup(q, CUR_PTR - q);
10229
287
      NEXT;
10230
287
        }
10231
390
    } else {
10232
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10233
0
    }
10234
287
    if (ret == NULL) {
10235
0
        xmlXPathPErrMemory(ctxt, NULL);
10236
0
        return;
10237
0
    }
10238
287
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10239
287
    if (lit == NULL) {
10240
0
  ctxt->error = XPATH_MEMORY_ERROR;
10241
287
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10242
287
                              NULL) == -1) {
10243
0
        xmlXPathReleaseObject(ctxt->context, lit);
10244
0
    }
10245
287
    xmlFree(ret);
10246
287
}
10247
10248
/**
10249
 * xmlXPathCompVariableReference:
10250
 * @ctxt:  the XPath Parser context
10251
 *
10252
 * Parse a VariableReference, evaluate it and push it on the stack.
10253
 *
10254
 * The variable bindings consist of a mapping from variable names
10255
 * to variable values. The value of a variable is an object, which can be
10256
 * of any of the types that are possible for the value of an expression,
10257
 * and may also be of additional types not specified here.
10258
 *
10259
 * Early evaluation is possible since:
10260
 * The variable bindings [...] used to evaluate a subexpression are
10261
 * always the same as those used to evaluate the containing expression.
10262
 *
10263
 *  [36]   VariableReference ::=   '$' QName
10264
 */
10265
static void
10266
222
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10267
222
    xmlChar *name;
10268
222
    xmlChar *prefix;
10269
10270
222
    SKIP_BLANKS;
10271
222
    if (CUR != '$') {
10272
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10273
0
    }
10274
222
    NEXT;
10275
222
    name = xmlXPathParseQName(ctxt, &prefix);
10276
222
    if (name == NULL) {
10277
1
        xmlFree(prefix);
10278
1
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10279
0
    }
10280
221
    ctxt->comp->last = -1;
10281
221
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10282
0
        xmlFree(prefix);
10283
0
        xmlFree(name);
10284
0
    }
10285
221
    SKIP_BLANKS;
10286
221
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10287
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10288
0
    }
10289
221
}
10290
10291
/**
10292
 * xmlXPathIsNodeType:
10293
 * @name:  a name string
10294
 *
10295
 * Is the name given a NodeType one.
10296
 *
10297
 *  [38]   NodeType ::=   'comment'
10298
 *                    | 'text'
10299
 *                    | 'processing-instruction'
10300
 *                    | 'node'
10301
 *
10302
 * Returns 1 if true 0 otherwise
10303
 */
10304
int
10305
407
xmlXPathIsNodeType(const xmlChar *name) {
10306
407
    if (name == NULL)
10307
0
  return(0);
10308
10309
407
    if (xmlStrEqual(name, BAD_CAST "node"))
10310
0
  return(1);
10311
407
    if (xmlStrEqual(name, BAD_CAST "text"))
10312
0
  return(1);
10313
407
    if (xmlStrEqual(name, BAD_CAST "comment"))
10314
0
  return(1);
10315
407
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10316
0
  return(1);
10317
407
    return(0);
10318
407
}
10319
10320
/**
10321
 * xmlXPathCompFunctionCall:
10322
 * @ctxt:  the XPath Parser context
10323
 *
10324
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10325
 *  [17]   Argument ::=   Expr
10326
 *
10327
 * Compile a function call, the evaluation of all arguments are
10328
 * pushed on the stack
10329
 */
10330
static void
10331
407
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10332
407
    xmlChar *name;
10333
407
    xmlChar *prefix;
10334
407
    int nbargs = 0;
10335
407
    int sort = 1;
10336
10337
407
    name = xmlXPathParseQName(ctxt, &prefix);
10338
407
    if (name == NULL) {
10339
0
  xmlFree(prefix);
10340
0
  XP_ERROR(XPATH_EXPR_ERROR);
10341
0
    }
10342
407
    SKIP_BLANKS;
10343
#ifdef DEBUG_EXPR
10344
    if (prefix == NULL)
10345
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10346
      name);
10347
    else
10348
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10349
      prefix, name);
10350
#endif
10351
10352
407
    if (CUR != '(') {
10353
0
  xmlFree(name);
10354
0
  xmlFree(prefix);
10355
0
  XP_ERROR(XPATH_EXPR_ERROR);
10356
0
    }
10357
407
    NEXT;
10358
407
    SKIP_BLANKS;
10359
10360
    /*
10361
    * Optimization for count(): we don't need the node-set to be sorted.
10362
    */
10363
407
    if ((prefix == NULL) && (name[0] == 'c') &&
10364
407
  xmlStrEqual(name, BAD_CAST "count"))
10365
0
    {
10366
0
  sort = 0;
10367
0
    }
10368
407
    ctxt->comp->last = -1;
10369
407
    if (CUR != ')') {
10370
586
  while (CUR != 0) {
10371
562
      int op1 = ctxt->comp->last;
10372
562
      ctxt->comp->last = -1;
10373
562
      xmlXPathCompileExpr(ctxt, sort);
10374
562
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10375
34
    xmlFree(name);
10376
34
    xmlFree(prefix);
10377
34
    return;
10378
34
      }
10379
528
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10380
528
      nbargs++;
10381
528
      if (CUR == ')') break;
10382
256
      if (CUR != ',') {
10383
52
    xmlFree(name);
10384
52
    xmlFree(prefix);
10385
52
    XP_ERROR(XPATH_EXPR_ERROR);
10386
0
      }
10387
204
      NEXT;
10388
204
      SKIP_BLANKS;
10389
204
  }
10390
382
    }
10391
321
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10392
0
        xmlFree(prefix);
10393
0
        xmlFree(name);
10394
0
    }
10395
321
    NEXT;
10396
321
    SKIP_BLANKS;
10397
321
}
10398
10399
/**
10400
 * xmlXPathCompPrimaryExpr:
10401
 * @ctxt:  the XPath Parser context
10402
 *
10403
 *  [15]   PrimaryExpr ::=   VariableReference
10404
 *                | '(' Expr ')'
10405
 *                | Literal
10406
 *                | Number
10407
 *                | FunctionCall
10408
 *
10409
 * Compile a primary expression.
10410
 */
10411
static void
10412
8.21k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10413
8.21k
    SKIP_BLANKS;
10414
8.21k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10415
7.99k
    else if (CUR == '(') {
10416
448
  NEXT;
10417
448
  SKIP_BLANKS;
10418
448
  xmlXPathCompileExpr(ctxt, 1);
10419
448
  CHECK_ERROR;
10420
438
  if (CUR != ')') {
10421
1
      XP_ERROR(XPATH_EXPR_ERROR);
10422
0
  }
10423
437
  NEXT;
10424
437
  SKIP_BLANKS;
10425
7.54k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10426
6.74k
  xmlXPathCompNumber(ctxt);
10427
6.74k
    } else if ((CUR == '\'') || (CUR == '"')) {
10428
390
  xmlXPathCompLiteral(ctxt);
10429
407
    } else {
10430
407
  xmlXPathCompFunctionCall(ctxt);
10431
407
    }
10432
8.20k
    SKIP_BLANKS;
10433
8.20k
}
10434
10435
/**
10436
 * xmlXPathCompFilterExpr:
10437
 * @ctxt:  the XPath Parser context
10438
 *
10439
 *  [20]   FilterExpr ::=   PrimaryExpr
10440
 *               | FilterExpr Predicate
10441
 *
10442
 * Compile a filter expression.
10443
 * Square brackets are used to filter expressions in the same way that
10444
 * they are used in location paths. It is an error if the expression to
10445
 * be filtered does not evaluate to a node-set. The context node list
10446
 * used for evaluating the expression in square brackets is the node-set
10447
 * to be filtered listed in document order.
10448
 */
10449
10450
static void
10451
8.21k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10452
8.21k
    xmlXPathCompPrimaryExpr(ctxt);
10453
8.21k
    CHECK_ERROR;
10454
8.01k
    SKIP_BLANKS;
10455
10456
8.15k
    while (CUR == '[') {
10457
139
  xmlXPathCompPredicate(ctxt, 1);
10458
139
  SKIP_BLANKS;
10459
139
    }
10460
10461
10462
8.01k
}
10463
10464
/**
10465
 * xmlXPathScanName:
10466
 * @ctxt:  the XPath Parser context
10467
 *
10468
 * Trickery: parse an XML name but without consuming the input flow
10469
 * Needed to avoid insanity in the parser state.
10470
 *
10471
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10472
 *                  CombiningChar | Extender
10473
 *
10474
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10475
 *
10476
 * [6] Names ::= Name (S Name)*
10477
 *
10478
 * Returns the Name parsed or NULL
10479
 */
10480
10481
static xmlChar *
10482
4.21M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10483
4.21M
    int l;
10484
4.21M
    int c;
10485
4.21M
    const xmlChar *cur;
10486
4.21M
    xmlChar *ret;
10487
10488
4.21M
    cur = ctxt->cur;
10489
10490
4.21M
    c = CUR_CHAR(l);
10491
4.21M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10492
4.21M
  (!IS_LETTER(c) && (c != '_') &&
10493
4.21M
         (c != ':'))) {
10494
3.61k
  return(NULL);
10495
3.61k
    }
10496
10497
14.9M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10498
14.9M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10499
14.9M
            (c == '.') || (c == '-') ||
10500
14.9M
      (c == '_') || (c == ':') ||
10501
14.9M
      (IS_COMBINING(c)) ||
10502
14.9M
      (IS_EXTENDER(c)))) {
10503
10.6M
  NEXTL(l);
10504
10.6M
  c = CUR_CHAR(l);
10505
10.6M
    }
10506
4.21M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10507
4.21M
    ctxt->cur = cur;
10508
4.21M
    return(ret);
10509
4.21M
}
10510
10511
/**
10512
 * xmlXPathCompPathExpr:
10513
 * @ctxt:  the XPath Parser context
10514
 *
10515
 *  [19]   PathExpr ::=   LocationPath
10516
 *               | FilterExpr
10517
 *               | FilterExpr '/' RelativeLocationPath
10518
 *               | FilterExpr '//' RelativeLocationPath
10519
 *
10520
 * Compile a path expression.
10521
 * The / operator and // operators combine an arbitrary expression
10522
 * and a relative location path. It is an error if the expression
10523
 * does not evaluate to a node-set.
10524
 * The / operator does composition in the same way as when / is
10525
 * used in a location path. As in location paths, // is short for
10526
 * /descendant-or-self::node()/.
10527
 */
10528
10529
static void
10530
4.23M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10531
4.23M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10532
4.23M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10533
10534
4.23M
    SKIP_BLANKS;
10535
4.23M
    if ((CUR == '$') || (CUR == '(') ||
10536
4.23M
  (IS_ASCII_DIGIT(CUR)) ||
10537
4.23M
        (CUR == '\'') || (CUR == '"') ||
10538
4.23M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10539
7.80k
  lc = 0;
10540
4.22M
    } else if (CUR == '*') {
10541
  /* relative or absolute location path */
10542
135
  lc = 1;
10543
4.22M
    } else if (CUR == '/') {
10544
  /* relative or absolute location path */
10545
6.70k
  lc = 1;
10546
4.21M
    } else if (CUR == '@') {
10547
  /* relative abbreviated attribute location path */
10548
102
  lc = 1;
10549
4.21M
    } else if (CUR == '.') {
10550
  /* relative abbreviated attribute location path */
10551
229
  lc = 1;
10552
4.21M
    } else {
10553
  /*
10554
   * Problem is finding if we have a name here whether it's:
10555
   *   - a nodetype
10556
   *   - a function call in which case it's followed by '('
10557
   *   - an axis in which case it's followed by ':'
10558
   *   - a element name
10559
   * We do an a priori analysis here rather than having to
10560
   * maintain parsed token content through the recursive function
10561
   * calls. This looks uglier but makes the code easier to
10562
   * read/write/debug.
10563
   */
10564
4.21M
  SKIP_BLANKS;
10565
4.21M
  name = xmlXPathScanName(ctxt);
10566
4.21M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10567
#ifdef DEBUG_STEP
10568
      xmlGenericError(xmlGenericErrorContext,
10569
        "PathExpr: Axis\n");
10570
#endif
10571
80
      lc = 1;
10572
80
      xmlFree(name);
10573
4.21M
  } else if (name != NULL) {
10574
4.21M
      int len =xmlStrlen(name);
10575
10576
10577
4.21M
      while (NXT(len) != 0) {
10578
4.21M
    if (NXT(len) == '/') {
10579
        /* element name */
10580
#ifdef DEBUG_STEP
10581
        xmlGenericError(xmlGenericErrorContext,
10582
          "PathExpr: AbbrRelLocation\n");
10583
#endif
10584
46
        lc = 1;
10585
46
        break;
10586
4.21M
    } else if (IS_BLANK_CH(NXT(len))) {
10587
        /* ignore blanks */
10588
902
        ;
10589
4.21M
    } else if (NXT(len) == ':') {
10590
#ifdef DEBUG_STEP
10591
        xmlGenericError(xmlGenericErrorContext,
10592
          "PathExpr: AbbrRelLocation\n");
10593
#endif
10594
7
        lc = 1;
10595
7
        break;
10596
4.21M
    } else if ((NXT(len) == '(')) {
10597
        /* Node Type or Function */
10598
407
        if (xmlXPathIsNodeType(name)) {
10599
#ifdef DEBUG_STEP
10600
            xmlGenericError(xmlGenericErrorContext,
10601
        "PathExpr: Type search\n");
10602
#endif
10603
0
      lc = 1;
10604
#ifdef LIBXML_XPTR_LOCS_ENABLED
10605
                    } else if (ctxt->xptr &&
10606
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10607
                        lc = 1;
10608
#endif
10609
407
        } else {
10610
#ifdef DEBUG_STEP
10611
            xmlGenericError(xmlGenericErrorContext,
10612
        "PathExpr: function call\n");
10613
#endif
10614
407
      lc = 0;
10615
407
        }
10616
407
                    break;
10617
4.21M
    } else if ((NXT(len) == '[')) {
10618
        /* element name */
10619
#ifdef DEBUG_STEP
10620
        xmlGenericError(xmlGenericErrorContext,
10621
          "PathExpr: AbbrRelLocation\n");
10622
#endif
10623
1
        lc = 1;
10624
1
        break;
10625
4.21M
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10626
4.21M
         (NXT(len) == '=')) {
10627
6.04k
        lc = 1;
10628
6.04k
        break;
10629
4.20M
    } else {
10630
4.20M
        lc = 1;
10631
4.20M
        break;
10632
4.20M
    }
10633
902
    len++;
10634
902
      }
10635
4.21M
      if (NXT(len) == 0) {
10636
#ifdef DEBUG_STEP
10637
    xmlGenericError(xmlGenericErrorContext,
10638
      "PathExpr: AbbrRelLocation\n");
10639
#endif
10640
    /* element name */
10641
83
    lc = 1;
10642
83
      }
10643
4.21M
      xmlFree(name);
10644
4.21M
  } else {
10645
      /* make sure all cases are covered explicitly */
10646
3.61k
      XP_ERROR(XPATH_EXPR_ERROR);
10647
0
  }
10648
4.21M
    }
10649
10650
4.22M
    if (lc) {
10651
4.21M
  if (CUR == '/') {
10652
6.70k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10653
4.21M
  } else {
10654
4.21M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10655
4.21M
  }
10656
4.21M
  xmlXPathCompLocationPath(ctxt);
10657
4.21M
    } else {
10658
8.21k
  xmlXPathCompFilterExpr(ctxt);
10659
8.21k
  CHECK_ERROR;
10660
8.00k
  if ((CUR == '/') && (NXT(1) == '/')) {
10661
13
      SKIP(2);
10662
13
      SKIP_BLANKS;
10663
10664
13
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10665
13
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10666
10667
13
      xmlXPathCompRelativeLocationPath(ctxt);
10668
7.98k
  } else if (CUR == '/') {
10669
290
      xmlXPathCompRelativeLocationPath(ctxt);
10670
290
  }
10671
8.00k
    }
10672
4.22M
    SKIP_BLANKS;
10673
4.22M
}
10674
10675
/**
10676
 * xmlXPathCompUnionExpr:
10677
 * @ctxt:  the XPath Parser context
10678
 *
10679
 *  [18]   UnionExpr ::=   PathExpr
10680
 *               | UnionExpr '|' PathExpr
10681
 *
10682
 * Compile an union expression.
10683
 */
10684
10685
static void
10686
14.2k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10687
14.2k
    xmlXPathCompPathExpr(ctxt);
10688
14.2k
    CHECK_ERROR;
10689
10.0k
    SKIP_BLANKS;
10690
4.22M
    while (CUR == '|') {
10691
4.21M
  int op1 = ctxt->comp->last;
10692
4.21M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10693
10694
4.21M
  NEXT;
10695
4.21M
  SKIP_BLANKS;
10696
4.21M
  xmlXPathCompPathExpr(ctxt);
10697
10698
4.21M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10699
10700
4.21M
  SKIP_BLANKS;
10701
4.21M
    }
10702
10.0k
}
10703
10704
/**
10705
 * xmlXPathCompUnaryExpr:
10706
 * @ctxt:  the XPath Parser context
10707
 *
10708
 *  [27]   UnaryExpr ::=   UnionExpr
10709
 *                   | '-' UnaryExpr
10710
 *
10711
 * Compile an unary expression.
10712
 */
10713
10714
static void
10715
14.2k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10716
14.2k
    int minus = 0;
10717
14.2k
    int found = 0;
10718
10719
14.2k
    SKIP_BLANKS;
10720
14.5k
    while (CUR == '-') {
10721
332
        minus = 1 - minus;
10722
332
  found = 1;
10723
332
  NEXT;
10724
332
  SKIP_BLANKS;
10725
332
    }
10726
10727
14.2k
    xmlXPathCompUnionExpr(ctxt);
10728
14.2k
    CHECK_ERROR;
10729
10.0k
    if (found) {
10730
206
  if (minus)
10731
169
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10732
37
  else
10733
37
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10734
206
    }
10735
10.0k
}
10736
10737
/**
10738
 * xmlXPathCompMultiplicativeExpr:
10739
 * @ctxt:  the XPath Parser context
10740
 *
10741
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10742
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10743
 *                   | MultiplicativeExpr 'div' UnaryExpr
10744
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10745
 *  [34]   MultiplyOperator ::=   '*'
10746
 *
10747
 * Compile an Additive expression.
10748
 */
10749
10750
static void
10751
13.7k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10752
13.7k
    xmlXPathCompUnaryExpr(ctxt);
10753
13.7k
    CHECK_ERROR;
10754
9.50k
    SKIP_BLANKS;
10755
10.0k
    while ((CUR == '*') ||
10756
10.0k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10757
10.0k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10758
536
  int op = -1;
10759
536
  int op1 = ctxt->comp->last;
10760
10761
536
        if (CUR == '*') {
10762
130
      op = 0;
10763
130
      NEXT;
10764
406
  } else if (CUR == 'd') {
10765
85
      op = 1;
10766
85
      SKIP(3);
10767
321
  } else if (CUR == 'm') {
10768
321
      op = 2;
10769
321
      SKIP(3);
10770
321
  }
10771
536
  SKIP_BLANKS;
10772
536
        xmlXPathCompUnaryExpr(ctxt);
10773
536
  CHECK_ERROR;
10774
529
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10775
529
  SKIP_BLANKS;
10776
529
    }
10777
9.50k
}
10778
10779
/**
10780
 * xmlXPathCompAdditiveExpr:
10781
 * @ctxt:  the XPath Parser context
10782
 *
10783
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10784
 *                   | AdditiveExpr '+' MultiplicativeExpr
10785
 *                   | AdditiveExpr '-' MultiplicativeExpr
10786
 *
10787
 * Compile an Additive expression.
10788
 */
10789
10790
static void
10791
13.5k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10792
10793
13.5k
    xmlXPathCompMultiplicativeExpr(ctxt);
10794
13.5k
    CHECK_ERROR;
10795
9.44k
    SKIP_BLANKS;
10796
9.49k
    while ((CUR == '+') || (CUR == '-')) {
10797
135
  int plus;
10798
135
  int op1 = ctxt->comp->last;
10799
10800
135
        if (CUR == '+') plus = 1;
10801
91
  else plus = 0;
10802
135
  NEXT;
10803
135
  SKIP_BLANKS;
10804
135
        xmlXPathCompMultiplicativeExpr(ctxt);
10805
135
  CHECK_ERROR;
10806
57
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10807
57
  SKIP_BLANKS;
10808
57
    }
10809
9.44k
}
10810
10811
/**
10812
 * xmlXPathCompRelationalExpr:
10813
 * @ctxt:  the XPath Parser context
10814
 *
10815
 *  [24]   RelationalExpr ::=   AdditiveExpr
10816
 *                 | RelationalExpr '<' AdditiveExpr
10817
 *                 | RelationalExpr '>' AdditiveExpr
10818
 *                 | RelationalExpr '<=' AdditiveExpr
10819
 *                 | RelationalExpr '>=' AdditiveExpr
10820
 *
10821
 *  A <= B > C is allowed ? Answer from James, yes with
10822
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10823
 *  which is basically what got implemented.
10824
 *
10825
 * Compile a Relational expression, then push the result
10826
 * on the stack
10827
 */
10828
10829
static void
10830
7.94k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10831
7.94k
    xmlXPathCompAdditiveExpr(ctxt);
10832
7.94k
    CHECK_ERROR;
10833
4.02k
    SKIP_BLANKS;
10834
9.36k
    while ((CUR == '<') || (CUR == '>')) {
10835
5.62k
  int inf, strict;
10836
5.62k
  int op1 = ctxt->comp->last;
10837
10838
5.62k
        if (CUR == '<') inf = 1;
10839
501
  else inf = 0;
10840
5.62k
  if (NXT(1) == '=') strict = 0;
10841
5.60k
  else strict = 1;
10842
5.62k
  NEXT;
10843
5.62k
  if (!strict) NEXT;
10844
5.62k
  SKIP_BLANKS;
10845
5.62k
        xmlXPathCompAdditiveExpr(ctxt);
10846
5.62k
  CHECK_ERROR;
10847
5.34k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10848
5.34k
  SKIP_BLANKS;
10849
5.34k
    }
10850
4.02k
}
10851
10852
/**
10853
 * xmlXPathCompEqualityExpr:
10854
 * @ctxt:  the XPath Parser context
10855
 *
10856
 *  [23]   EqualityExpr ::=   RelationalExpr
10857
 *                 | EqualityExpr '=' RelationalExpr
10858
 *                 | EqualityExpr '!=' RelationalExpr
10859
 *
10860
 *  A != B != C is allowed ? Answer from James, yes with
10861
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10862
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10863
 *  which is basically what got implemented.
10864
 *
10865
 * Compile an Equality expression.
10866
 *
10867
 */
10868
static void
10869
6.99k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10870
6.99k
    xmlXPathCompRelationalExpr(ctxt);
10871
6.99k
    CHECK_ERROR;
10872
2.96k
    SKIP_BLANKS;
10873
3.74k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10874
955
  int eq;
10875
955
  int op1 = ctxt->comp->last;
10876
10877
955
        if (CUR == '=') eq = 1;
10878
11
  else eq = 0;
10879
955
  NEXT;
10880
955
  if (!eq) NEXT;
10881
955
  SKIP_BLANKS;
10882
955
        xmlXPathCompRelationalExpr(ctxt);
10883
955
  CHECK_ERROR;
10884
775
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10885
775
  SKIP_BLANKS;
10886
775
    }
10887
2.96k
}
10888
10889
/**
10890
 * xmlXPathCompAndExpr:
10891
 * @ctxt:  the XPath Parser context
10892
 *
10893
 *  [22]   AndExpr ::=   EqualityExpr
10894
 *                 | AndExpr 'and' EqualityExpr
10895
 *
10896
 * Compile an AND expression.
10897
 *
10898
 */
10899
static void
10900
6.98k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10901
6.98k
    xmlXPathCompEqualityExpr(ctxt);
10902
6.98k
    CHECK_ERROR;
10903
2.78k
    SKIP_BLANKS;
10904
2.78k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10905
3
  int op1 = ctxt->comp->last;
10906
3
        SKIP(3);
10907
3
  SKIP_BLANKS;
10908
3
        xmlXPathCompEqualityExpr(ctxt);
10909
3
  CHECK_ERROR;
10910
3
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10911
3
  SKIP_BLANKS;
10912
3
    }
10913
2.78k
}
10914
10915
/**
10916
 * xmlXPathCompileExpr:
10917
 * @ctxt:  the XPath Parser context
10918
 *
10919
 *  [14]   Expr ::=   OrExpr
10920
 *  [21]   OrExpr ::=   AndExpr
10921
 *                 | OrExpr 'or' AndExpr
10922
 *
10923
 * Parse and compile an expression
10924
 */
10925
static void
10926
6.98k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10927
6.98k
    xmlXPathContextPtr xpctxt = ctxt->context;
10928
10929
6.98k
    if (xpctxt != NULL) {
10930
6.98k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10931
6.98k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10932
        /*
10933
         * Parsing a single '(' pushes about 10 functions on the call stack
10934
         * before recursing!
10935
         */
10936
6.98k
        xpctxt->depth += 10;
10937
6.98k
    }
10938
10939
6.98k
    xmlXPathCompAndExpr(ctxt);
10940
6.98k
    CHECK_ERROR;
10941
2.77k
    SKIP_BLANKS;
10942
2.78k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10943
7
  int op1 = ctxt->comp->last;
10944
7
        SKIP(2);
10945
7
  SKIP_BLANKS;
10946
7
        xmlXPathCompAndExpr(ctxt);
10947
7
  CHECK_ERROR;
10948
7
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10949
7
  SKIP_BLANKS;
10950
7
    }
10951
2.77k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10952
  /* more ops could be optimized too */
10953
  /*
10954
  * This is the main place to eliminate sorting for
10955
  * operations which don't require a sorted node-set.
10956
  * E.g. count().
10957
  */
10958
2.02k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10959
2.02k
    }
10960
10961
2.77k
    if (xpctxt != NULL)
10962
2.77k
        xpctxt->depth -= 10;
10963
2.77k
}
10964
10965
/**
10966
 * xmlXPathCompPredicate:
10967
 * @ctxt:  the XPath Parser context
10968
 * @filter:  act as a filter
10969
 *
10970
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10971
 *  [9]   PredicateExpr ::=   Expr
10972
 *
10973
 * Compile a predicate expression
10974
 */
10975
static void
10976
280
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10977
280
    int op1 = ctxt->comp->last;
10978
10979
280
    SKIP_BLANKS;
10980
280
    if (CUR != '[') {
10981
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10982
0
    }
10983
280
    NEXT;
10984
280
    SKIP_BLANKS;
10985
10986
280
    ctxt->comp->last = -1;
10987
    /*
10988
    * This call to xmlXPathCompileExpr() will deactivate sorting
10989
    * of the predicate result.
10990
    * TODO: Sorting is still activated for filters, since I'm not
10991
    *  sure if needed. Normally sorting should not be needed, since
10992
    *  a filter can only diminish the number of items in a sequence,
10993
    *  but won't change its order; so if the initial sequence is sorted,
10994
    *  subsequent sorting is not needed.
10995
    */
10996
280
    if (! filter)
10997
141
  xmlXPathCompileExpr(ctxt, 0);
10998
139
    else
10999
139
  xmlXPathCompileExpr(ctxt, 1);
11000
280
    CHECK_ERROR;
11001
11002
265
    if (CUR != ']') {
11003
9
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11004
0
    }
11005
11006
256
    if (filter)
11007
129
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11008
127
    else
11009
127
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11010
11011
256
    NEXT;
11012
256
    SKIP_BLANKS;
11013
256
}
11014
11015
/**
11016
 * xmlXPathCompNodeTest:
11017
 * @ctxt:  the XPath Parser context
11018
 * @test:  pointer to a xmlXPathTestVal
11019
 * @type:  pointer to a xmlXPathTypeVal
11020
 * @prefix:  placeholder for a possible name prefix
11021
 *
11022
 * [7] NodeTest ::=   NameTest
11023
 *        | NodeType '(' ')'
11024
 *        | 'processing-instruction' '(' Literal ')'
11025
 *
11026
 * [37] NameTest ::=  '*'
11027
 *        | NCName ':' '*'
11028
 *        | QName
11029
 * [38] NodeType ::= 'comment'
11030
 *       | 'text'
11031
 *       | 'processing-instruction'
11032
 *       | 'node'
11033
 *
11034
 * Returns the name found and updates @test, @type and @prefix appropriately
11035
 */
11036
static xmlChar *
11037
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11038
               xmlXPathTypeVal *type, xmlChar **prefix,
11039
4.94M
         xmlChar *name) {
11040
4.94M
    int blanks;
11041
11042
4.94M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11043
0
  STRANGE;
11044
0
  return(NULL);
11045
0
    }
11046
4.94M
    *type = (xmlXPathTypeVal) 0;
11047
4.94M
    *test = (xmlXPathTestVal) 0;
11048
4.94M
    *prefix = NULL;
11049
4.94M
    SKIP_BLANKS;
11050
11051
4.94M
    if ((name == NULL) && (CUR == '*')) {
11052
  /*
11053
   * All elements
11054
   */
11055
246k
  NEXT;
11056
246k
  *test = NODE_TEST_ALL;
11057
246k
  return(NULL);
11058
246k
    }
11059
11060
4.70M
    if (name == NULL)
11061
211
  name = xmlXPathParseNCName(ctxt);
11062
4.70M
    if (name == NULL) {
11063
79
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11064
0
    }
11065
11066
4.69M
    blanks = IS_BLANK_CH(CUR);
11067
4.69M
    SKIP_BLANKS;
11068
4.69M
    if (CUR == '(') {
11069
539
  NEXT;
11070
  /*
11071
   * NodeType or PI search
11072
   */
11073
539
  if (xmlStrEqual(name, BAD_CAST "comment"))
11074
0
      *type = NODE_TYPE_COMMENT;
11075
539
  else if (xmlStrEqual(name, BAD_CAST "node"))
11076
489
      *type = NODE_TYPE_NODE;
11077
50
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11078
47
      *type = NODE_TYPE_PI;
11079
3
  else if (xmlStrEqual(name, BAD_CAST "text"))
11080
2
      *type = NODE_TYPE_TEXT;
11081
1
  else {
11082
1
      if (name != NULL)
11083
1
    xmlFree(name);
11084
1
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11085
0
  }
11086
11087
538
  *test = NODE_TEST_TYPE;
11088
11089
538
  SKIP_BLANKS;
11090
538
  if (*type == NODE_TYPE_PI) {
11091
      /*
11092
       * Specific case: search a PI by name.
11093
       */
11094
47
      if (name != NULL)
11095
47
    xmlFree(name);
11096
47
      name = NULL;
11097
47
      if (CUR != ')') {
11098
0
    name = xmlXPathParseLiteral(ctxt);
11099
0
                if (name == NULL) {
11100
0
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11101
0
                }
11102
0
    *test = NODE_TEST_PI;
11103
0
    SKIP_BLANKS;
11104
0
      }
11105
47
  }
11106
538
  if (CUR != ')') {
11107
0
      if (name != NULL)
11108
0
    xmlFree(name);
11109
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11110
0
  }
11111
538
  NEXT;
11112
538
  return(name);
11113
538
    }
11114
4.69M
    *test = NODE_TEST_NAME;
11115
4.69M
    if ((!blanks) && (CUR == ':')) {
11116
345
  NEXT;
11117
11118
  /*
11119
   * Since currently the parser context don't have a
11120
   * namespace list associated:
11121
   * The namespace name for this prefix can be computed
11122
   * only at evaluation time. The compilation is done
11123
   * outside of any context.
11124
   */
11125
#if 0
11126
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11127
  if (name != NULL)
11128
      xmlFree(name);
11129
  if (*prefix == NULL) {
11130
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11131
  }
11132
#else
11133
345
  *prefix = name;
11134
345
#endif
11135
11136
345
  if (CUR == '*') {
11137
      /*
11138
       * All elements
11139
       */
11140
1
      NEXT;
11141
1
      *test = NODE_TEST_ALL;
11142
1
      return(NULL);
11143
1
  }
11144
11145
344
  name = xmlXPathParseNCName(ctxt);
11146
344
  if (name == NULL) {
11147
117
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11148
0
  }
11149
344
    }
11150
4.69M
    return(name);
11151
4.69M
}
11152
11153
/**
11154
 * xmlXPathIsAxisName:
11155
 * @name:  a preparsed name token
11156
 *
11157
 * [6] AxisName ::=   'ancestor'
11158
 *                  | 'ancestor-or-self'
11159
 *                  | 'attribute'
11160
 *                  | 'child'
11161
 *                  | 'descendant'
11162
 *                  | 'descendant-or-self'
11163
 *                  | 'following'
11164
 *                  | 'following-sibling'
11165
 *                  | 'namespace'
11166
 *                  | 'parent'
11167
 *                  | 'preceding'
11168
 *                  | 'preceding-sibling'
11169
 *                  | 'self'
11170
 *
11171
 * Returns the axis or 0
11172
 */
11173
static xmlXPathAxisVal
11174
4.70M
xmlXPathIsAxisName(const xmlChar *name) {
11175
4.70M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11176
4.70M
    switch (name[0]) {
11177
246k
  case 'a':
11178
246k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11179
1
    ret = AXIS_ANCESTOR;
11180
246k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11181
25
    ret = AXIS_ANCESTOR_OR_SELF;
11182
246k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11183
0
    ret = AXIS_ATTRIBUTE;
11184
246k
      break;
11185
9
  case 'c':
11186
9
      if (xmlStrEqual(name, BAD_CAST "child"))
11187
0
    ret = AXIS_CHILD;
11188
9
      break;
11189
156
  case 'd':
11190
156
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11191
0
    ret = AXIS_DESCENDANT;
11192
156
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11193
0
    ret = AXIS_DESCENDANT_OR_SELF;
11194
156
      break;
11195
133
  case 'f':
11196
133
      if (xmlStrEqual(name, BAD_CAST "following"))
11197
4
    ret = AXIS_FOLLOWING;
11198
133
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11199
0
    ret = AXIS_FOLLOWING_SIBLING;
11200
133
      break;
11201
939
  case 'n':
11202
939
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11203
406
    ret = AXIS_NAMESPACE;
11204
939
      break;
11205
209
  case 'p':
11206
209
      if (xmlStrEqual(name, BAD_CAST "parent"))
11207
0
    ret = AXIS_PARENT;
11208
209
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11209
40
    ret = AXIS_PRECEDING;
11210
209
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11211
25
    ret = AXIS_PRECEDING_SIBLING;
11212
209
      break;
11213
55
  case 's':
11214
55
      if (xmlStrEqual(name, BAD_CAST "self"))
11215
2
    ret = AXIS_SELF;
11216
55
      break;
11217
4.70M
    }
11218
4.70M
    return(ret);
11219
4.70M
}
11220
11221
/**
11222
 * xmlXPathCompStep:
11223
 * @ctxt:  the XPath Parser context
11224
 *
11225
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11226
 *                  | AbbreviatedStep
11227
 *
11228
 * [12] AbbreviatedStep ::=   '.' | '..'
11229
 *
11230
 * [5] AxisSpecifier ::= AxisName '::'
11231
 *                  | AbbreviatedAxisSpecifier
11232
 *
11233
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11234
 *
11235
 * Modified for XPtr range support as:
11236
 *
11237
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11238
 *                     | AbbreviatedStep
11239
 *                     | 'range-to' '(' Expr ')' Predicate*
11240
 *
11241
 * Compile one step in a Location Path
11242
 * A location step of . is short for self::node(). This is
11243
 * particularly useful in conjunction with //. For example, the
11244
 * location path .//para is short for
11245
 * self::node()/descendant-or-self::node()/child::para
11246
 * and so will select all para descendant elements of the context
11247
 * node.
11248
 * Similarly, a location step of .. is short for parent::node().
11249
 * For example, ../title is short for parent::node()/child::title
11250
 * and so will select the title children of the parent of the context
11251
 * node.
11252
 */
11253
static void
11254
4.95M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11255
#ifdef LIBXML_XPTR_LOCS_ENABLED
11256
    int rangeto = 0;
11257
    int op2 = -1;
11258
#endif
11259
11260
4.95M
    SKIP_BLANKS;
11261
4.95M
    if ((CUR == '.') && (NXT(1) == '.')) {
11262
79
  SKIP(2);
11263
79
  SKIP_BLANKS;
11264
79
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11265
79
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11266
4.95M
    } else if (CUR == '.') {
11267
403
  NEXT;
11268
403
  SKIP_BLANKS;
11269
4.95M
    } else {
11270
4.95M
  xmlChar *name = NULL;
11271
4.95M
  xmlChar *prefix = NULL;
11272
4.95M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11273
4.95M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11274
4.95M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11275
4.95M
  int op1;
11276
11277
  /*
11278
   * The modification needed for XPointer change to the production
11279
   */
11280
#ifdef LIBXML_XPTR_LOCS_ENABLED
11281
  if (ctxt->xptr) {
11282
      name = xmlXPathParseNCName(ctxt);
11283
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11284
                op2 = ctxt->comp->last;
11285
    xmlFree(name);
11286
    SKIP_BLANKS;
11287
    if (CUR != '(') {
11288
        XP_ERROR(XPATH_EXPR_ERROR);
11289
    }
11290
    NEXT;
11291
    SKIP_BLANKS;
11292
11293
    xmlXPathCompileExpr(ctxt, 1);
11294
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11295
    CHECK_ERROR;
11296
11297
    SKIP_BLANKS;
11298
    if (CUR != ')') {
11299
        XP_ERROR(XPATH_EXPR_ERROR);
11300
    }
11301
    NEXT;
11302
    rangeto = 1;
11303
    goto eval_predicates;
11304
      }
11305
  }
11306
#endif
11307
4.95M
  if (CUR == '*') {
11308
245k
      axis = AXIS_CHILD;
11309
4.70M
  } else {
11310
4.70M
      if (name == NULL)
11311
4.70M
    name = xmlXPathParseNCName(ctxt);
11312
4.70M
      if (name != NULL) {
11313
4.70M
    axis = xmlXPathIsAxisName(name);
11314
4.70M
    if (axis != 0) {
11315
503
        SKIP_BLANKS;
11316
503
        if ((CUR == ':') && (NXT(1) == ':')) {
11317
503
      SKIP(2);
11318
503
      xmlFree(name);
11319
503
      name = NULL;
11320
503
        } else {
11321
      /* an element name can conflict with an axis one :-\ */
11322
0
      axis = AXIS_CHILD;
11323
0
        }
11324
4.70M
    } else {
11325
4.70M
        axis = AXIS_CHILD;
11326
4.70M
    }
11327
4.70M
      } else if (CUR == '@') {
11328
103
    NEXT;
11329
103
    axis = AXIS_ATTRIBUTE;
11330
128
      } else {
11331
128
    axis = AXIS_CHILD;
11332
128
      }
11333
4.70M
  }
11334
11335
4.95M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11336
5.05k
            xmlFree(name);
11337
5.05k
            return;
11338
5.05k
        }
11339
11340
4.94M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11341
4.94M
  if (test == 0)
11342
80
      return;
11343
11344
4.94M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11345
4.94M
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11346
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11347
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11348
0
      }
11349
0
  }
11350
#ifdef DEBUG_STEP
11351
  xmlGenericError(xmlGenericErrorContext,
11352
    "Basis : computing new set\n");
11353
#endif
11354
11355
#ifdef DEBUG_STEP
11356
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11357
  if (ctxt->value == NULL)
11358
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11359
  else if (ctxt->value->nodesetval == NULL)
11360
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11361
  else
11362
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11363
#endif
11364
11365
#ifdef LIBXML_XPTR_LOCS_ENABLED
11366
eval_predicates:
11367
#endif
11368
4.94M
  op1 = ctxt->comp->last;
11369
4.94M
  ctxt->comp->last = -1;
11370
11371
4.94M
  SKIP_BLANKS;
11372
4.94M
  while (CUR == '[') {
11373
141
      xmlXPathCompPredicate(ctxt, 0);
11374
141
  }
11375
11376
#ifdef LIBXML_XPTR_LOCS_ENABLED
11377
  if (rangeto) {
11378
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11379
  } else
11380
#endif
11381
4.94M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11382
4.94M
                           test, type, (void *)prefix, (void *)name) == -1) {
11383
1
            xmlFree(prefix);
11384
1
            xmlFree(name);
11385
1
        }
11386
4.94M
    }
11387
#ifdef DEBUG_STEP
11388
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11389
    if (ctxt->value == NULL)
11390
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11391
    else if (ctxt->value->nodesetval == NULL)
11392
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11393
    else
11394
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11395
    ctxt->value->nodesetval);
11396
#endif
11397
4.95M
}
11398
11399
/**
11400
 * xmlXPathCompRelativeLocationPath:
11401
 * @ctxt:  the XPath Parser context
11402
 *
11403
 *  [3]   RelativeLocationPath ::=   Step
11404
 *                     | RelativeLocationPath '/' Step
11405
 *                     | AbbreviatedRelativeLocationPath
11406
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11407
 *
11408
 * Compile a relative location path.
11409
 */
11410
static void
11411
xmlXPathCompRelativeLocationPath
11412
4.21M
(xmlXPathParserContextPtr ctxt) {
11413
4.21M
    SKIP_BLANKS;
11414
4.21M
    if ((CUR == '/') && (NXT(1) == '/')) {
11415
3
  SKIP(2);
11416
3
  SKIP_BLANKS;
11417
3
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11418
3
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11419
4.21M
    } else if (CUR == '/') {
11420
308
      NEXT;
11421
308
  SKIP_BLANKS;
11422
308
    }
11423
4.21M
    xmlXPathCompStep(ctxt);
11424
4.21M
    CHECK_ERROR;
11425
4.20M
    SKIP_BLANKS;
11426
4.94M
    while (CUR == '/') {
11427
738k
  if ((CUR == '/') && (NXT(1) == '/')) {
11428
88
      SKIP(2);
11429
88
      SKIP_BLANKS;
11430
88
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11431
88
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11432
88
      xmlXPathCompStep(ctxt);
11433
738k
  } else if (CUR == '/') {
11434
738k
      NEXT;
11435
738k
      SKIP_BLANKS;
11436
738k
      xmlXPathCompStep(ctxt);
11437
738k
  }
11438
738k
  SKIP_BLANKS;
11439
738k
    }
11440
4.20M
}
11441
11442
/**
11443
 * xmlXPathCompLocationPath:
11444
 * @ctxt:  the XPath Parser context
11445
 *
11446
 *  [1]   LocationPath ::=   RelativeLocationPath
11447
 *                     | AbsoluteLocationPath
11448
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11449
 *                     | AbbreviatedAbsoluteLocationPath
11450
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11451
 *                           '//' RelativeLocationPath
11452
 *
11453
 * Compile a location path
11454
 *
11455
 * // is short for /descendant-or-self::node()/. For example,
11456
 * //para is short for /descendant-or-self::node()/child::para and
11457
 * so will select any para element in the document (even a para element
11458
 * that is a document element will be selected by //para since the
11459
 * document element node is a child of the root node); div//para is
11460
 * short for div/descendant-or-self::node()/child::para and so will
11461
 * select all para descendants of div children.
11462
 */
11463
static void
11464
4.21M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11465
4.21M
    SKIP_BLANKS;
11466
4.21M
    if (CUR != '/') {
11467
4.21M
        xmlXPathCompRelativeLocationPath(ctxt);
11468
4.21M
    } else {
11469
13.3k
  while (CUR == '/') {
11470
6.70k
      if ((CUR == '/') && (NXT(1) == '/')) {
11471
787
    SKIP(2);
11472
787
    SKIP_BLANKS;
11473
787
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11474
787
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11475
787
    xmlXPathCompRelativeLocationPath(ctxt);
11476
5.91k
      } else if (CUR == '/') {
11477
5.91k
    NEXT;
11478
5.91k
    SKIP_BLANKS;
11479
5.91k
    if ((CUR != 0 ) &&
11480
5.91k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11481
5.91k
         (CUR == '@') || (CUR == '*')))
11482
533
        xmlXPathCompRelativeLocationPath(ctxt);
11483
5.91k
      }
11484
6.70k
      CHECK_ERROR;
11485
6.70k
  }
11486
6.70k
    }
11487
4.21M
}
11488
11489
/************************************************************************
11490
 *                  *
11491
 *    XPath precompiled expression evaluation     *
11492
 *                  *
11493
 ************************************************************************/
11494
11495
static int
11496
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11497
11498
#ifdef DEBUG_STEP
11499
static void
11500
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11501
        int nbNodes)
11502
{
11503
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11504
    switch (op->value) {
11505
        case AXIS_ANCESTOR:
11506
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11507
            break;
11508
        case AXIS_ANCESTOR_OR_SELF:
11509
            xmlGenericError(xmlGenericErrorContext,
11510
                            "axis 'ancestors-or-self' ");
11511
            break;
11512
        case AXIS_ATTRIBUTE:
11513
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11514
            break;
11515
        case AXIS_CHILD:
11516
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11517
            break;
11518
        case AXIS_DESCENDANT:
11519
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11520
            break;
11521
        case AXIS_DESCENDANT_OR_SELF:
11522
            xmlGenericError(xmlGenericErrorContext,
11523
                            "axis 'descendant-or-self' ");
11524
            break;
11525
        case AXIS_FOLLOWING:
11526
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11527
            break;
11528
        case AXIS_FOLLOWING_SIBLING:
11529
            xmlGenericError(xmlGenericErrorContext,
11530
                            "axis 'following-siblings' ");
11531
            break;
11532
        case AXIS_NAMESPACE:
11533
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11534
            break;
11535
        case AXIS_PARENT:
11536
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11537
            break;
11538
        case AXIS_PRECEDING:
11539
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11540
            break;
11541
        case AXIS_PRECEDING_SIBLING:
11542
            xmlGenericError(xmlGenericErrorContext,
11543
                            "axis 'preceding-sibling' ");
11544
            break;
11545
        case AXIS_SELF:
11546
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11547
            break;
11548
    }
11549
    xmlGenericError(xmlGenericErrorContext,
11550
  " context contains %d nodes\n", nbNodes);
11551
    switch (op->value2) {
11552
        case NODE_TEST_NONE:
11553
            xmlGenericError(xmlGenericErrorContext,
11554
                            "           searching for none !!!\n");
11555
            break;
11556
        case NODE_TEST_TYPE:
11557
            xmlGenericError(xmlGenericErrorContext,
11558
                            "           searching for type %d\n", op->value3);
11559
            break;
11560
        case NODE_TEST_PI:
11561
            xmlGenericError(xmlGenericErrorContext,
11562
                            "           searching for PI !!!\n");
11563
            break;
11564
        case NODE_TEST_ALL:
11565
            xmlGenericError(xmlGenericErrorContext,
11566
                            "           searching for *\n");
11567
            break;
11568
        case NODE_TEST_NS:
11569
            xmlGenericError(xmlGenericErrorContext,
11570
                            "           searching for namespace %s\n",
11571
                            op->value5);
11572
            break;
11573
        case NODE_TEST_NAME:
11574
            xmlGenericError(xmlGenericErrorContext,
11575
                            "           searching for name %s\n", op->value5);
11576
            if (op->value4)
11577
                xmlGenericError(xmlGenericErrorContext,
11578
                                "           with namespace %s\n", op->value4);
11579
            break;
11580
    }
11581
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11582
}
11583
#endif /* DEBUG_STEP */
11584
11585
/**
11586
 * xmlXPathNodeSetFilter:
11587
 * @ctxt:  the XPath Parser context
11588
 * @set: the node set to filter
11589
 * @filterOpIndex: the index of the predicate/filter op
11590
 * @minPos: minimum position in the filtered set (1-based)
11591
 * @maxPos: maximum position in the filtered set (1-based)
11592
 * @hasNsNodes: true if the node set may contain namespace nodes
11593
 *
11594
 * Filter a node set, keeping only nodes for which the predicate expression
11595
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11596
 * filtered result.
11597
 */
11598
static void
11599
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11600
          xmlNodeSetPtr set,
11601
          int filterOpIndex,
11602
                      int minPos, int maxPos,
11603
          int hasNsNodes)
11604
18.4k
{
11605
18.4k
    xmlXPathContextPtr xpctxt;
11606
18.4k
    xmlNodePtr oldnode;
11607
18.4k
    xmlDocPtr olddoc;
11608
18.4k
    xmlXPathStepOpPtr filterOp;
11609
18.4k
    int oldcs, oldpp;
11610
18.4k
    int i, j, pos;
11611
11612
18.4k
    if ((set == NULL) || (set->nodeNr == 0))
11613
23
        return;
11614
11615
    /*
11616
    * Check if the node set contains a sufficient number of nodes for
11617
    * the requested range.
11618
    */
11619
18.4k
    if (set->nodeNr < minPos) {
11620
0
        xmlXPathNodeSetClear(set, hasNsNodes);
11621
0
        return;
11622
0
    }
11623
11624
18.4k
    xpctxt = ctxt->context;
11625
18.4k
    oldnode = xpctxt->node;
11626
18.4k
    olddoc = xpctxt->doc;
11627
18.4k
    oldcs = xpctxt->contextSize;
11628
18.4k
    oldpp = xpctxt->proximityPosition;
11629
18.4k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11630
11631
18.4k
    xpctxt->contextSize = set->nodeNr;
11632
11633
639k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11634
624k
        xmlNodePtr node = set->nodeTab[i];
11635
624k
        int res;
11636
11637
624k
        xpctxt->node = node;
11638
624k
        xpctxt->proximityPosition = i + 1;
11639
11640
        /*
11641
        * Also set the xpath document in case things like
11642
        * key() are evaluated in the predicate.
11643
        *
11644
        * TODO: Get real doc for namespace nodes.
11645
        */
11646
624k
        if ((node->type != XML_NAMESPACE_DECL) &&
11647
624k
            (node->doc != NULL))
11648
620k
            xpctxt->doc = node->doc;
11649
11650
624k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11651
11652
624k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11653
63
            break;
11654
624k
        if (res < 0) {
11655
            /* Shouldn't happen */
11656
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11657
0
            break;
11658
0
        }
11659
11660
624k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11661
8.01k
            if (i != j) {
11662
420
                set->nodeTab[j] = node;
11663
420
                set->nodeTab[i] = NULL;
11664
420
            }
11665
11666
8.01k
            j += 1;
11667
616k
        } else {
11668
            /* Remove the entry from the initial node set. */
11669
616k
            set->nodeTab[i] = NULL;
11670
616k
            if (node->type == XML_NAMESPACE_DECL)
11671
231
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11672
616k
        }
11673
11674
624k
        if (res != 0) {
11675
8.01k
            if (pos == maxPos) {
11676
3.23k
                i += 1;
11677
3.23k
                break;
11678
3.23k
            }
11679
11680
4.78k
            pos += 1;
11681
4.78k
        }
11682
624k
    }
11683
11684
    /* Free remaining nodes. */
11685
18.4k
    if (hasNsNodes) {
11686
774k
        for (; i < set->nodeNr; i++) {
11687
774k
            xmlNodePtr node = set->nodeTab[i];
11688
774k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11689
12
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11690
774k
        }
11691
376
    }
11692
11693
18.4k
    set->nodeNr = j;
11694
11695
    /* If too many elements were removed, shrink table to preserve memory. */
11696
18.4k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11697
18.4k
        (set->nodeNr < set->nodeMax / 2)) {
11698
7.84k
        xmlNodePtr *tmp;
11699
7.84k
        int nodeMax = set->nodeNr;
11700
11701
7.84k
        if (nodeMax < XML_NODESET_DEFAULT)
11702
7.83k
            nodeMax = XML_NODESET_DEFAULT;
11703
7.84k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11704
7.84k
                nodeMax * sizeof(xmlNodePtr));
11705
7.84k
        if (tmp == NULL) {
11706
20
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11707
7.82k
        } else {
11708
7.82k
            set->nodeTab = tmp;
11709
7.82k
            set->nodeMax = nodeMax;
11710
7.82k
        }
11711
7.84k
    }
11712
11713
18.4k
    xpctxt->node = oldnode;
11714
18.4k
    xpctxt->doc = olddoc;
11715
18.4k
    xpctxt->contextSize = oldcs;
11716
18.4k
    xpctxt->proximityPosition = oldpp;
11717
18.4k
}
11718
11719
#ifdef LIBXML_XPTR_LOCS_ENABLED
11720
/**
11721
 * xmlXPathLocationSetFilter:
11722
 * @ctxt:  the XPath Parser context
11723
 * @locset: the location set to filter
11724
 * @filterOpIndex: the index of the predicate/filter op
11725
 * @minPos: minimum position in the filtered set (1-based)
11726
 * @maxPos: maximum position in the filtered set (1-based)
11727
 *
11728
 * Filter a location set, keeping only nodes for which the predicate
11729
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11730
 * in the filtered result.
11731
 */
11732
static void
11733
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11734
              xmlLocationSetPtr locset,
11735
              int filterOpIndex,
11736
                          int minPos, int maxPos)
11737
{
11738
    xmlXPathContextPtr xpctxt;
11739
    xmlNodePtr oldnode;
11740
    xmlDocPtr olddoc;
11741
    xmlXPathStepOpPtr filterOp;
11742
    int oldcs, oldpp;
11743
    int i, j, pos;
11744
11745
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11746
        return;
11747
11748
    xpctxt = ctxt->context;
11749
    oldnode = xpctxt->node;
11750
    olddoc = xpctxt->doc;
11751
    oldcs = xpctxt->contextSize;
11752
    oldpp = xpctxt->proximityPosition;
11753
    filterOp = &ctxt->comp->steps[filterOpIndex];
11754
11755
    xpctxt->contextSize = locset->locNr;
11756
11757
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11758
        xmlNodePtr contextNode = locset->locTab[i]->user;
11759
        int res;
11760
11761
        xpctxt->node = contextNode;
11762
        xpctxt->proximityPosition = i + 1;
11763
11764
        /*
11765
        * Also set the xpath document in case things like
11766
        * key() are evaluated in the predicate.
11767
        *
11768
        * TODO: Get real doc for namespace nodes.
11769
        */
11770
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11771
            (contextNode->doc != NULL))
11772
            xpctxt->doc = contextNode->doc;
11773
11774
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11775
11776
        if (ctxt->error != XPATH_EXPRESSION_OK)
11777
            break;
11778
        if (res < 0) {
11779
            /* Shouldn't happen */
11780
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11781
            break;
11782
        }
11783
11784
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11785
            if (i != j) {
11786
                locset->locTab[j] = locset->locTab[i];
11787
                locset->locTab[i] = NULL;
11788
            }
11789
11790
            j += 1;
11791
        } else {
11792
            /* Remove the entry from the initial location set. */
11793
            xmlXPathFreeObject(locset->locTab[i]);
11794
            locset->locTab[i] = NULL;
11795
        }
11796
11797
        if (res != 0) {
11798
            if (pos == maxPos) {
11799
                i += 1;
11800
                break;
11801
            }
11802
11803
            pos += 1;
11804
        }
11805
    }
11806
11807
    /* Free remaining nodes. */
11808
    for (; i < locset->locNr; i++)
11809
        xmlXPathFreeObject(locset->locTab[i]);
11810
11811
    locset->locNr = j;
11812
11813
    /* If too many elements were removed, shrink table to preserve memory. */
11814
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11815
        (locset->locNr < locset->locMax / 2)) {
11816
        xmlXPathObjectPtr *tmp;
11817
        int locMax = locset->locNr;
11818
11819
        if (locMax < XML_NODESET_DEFAULT)
11820
            locMax = XML_NODESET_DEFAULT;
11821
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11822
                locMax * sizeof(xmlXPathObjectPtr));
11823
        if (tmp == NULL) {
11824
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11825
        } else {
11826
            locset->locTab = tmp;
11827
            locset->locMax = locMax;
11828
        }
11829
    }
11830
11831
    xpctxt->node = oldnode;
11832
    xpctxt->doc = olddoc;
11833
    xpctxt->contextSize = oldcs;
11834
    xpctxt->proximityPosition = oldpp;
11835
}
11836
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11837
11838
/**
11839
 * xmlXPathCompOpEvalPredicate:
11840
 * @ctxt:  the XPath Parser context
11841
 * @op: the predicate op
11842
 * @set: the node set to filter
11843
 * @minPos: minimum position in the filtered set (1-based)
11844
 * @maxPos: maximum position in the filtered set (1-based)
11845
 * @hasNsNodes: true if the node set may contain namespace nodes
11846
 *
11847
 * Filter a node set, keeping only nodes for which the sequence of predicate
11848
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11849
 * in the filtered result.
11850
 */
11851
static void
11852
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11853
          xmlXPathStepOpPtr op,
11854
          xmlNodeSetPtr set,
11855
                            int minPos, int maxPos,
11856
          int hasNsNodes)
11857
18.1k
{
11858
18.1k
    if (op->ch1 != -1) {
11859
131
  xmlXPathCompExprPtr comp = ctxt->comp;
11860
  /*
11861
  * Process inner predicates first.
11862
  */
11863
131
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11864
0
            xmlGenericError(xmlGenericErrorContext,
11865
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11866
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11867
0
  }
11868
131
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11869
131
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11870
131
        ctxt->context->depth += 1;
11871
131
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11872
131
                                    1, set->nodeNr, hasNsNodes);
11873
131
        ctxt->context->depth -= 1;
11874
131
  CHECK_ERROR;
11875
131
    }
11876
11877
18.1k
    if (op->ch2 != -1)
11878
18.1k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11879
18.1k
}
11880
11881
static int
11882
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11883
          xmlXPathStepOpPtr op,
11884
          int *maxPos)
11885
1.96k
{
11886
11887
1.96k
    xmlXPathStepOpPtr exprOp;
11888
11889
    /*
11890
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11891
    */
11892
11893
    /*
11894
    * If not -1, then ch1 will point to:
11895
    * 1) For predicates (XPATH_OP_PREDICATE):
11896
    *    - an inner predicate operator
11897
    * 2) For filters (XPATH_OP_FILTER):
11898
    *    - an inner filter operator OR
11899
    *    - an expression selecting the node set.
11900
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11901
    */
11902
1.96k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11903
0
  return(0);
11904
11905
1.96k
    if (op->ch2 != -1) {
11906
1.96k
  exprOp = &ctxt->comp->steps[op->ch2];
11907
1.96k
    } else
11908
0
  return(0);
11909
11910
1.96k
    if ((exprOp != NULL) &&
11911
1.96k
  (exprOp->op == XPATH_OP_VALUE) &&
11912
1.96k
  (exprOp->value4 != NULL) &&
11913
1.96k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11914
0
    {
11915
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11916
11917
  /*
11918
  * We have a "[n]" predicate here.
11919
  * TODO: Unfortunately this simplistic test here is not
11920
  * able to detect a position() predicate in compound
11921
  * expressions like "[@attr = 'a" and position() = 1],
11922
  * and even not the usage of position() in
11923
  * "[position() = 1]"; thus - obviously - a position-range,
11924
  * like it "[position() < 5]", is also not detected.
11925
  * Maybe we could rewrite the AST to ease the optimization.
11926
  */
11927
11928
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11929
0
      *maxPos = (int) floatval;
11930
0
            if (floatval == (double) *maxPos)
11931
0
                return(1);
11932
0
        }
11933
0
    }
11934
1.96k
    return(0);
11935
1.96k
}
11936
11937
static int
11938
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11939
                           xmlXPathStepOpPtr op,
11940
         xmlNodePtr * first, xmlNodePtr * last,
11941
         int toBool)
11942
401k
{
11943
11944
401k
#define XP_TEST_HIT \
11945
9.93M
    if (hasAxisRange != 0) { \
11946
0
  if (++pos == maxPos) { \
11947
0
      if (addNode(seq, cur) < 0) \
11948
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11949
0
      goto axis_range_end; } \
11950
9.93M
    } else { \
11951
9.93M
  if (addNode(seq, cur) < 0) \
11952
9.93M
      ctxt->error = XPATH_MEMORY_ERROR; \
11953
9.93M
  if (breakOnFirstHit) goto first_hit; }
11954
11955
401k
#define XP_TEST_HIT_NS \
11956
401k
    if (hasAxisRange != 0) { \
11957
0
  if (++pos == maxPos) { \
11958
0
      hasNsNodes = 1; \
11959
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11960
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11961
0
  goto axis_range_end; } \
11962
358k
    } else { \
11963
358k
  hasNsNodes = 1; \
11964
358k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11965
358k
      ctxt->error = XPATH_MEMORY_ERROR; \
11966
358k
  if (breakOnFirstHit) goto first_hit; }
11967
11968
401k
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11969
401k
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11970
401k
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11971
401k
    const xmlChar *prefix = op->value4;
11972
401k
    const xmlChar *name = op->value5;
11973
401k
    const xmlChar *URI = NULL;
11974
11975
#ifdef DEBUG_STEP
11976
    int nbMatches = 0, prevMatches = 0;
11977
#endif
11978
401k
    int total = 0, hasNsNodes = 0;
11979
    /* The popped object holding the context nodes */
11980
401k
    xmlXPathObjectPtr obj;
11981
    /* The set of context nodes for the node tests */
11982
401k
    xmlNodeSetPtr contextSeq;
11983
401k
    int contextIdx;
11984
401k
    xmlNodePtr contextNode;
11985
    /* The final resulting node set wrt to all context nodes */
11986
401k
    xmlNodeSetPtr outSeq;
11987
    /*
11988
    * The temporary resulting node set wrt 1 context node.
11989
    * Used to feed predicate evaluation.
11990
    */
11991
401k
    xmlNodeSetPtr seq;
11992
401k
    xmlNodePtr cur;
11993
    /* First predicate operator */
11994
401k
    xmlXPathStepOpPtr predOp;
11995
401k
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11996
401k
    int hasPredicateRange, hasAxisRange, pos;
11997
401k
    int breakOnFirstHit;
11998
11999
401k
    xmlXPathTraversalFunction next = NULL;
12000
401k
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12001
401k
    xmlXPathNodeSetMergeFunction mergeAndClear;
12002
401k
    xmlNodePtr oldContextNode;
12003
401k
    xmlXPathContextPtr xpctxt = ctxt->context;
12004
12005
12006
401k
    CHECK_TYPE0(XPATH_NODESET);
12007
401k
    obj = valuePop(ctxt);
12008
    /*
12009
    * Setup namespaces.
12010
    */
12011
401k
    if (prefix != NULL) {
12012
121k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12013
121k
        if (URI == NULL) {
12014
3
      xmlXPathReleaseObject(xpctxt, obj);
12015
3
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12016
0
  }
12017
121k
    }
12018
    /*
12019
    * Setup axis.
12020
    *
12021
    * MAYBE FUTURE TODO: merging optimizations:
12022
    * - If the nodes to be traversed wrt to the initial nodes and
12023
    *   the current axis cannot overlap, then we could avoid searching
12024
    *   for duplicates during the merge.
12025
    *   But the question is how/when to evaluate if they cannot overlap.
12026
    *   Example: if we know that for two initial nodes, the one is
12027
    *   not in the ancestor-or-self axis of the other, then we could safely
12028
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12029
    *   the descendant-or-self axis.
12030
    */
12031
401k
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12032
401k
    switch (axis) {
12033
352
        case AXIS_ANCESTOR:
12034
352
            first = NULL;
12035
352
            next = xmlXPathNextAncestor;
12036
352
            break;
12037
0
        case AXIS_ANCESTOR_OR_SELF:
12038
0
            first = NULL;
12039
0
            next = xmlXPathNextAncestorOrSelf;
12040
0
            break;
12041
200k
        case AXIS_ATTRIBUTE:
12042
200k
            first = NULL;
12043
200k
      last = NULL;
12044
200k
            next = xmlXPathNextAttribute;
12045
200k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12046
200k
            break;
12047
186k
        case AXIS_CHILD:
12048
186k
      last = NULL;
12049
186k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12050
186k
    (type == NODE_TYPE_NODE))
12051
186k
      {
12052
    /*
12053
    * Optimization if an element node type is 'element'.
12054
    */
12055
186k
    next = xmlXPathNextChildElement;
12056
186k
      } else
12057
73
    next = xmlXPathNextChild;
12058
186k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12059
186k
            break;
12060
6.52k
        case AXIS_DESCENDANT:
12061
6.52k
      last = NULL;
12062
6.52k
            next = xmlXPathNextDescendant;
12063
6.52k
            break;
12064
1.48k
        case AXIS_DESCENDANT_OR_SELF:
12065
1.48k
      last = NULL;
12066
1.48k
            next = xmlXPathNextDescendantOrSelf;
12067
1.48k
            break;
12068
0
        case AXIS_FOLLOWING:
12069
0
      last = NULL;
12070
0
            next = xmlXPathNextFollowing;
12071
0
            break;
12072
0
        case AXIS_FOLLOWING_SIBLING:
12073
0
      last = NULL;
12074
0
            next = xmlXPathNextFollowingSibling;
12075
0
            break;
12076
424
        case AXIS_NAMESPACE:
12077
424
            first = NULL;
12078
424
      last = NULL;
12079
424
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12080
424
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081
424
            break;
12082
3.21k
        case AXIS_PARENT:
12083
3.21k
            first = NULL;
12084
3.21k
            next = xmlXPathNextParent;
12085
3.21k
            break;
12086
2.44k
        case AXIS_PRECEDING:
12087
2.44k
            first = NULL;
12088
2.44k
            next = xmlXPathNextPrecedingInternal;
12089
2.44k
            break;
12090
25
        case AXIS_PRECEDING_SIBLING:
12091
25
            first = NULL;
12092
25
            next = xmlXPathNextPrecedingSibling;
12093
25
            break;
12094
0
        case AXIS_SELF:
12095
0
            first = NULL;
12096
0
      last = NULL;
12097
0
            next = xmlXPathNextSelf;
12098
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12099
0
            break;
12100
401k
    }
12101
12102
#ifdef DEBUG_STEP
12103
    xmlXPathDebugDumpStepAxis(op,
12104
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12105
#endif
12106
12107
401k
    if (next == NULL) {
12108
0
  xmlXPathReleaseObject(xpctxt, obj);
12109
0
        return(0);
12110
0
    }
12111
401k
    contextSeq = obj->nodesetval;
12112
401k
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12113
20.7k
  xmlXPathReleaseObject(xpctxt, obj);
12114
20.7k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12115
20.7k
        return(0);
12116
20.7k
    }
12117
    /*
12118
    * Predicate optimization ---------------------------------------------
12119
    * If this step has a last predicate, which contains a position(),
12120
    * then we'll optimize (although not exactly "position()", but only
12121
    * the  short-hand form, i.e., "[n]".
12122
    *
12123
    * Example - expression "/foo[parent::bar][1]":
12124
    *
12125
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12126
    *   ROOT                               -- op->ch1
12127
    *   PREDICATE                          -- op->ch2 (predOp)
12128
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12129
    *       SORT
12130
    *         COLLECT  'parent' 'name' 'node' bar
12131
    *           NODE
12132
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12133
    *
12134
    */
12135
380k
    maxPos = 0;
12136
380k
    predOp = NULL;
12137
380k
    hasPredicateRange = 0;
12138
380k
    hasAxisRange = 0;
12139
380k
    if (op->ch2 != -1) {
12140
  /*
12141
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12142
  */
12143
1.96k
  predOp = &ctxt->comp->steps[op->ch2];
12144
1.96k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12145
0
      if (predOp->ch1 != -1) {
12146
    /*
12147
    * Use the next inner predicate operator.
12148
    */
12149
0
    predOp = &ctxt->comp->steps[predOp->ch1];
12150
0
    hasPredicateRange = 1;
12151
0
      } else {
12152
    /*
12153
    * There's no other predicate than the [n] predicate.
12154
    */
12155
0
    predOp = NULL;
12156
0
    hasAxisRange = 1;
12157
0
      }
12158
0
  }
12159
1.96k
    }
12160
380k
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12161
    /*
12162
    * Axis traversal -----------------------------------------------------
12163
    */
12164
    /*
12165
     * 2.3 Node Tests
12166
     *  - For the attribute axis, the principal node type is attribute.
12167
     *  - For the namespace axis, the principal node type is namespace.
12168
     *  - For other axes, the principal node type is element.
12169
     *
12170
     * A node test * is true for any node of the
12171
     * principal node type. For example, child::* will
12172
     * select all element children of the context node
12173
     */
12174
380k
    oldContextNode = xpctxt->node;
12175
380k
    addNode = xmlXPathNodeSetAddUnique;
12176
380k
    outSeq = NULL;
12177
380k
    seq = NULL;
12178
380k
    contextNode = NULL;
12179
380k
    contextIdx = 0;
12180
12181
12182
1.62M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12183
1.62M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12184
1.23M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12185
12186
1.23M
  if (seq == NULL) {
12187
382k
      seq = xmlXPathNodeSetCreate(NULL);
12188
382k
      if (seq == NULL) {
12189
                /* TODO: Propagate memory error. */
12190
3
    total = 0;
12191
3
    goto error;
12192
3
      }
12193
382k
  }
12194
  /*
12195
  * Traverse the axis and test the nodes.
12196
  */
12197
1.23M
  pos = 0;
12198
1.23M
  cur = NULL;
12199
1.23M
  hasNsNodes = 0;
12200
12.5M
        do {
12201
12.5M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12202
17
                goto error;
12203
12204
12.5M
            cur = next(ctxt, cur);
12205
12.5M
            if (cur == NULL)
12206
1.23M
                break;
12207
12208
      /*
12209
      * QUESTION TODO: What does the "first" and "last" stuff do?
12210
      */
12211
11.3M
            if ((first != NULL) && (*first != NULL)) {
12212
0
    if (*first == cur)
12213
0
        break;
12214
0
    if (((total % 256) == 0) &&
12215
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12216
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12217
#else
12218
        (xmlXPathCmpNodes(*first, cur) >= 0))
12219
#endif
12220
0
    {
12221
0
        break;
12222
0
    }
12223
0
      }
12224
11.3M
      if ((last != NULL) && (*last != NULL)) {
12225
0
    if (*last == cur)
12226
0
        break;
12227
0
    if (((total % 256) == 0) &&
12228
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12229
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12230
#else
12231
        (xmlXPathCmpNodes(cur, *last) >= 0))
12232
#endif
12233
0
    {
12234
0
        break;
12235
0
    }
12236
0
      }
12237
12238
11.3M
            total++;
12239
12240
#ifdef DEBUG_STEP
12241
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12242
#endif
12243
12244
11.3M
      switch (test) {
12245
0
                case NODE_TEST_NONE:
12246
0
        total = 0;
12247
0
                    STRANGE
12248
0
        goto error;
12249
9.46M
                case NODE_TEST_TYPE:
12250
9.46M
        if (type == NODE_TYPE_NODE) {
12251
9.34M
      switch (cur->type) {
12252
175k
          case XML_DOCUMENT_NODE:
12253
175k
          case XML_HTML_DOCUMENT_NODE:
12254
6.87M
          case XML_ELEMENT_NODE:
12255
6.92M
          case XML_ATTRIBUTE_NODE:
12256
6.93M
          case XML_PI_NODE:
12257
6.99M
          case XML_COMMENT_NODE:
12258
6.99M
          case XML_CDATA_SECTION_NODE:
12259
9.32M
          case XML_TEXT_NODE:
12260
9.32M
        XP_TEST_HIT
12261
9.32M
        break;
12262
9.32M
          case XML_NAMESPACE_DECL: {
12263
3.49k
        if (axis == AXIS_NAMESPACE) {
12264
0
            XP_TEST_HIT_NS
12265
3.49k
        } else {
12266
3.49k
                              hasNsNodes = 1;
12267
3.49k
            XP_TEST_HIT
12268
3.49k
        }
12269
3.49k
        break;
12270
3.49k
                            }
12271
13.1k
          default:
12272
13.1k
        break;
12273
9.34M
      }
12274
9.34M
        } else if (cur->type == (xmlElementType) type) {
12275
9.61k
      if (cur->type == XML_NAMESPACE_DECL)
12276
0
          XP_TEST_HIT_NS
12277
9.61k
      else
12278
9.61k
          XP_TEST_HIT
12279
111k
        } else if ((type == NODE_TYPE_TEXT) &&
12280
111k
       (cur->type == XML_CDATA_SECTION_NODE))
12281
0
        {
12282
0
      XP_TEST_HIT
12283
0
        }
12284
9.46M
        break;
12285
9.46M
                case NODE_TEST_PI:
12286
0
                    if ((cur->type == XML_PI_NODE) &&
12287
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12288
0
        {
12289
0
      XP_TEST_HIT
12290
0
                    }
12291
0
                    break;
12292
1.19M
                case NODE_TEST_ALL:
12293
1.19M
                    if (axis == AXIS_ATTRIBUTE) {
12294
62.9k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12295
62.9k
      {
12296
62.9k
                            if (prefix == NULL)
12297
62.9k
          {
12298
62.9k
        XP_TEST_HIT
12299
62.9k
                            } else if ((cur->ns != NULL) &&
12300
0
        (xmlStrEqual(URI, cur->ns->href)))
12301
0
          {
12302
0
        XP_TEST_HIT
12303
0
                            }
12304
62.9k
                        }
12305
1.13M
                    } else if (axis == AXIS_NAMESPACE) {
12306
358k
                        if (cur->type == XML_NAMESPACE_DECL)
12307
358k
      {
12308
358k
          XP_TEST_HIT_NS
12309
358k
                        }
12310
772k
                    } else {
12311
772k
                        if (cur->type == XML_ELEMENT_NODE) {
12312
516k
                            if (prefix == NULL)
12313
516k
          {
12314
516k
        XP_TEST_HIT
12315
12316
516k
                            } else if ((cur->ns != NULL) &&
12317
1
        (xmlStrEqual(URI, cur->ns->href)))
12318
0
          {
12319
0
        XP_TEST_HIT
12320
0
                            }
12321
516k
                        }
12322
772k
                    }
12323
1.19M
                    break;
12324
1.19M
                case NODE_TEST_NS:{
12325
0
                        TODO;
12326
0
                        break;
12327
1.19M
                    }
12328
663k
                case NODE_TEST_NAME:
12329
663k
                    if (axis == AXIS_ATTRIBUTE) {
12330
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
12331
0
          break;
12332
663k
        } else if (axis == AXIS_NAMESPACE) {
12333
0
                        if (cur->type != XML_NAMESPACE_DECL)
12334
0
          break;
12335
663k
        } else {
12336
663k
            if (cur->type != XML_ELEMENT_NODE)
12337
89.2k
          break;
12338
663k
        }
12339
573k
                    switch (cur->type) {
12340
573k
                        case XML_ELEMENT_NODE:
12341
573k
                            if (xmlStrEqual(name, cur->name)) {
12342
13.2k
                                if (prefix == NULL) {
12343
13.2k
                                    if (cur->ns == NULL)
12344
13.2k
            {
12345
13.2k
          XP_TEST_HIT
12346
13.2k
                                    }
12347
13.2k
                                } else {
12348
0
                                    if ((cur->ns != NULL) &&
12349
0
                                        (xmlStrEqual(URI, cur->ns->href)))
12350
0
            {
12351
0
          XP_TEST_HIT
12352
0
                                    }
12353
0
                                }
12354
13.2k
                            }
12355
573k
                            break;
12356
573k
                        case XML_ATTRIBUTE_NODE:{
12357
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12358
12359
0
                                if (xmlStrEqual(name, attr->name)) {
12360
0
                                    if (prefix == NULL) {
12361
0
                                        if ((attr->ns == NULL) ||
12362
0
                                            (attr->ns->prefix == NULL))
12363
0
          {
12364
0
              XP_TEST_HIT
12365
0
                                        }
12366
0
                                    } else {
12367
0
                                        if ((attr->ns != NULL) &&
12368
0
                                            (xmlStrEqual(URI,
12369
0
                attr->ns->href)))
12370
0
          {
12371
0
              XP_TEST_HIT
12372
0
                                        }
12373
0
                                    }
12374
0
                                }
12375
0
                                break;
12376
0
                            }
12377
0
                        case XML_NAMESPACE_DECL:
12378
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12379
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12380
12381
0
                                if ((ns->prefix != NULL) && (name != NULL)
12382
0
                                    && (xmlStrEqual(ns->prefix, name)))
12383
0
        {
12384
0
            XP_TEST_HIT_NS
12385
0
                                }
12386
0
                            }
12387
0
                            break;
12388
0
                        default:
12389
0
                            break;
12390
573k
                    }
12391
573k
                    break;
12392
11.3M
      } /* switch(test) */
12393
11.3M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12394
12395
1.23M
  goto apply_predicates;
12396
12397
1.23M
axis_range_end: /* ----------------------------------------------------- */
12398
  /*
12399
  * We have a "/foo[n]", and position() = n was reached.
12400
  * Note that we can have as well "/foo/::parent::foo[1]", so
12401
  * a duplicate-aware merge is still needed.
12402
  * Merge with the result.
12403
  */
12404
0
  if (outSeq == NULL) {
12405
0
      outSeq = seq;
12406
0
      seq = NULL;
12407
0
  } else
12408
            /* TODO: Check memory error. */
12409
0
      outSeq = mergeAndClear(outSeq, seq);
12410
  /*
12411
  * Break if only a true/false result was requested.
12412
  */
12413
0
  if (toBool)
12414
0
      break;
12415
0
  continue;
12416
12417
0
first_hit: /* ---------------------------------------------------------- */
12418
  /*
12419
  * Break if only a true/false result was requested and
12420
  * no predicates existed and a node test succeeded.
12421
  */
12422
0
  if (outSeq == NULL) {
12423
0
      outSeq = seq;
12424
0
      seq = NULL;
12425
0
  } else
12426
            /* TODO: Check memory error. */
12427
0
      outSeq = mergeAndClear(outSeq, seq);
12428
0
  break;
12429
12430
#ifdef DEBUG_STEP
12431
  if (seq != NULL)
12432
      nbMatches += seq->nodeNr;
12433
#endif
12434
12435
1.23M
apply_predicates: /* --------------------------------------------------- */
12436
1.23M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12437
2
      goto error;
12438
12439
        /*
12440
  * Apply predicates.
12441
  */
12442
1.23M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12443
      /*
12444
      * E.g. when we have a "/foo[some expression][n]".
12445
      */
12446
      /*
12447
      * QUESTION TODO: The old predicate evaluation took into
12448
      *  account location-sets.
12449
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12450
      *  Do we expect such a set here?
12451
      *  All what I learned now from the evaluation semantics
12452
      *  does not indicate that a location-set will be processed
12453
      *  here, so this looks OK.
12454
      */
12455
      /*
12456
      * Iterate over all predicates, starting with the outermost
12457
      * predicate.
12458
      * TODO: Problem: we cannot execute the inner predicates first
12459
      *  since we cannot go back *up* the operator tree!
12460
      *  Options we have:
12461
      *  1) Use of recursive functions (like is it currently done
12462
      *     via xmlXPathCompOpEval())
12463
      *  2) Add a predicate evaluation information stack to the
12464
      *     context struct
12465
      *  3) Change the way the operators are linked; we need a
12466
      *     "parent" field on xmlXPathStepOp
12467
      *
12468
      * For the moment, I'll try to solve this with a recursive
12469
      * function: xmlXPathCompOpEvalPredicate().
12470
      */
12471
17.9k
      if (hasPredicateRange != 0)
12472
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12473
0
              hasNsNodes);
12474
17.9k
      else
12475
17.9k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12476
17.9k
              hasNsNodes);
12477
12478
17.9k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12479
38
    total = 0;
12480
38
    goto error;
12481
38
      }
12482
17.9k
        }
12483
12484
1.23M
        if (seq->nodeNr > 0) {
12485
      /*
12486
      * Add to result set.
12487
      */
12488
743k
      if (outSeq == NULL) {
12489
74.3k
    outSeq = seq;
12490
74.3k
    seq = NULL;
12491
668k
      } else {
12492
                /* TODO: Check memory error. */
12493
668k
    outSeq = mergeAndClear(outSeq, seq);
12494
668k
      }
12495
12496
743k
            if (toBool)
12497
0
                break;
12498
743k
  }
12499
1.23M
    }
12500
12501
380k
error:
12502
380k
    if ((obj->boolval) && (obj->user != NULL)) {
12503
  /*
12504
  * QUESTION TODO: What does this do and why?
12505
  * TODO: Do we have to do this also for the "error"
12506
  * cleanup further down?
12507
  */
12508
0
  ctxt->value->boolval = 1;
12509
0
  ctxt->value->user = obj->user;
12510
0
  obj->user = NULL;
12511
0
  obj->boolval = 0;
12512
0
    }
12513
380k
    xmlXPathReleaseObject(xpctxt, obj);
12514
12515
    /*
12516
    * Ensure we return at least an empty set.
12517
    */
12518
380k
    if (outSeq == NULL) {
12519
306k
  if ((seq != NULL) && (seq->nodeNr == 0))
12520
306k
      outSeq = seq;
12521
16
  else
12522
            /* TODO: Check memory error. */
12523
16
      outSeq = xmlXPathNodeSetCreate(NULL);
12524
306k
    }
12525
380k
    if ((seq != NULL) && (seq != outSeq)) {
12526
1.50k
   xmlXPathFreeNodeSet(seq);
12527
1.50k
    }
12528
    /*
12529
    * Hand over the result. Better to push the set also in
12530
    * case of errors.
12531
    */
12532
380k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12533
    /*
12534
    * Reset the context node.
12535
    */
12536
380k
    xpctxt->node = oldContextNode;
12537
    /*
12538
    * When traversing the namespace axis in "toBool" mode, it's
12539
    * possible that tmpNsList wasn't freed.
12540
    */
12541
380k
    if (xpctxt->tmpNsList != NULL) {
12542
1
        xmlFree(xpctxt->tmpNsList);
12543
1
        xpctxt->tmpNsList = NULL;
12544
1
    }
12545
12546
#ifdef DEBUG_STEP
12547
    xmlGenericError(xmlGenericErrorContext,
12548
  "\nExamined %d nodes, found %d nodes at that step\n",
12549
  total, nbMatches);
12550
#endif
12551
12552
380k
    return(total);
12553
380k
}
12554
12555
static int
12556
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12557
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12558
12559
/**
12560
 * xmlXPathCompOpEvalFirst:
12561
 * @ctxt:  the XPath parser context with the compiled expression
12562
 * @op:  an XPath compiled operation
12563
 * @first:  the first elem found so far
12564
 *
12565
 * Evaluate the Precompiled XPath operation searching only the first
12566
 * element in document order
12567
 *
12568
 * Returns the number of examined objects.
12569
 */
12570
static int
12571
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12572
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12573
4
{
12574
4
    int total = 0, cur;
12575
4
    xmlXPathCompExprPtr comp;
12576
4
    xmlXPathObjectPtr arg1, arg2;
12577
12578
4
    CHECK_ERROR0;
12579
4
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12580
0
        return(0);
12581
4
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12582
4
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12583
4
    ctxt->context->depth += 1;
12584
4
    comp = ctxt->comp;
12585
4
    switch (op->op) {
12586
0
        case XPATH_OP_END:
12587
0
            break;
12588
0
        case XPATH_OP_UNION:
12589
0
            total =
12590
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12591
0
                                        first);
12592
0
      CHECK_ERROR0;
12593
0
            if ((ctxt->value != NULL)
12594
0
                && (ctxt->value->type == XPATH_NODESET)
12595
0
                && (ctxt->value->nodesetval != NULL)
12596
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12597
                /*
12598
                 * limit tree traversing to first node in the result
12599
                 */
12600
    /*
12601
    * OPTIMIZE TODO: This implicitly sorts
12602
    *  the result, even if not needed. E.g. if the argument
12603
    *  of the count() function, no sorting is needed.
12604
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12605
    *  already sorted?
12606
    */
12607
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12608
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12609
0
                *first = ctxt->value->nodesetval->nodeTab[0];
12610
0
            }
12611
0
            cur =
12612
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12613
0
                                        first);
12614
0
      CHECK_ERROR0;
12615
12616
0
            arg2 = valuePop(ctxt);
12617
0
            arg1 = valuePop(ctxt);
12618
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12619
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12620
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12621
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12622
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12623
0
            }
12624
0
            if ((ctxt->context->opLimit != 0) &&
12625
0
                (((arg1->nodesetval != NULL) &&
12626
0
                  (xmlXPathCheckOpLimit(ctxt,
12627
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12628
0
                 ((arg2->nodesetval != NULL) &&
12629
0
                  (xmlXPathCheckOpLimit(ctxt,
12630
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12631
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12632
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12633
0
                break;
12634
0
            }
12635
12636
            /* TODO: Check memory error. */
12637
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12638
0
                                                    arg2->nodesetval);
12639
0
            valuePush(ctxt, arg1);
12640
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12641
            /* optimizer */
12642
0
      if (total > cur)
12643
0
    xmlXPathCompSwap(op);
12644
0
            total += cur;
12645
0
            break;
12646
0
        case XPATH_OP_ROOT:
12647
0
            xmlXPathRoot(ctxt);
12648
0
            break;
12649
0
        case XPATH_OP_NODE:
12650
0
            if (op->ch1 != -1)
12651
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12652
0
      CHECK_ERROR0;
12653
0
            if (op->ch2 != -1)
12654
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12655
0
      CHECK_ERROR0;
12656
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12657
0
    ctxt->context->node));
12658
0
            break;
12659
0
        case XPATH_OP_COLLECT:{
12660
0
                if (op->ch1 == -1)
12661
0
                    break;
12662
12663
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12664
0
    CHECK_ERROR0;
12665
12666
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12667
0
                break;
12668
0
            }
12669
0
        case XPATH_OP_VALUE:
12670
0
            valuePush(ctxt,
12671
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12672
0
      (xmlXPathObjectPtr) op->value4));
12673
0
            break;
12674
0
        case XPATH_OP_SORT:
12675
0
            if (op->ch1 != -1)
12676
0
                total +=
12677
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12678
0
                                            first);
12679
0
      CHECK_ERROR0;
12680
0
            if ((ctxt->value != NULL)
12681
0
                && (ctxt->value->type == XPATH_NODESET)
12682
0
                && (ctxt->value->nodesetval != NULL)
12683
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12684
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12685
0
            break;
12686
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12687
4
  case XPATH_OP_FILTER:
12688
4
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12689
4
            break;
12690
0
#endif
12691
0
        default:
12692
0
            total += xmlXPathCompOpEval(ctxt, op);
12693
0
            break;
12694
4
    }
12695
12696
4
    ctxt->context->depth -= 1;
12697
4
    return(total);
12698
4
}
12699
12700
/**
12701
 * xmlXPathCompOpEvalLast:
12702
 * @ctxt:  the XPath parser context with the compiled expression
12703
 * @op:  an XPath compiled operation
12704
 * @last:  the last elem found so far
12705
 *
12706
 * Evaluate the Precompiled XPath operation searching only the last
12707
 * element in document order
12708
 *
12709
 * Returns the number of nodes traversed
12710
 */
12711
static int
12712
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12713
                       xmlNodePtr * last)
12714
631
{
12715
631
    int total = 0, cur;
12716
631
    xmlXPathCompExprPtr comp;
12717
631
    xmlXPathObjectPtr arg1, arg2;
12718
12719
631
    CHECK_ERROR0;
12720
631
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12721
0
        return(0);
12722
631
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12723
631
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12724
631
    ctxt->context->depth += 1;
12725
631
    comp = ctxt->comp;
12726
631
    switch (op->op) {
12727
0
        case XPATH_OP_END:
12728
0
            break;
12729
334
        case XPATH_OP_UNION:
12730
334
            total =
12731
334
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12732
334
      CHECK_ERROR0;
12733
111
            if ((ctxt->value != NULL)
12734
111
                && (ctxt->value->type == XPATH_NODESET)
12735
111
                && (ctxt->value->nodesetval != NULL)
12736
111
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12737
                /*
12738
                 * limit tree traversing to first node in the result
12739
                 */
12740
18
    if (ctxt->value->nodesetval->nodeNr > 1)
12741
6
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12742
18
                *last =
12743
18
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12744
18
                                                     nodesetval->nodeNr -
12745
18
                                                     1];
12746
18
            }
12747
111
            cur =
12748
111
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12749
111
      CHECK_ERROR0;
12750
100
            if ((ctxt->value != NULL)
12751
100
                && (ctxt->value->type == XPATH_NODESET)
12752
100
                && (ctxt->value->nodesetval != NULL)
12753
100
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12754
26
            }
12755
12756
100
            arg2 = valuePop(ctxt);
12757
100
            arg1 = valuePop(ctxt);
12758
100
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12759
100
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12760
74
          xmlXPathReleaseObject(ctxt->context, arg1);
12761
74
          xmlXPathReleaseObject(ctxt->context, arg2);
12762
74
                XP_ERROR0(XPATH_INVALID_TYPE);
12763
0
            }
12764
26
            if ((ctxt->context->opLimit != 0) &&
12765
26
                (((arg1->nodesetval != NULL) &&
12766
26
                  (xmlXPathCheckOpLimit(ctxt,
12767
13
                                        arg1->nodesetval->nodeNr) < 0)) ||
12768
26
                 ((arg2->nodesetval != NULL) &&
12769
26
                  (xmlXPathCheckOpLimit(ctxt,
12770
26
                                        arg2->nodesetval->nodeNr) < 0)))) {
12771
1
          xmlXPathReleaseObject(ctxt->context, arg1);
12772
1
          xmlXPathReleaseObject(ctxt->context, arg2);
12773
1
                break;
12774
1
            }
12775
12776
            /* TODO: Check memory error. */
12777
25
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12778
25
                                                    arg2->nodesetval);
12779
25
            valuePush(ctxt, arg1);
12780
25
      xmlXPathReleaseObject(ctxt->context, arg2);
12781
            /* optimizer */
12782
25
      if (total > cur)
12783
6
    xmlXPathCompSwap(op);
12784
25
            total += cur;
12785
25
            break;
12786
0
        case XPATH_OP_ROOT:
12787
0
            xmlXPathRoot(ctxt);
12788
0
            break;
12789
18
        case XPATH_OP_NODE:
12790
18
            if (op->ch1 != -1)
12791
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12792
18
      CHECK_ERROR0;
12793
18
            if (op->ch2 != -1)
12794
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12795
18
      CHECK_ERROR0;
12796
18
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12797
18
    ctxt->context->node));
12798
18
            break;
12799
112
        case XPATH_OP_COLLECT:{
12800
112
                if (op->ch1 == -1)
12801
0
                    break;
12802
12803
112
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12804
112
    CHECK_ERROR0;
12805
12806
112
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12807
112
                break;
12808
112
            }
12809
74
        case XPATH_OP_VALUE:
12810
74
            valuePush(ctxt,
12811
74
                      xmlXPathCacheObjectCopy(ctxt->context,
12812
74
      (xmlXPathObjectPtr) op->value4));
12813
74
            break;
12814
93
        case XPATH_OP_SORT:
12815
93
            if (op->ch1 != -1)
12816
93
                total +=
12817
93
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12818
93
                                           last);
12819
93
      CHECK_ERROR0;
12820
12
            if ((ctxt->value != NULL)
12821
12
                && (ctxt->value->type == XPATH_NODESET)
12822
12
                && (ctxt->value->nodesetval != NULL)
12823
12
    && (ctxt->value->nodesetval->nodeNr > 1))
12824
12
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12825
12
            break;
12826
0
        default:
12827
0
            total += xmlXPathCompOpEval(ctxt, op);
12828
0
            break;
12829
631
    }
12830
12831
242
    ctxt->context->depth -= 1;
12832
242
    return (total);
12833
631
}
12834
12835
#ifdef XP_OPTIMIZED_FILTER_FIRST
12836
static int
12837
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12838
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12839
4
{
12840
4
    int total = 0;
12841
4
    xmlXPathCompExprPtr comp;
12842
4
    xmlXPathObjectPtr obj;
12843
4
    xmlNodeSetPtr set;
12844
12845
4
    CHECK_ERROR0;
12846
4
    comp = ctxt->comp;
12847
    /*
12848
    * Optimization for ()[last()] selection i.e. the last elem
12849
    */
12850
4
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12851
4
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12852
4
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12853
4
  int f = comp->steps[op->ch2].ch1;
12854
12855
4
  if ((f != -1) &&
12856
4
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12857
4
      (comp->steps[f].value5 == NULL) &&
12858
4
      (comp->steps[f].value == 0) &&
12859
4
      (comp->steps[f].value4 != NULL) &&
12860
4
      (xmlStrEqual
12861
4
      (comp->steps[f].value4, BAD_CAST "last"))) {
12862
4
      xmlNodePtr last = NULL;
12863
12864
4
      total +=
12865
4
    xmlXPathCompOpEvalLast(ctxt,
12866
4
        &comp->steps[op->ch1],
12867
4
        &last);
12868
4
      CHECK_ERROR0;
12869
      /*
12870
      * The nodeset should be in document order,
12871
      * Keep only the last value
12872
      */
12873
3
      if ((ctxt->value != NULL) &&
12874
3
    (ctxt->value->type == XPATH_NODESET) &&
12875
3
    (ctxt->value->nodesetval != NULL) &&
12876
3
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12877
3
    (ctxt->value->nodesetval->nodeNr > 1)) {
12878
3
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12879
3
    *first = *(ctxt->value->nodesetval->nodeTab);
12880
3
      }
12881
3
      return (total);
12882
4
  }
12883
4
    }
12884
12885
0
    if (op->ch1 != -1)
12886
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12887
0
    CHECK_ERROR0;
12888
0
    if (op->ch2 == -1)
12889
0
  return (total);
12890
0
    if (ctxt->value == NULL)
12891
0
  return (total);
12892
12893
#ifdef LIBXML_XPTR_LOCS_ENABLED
12894
    /*
12895
    * Hum are we filtering the result of an XPointer expression
12896
    */
12897
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12898
        xmlLocationSetPtr locset = ctxt->value->user;
12899
12900
        if (locset != NULL) {
12901
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12902
            if (locset->locNr > 0)
12903
                *first = (xmlNodePtr) locset->locTab[0]->user;
12904
        }
12905
12906
  return (total);
12907
    }
12908
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12909
12910
    /*
12911
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12912
     * the stack. We have to temporarily remove the nodeset object from the
12913
     * stack to avoid freeing it prematurely.
12914
     */
12915
0
    CHECK_TYPE0(XPATH_NODESET);
12916
0
    obj = valuePop(ctxt);
12917
0
    set = obj->nodesetval;
12918
0
    if (set != NULL) {
12919
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12920
0
        if (set->nodeNr > 0)
12921
0
            *first = set->nodeTab[0];
12922
0
    }
12923
0
    valuePush(ctxt, obj);
12924
12925
0
    return (total);
12926
0
}
12927
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12928
12929
/**
12930
 * xmlXPathCompOpEval:
12931
 * @ctxt:  the XPath parser context with the compiled expression
12932
 * @op:  an XPath compiled operation
12933
 *
12934
 * Evaluate the Precompiled XPath operation
12935
 * Returns the number of nodes traversed
12936
 */
12937
static int
12938
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12939
2.12M
{
12940
2.12M
    int total = 0;
12941
2.12M
    int equal, ret;
12942
2.12M
    xmlXPathCompExprPtr comp;
12943
2.12M
    xmlXPathObjectPtr arg1, arg2;
12944
12945
2.12M
    CHECK_ERROR0;
12946
2.12M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12947
0
        return(0);
12948
2.12M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12949
2.12M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12950
2.12M
    ctxt->context->depth += 1;
12951
2.12M
    comp = ctxt->comp;
12952
2.12M
    switch (op->op) {
12953
0
        case XPATH_OP_END:
12954
0
            break;
12955
149
        case XPATH_OP_AND:
12956
149
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12957
149
      CHECK_ERROR0;
12958
146
            xmlXPathBooleanFunction(ctxt, 1);
12959
146
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12960
48
                break;
12961
98
            arg2 = valuePop(ctxt);
12962
98
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12963
98
      if (ctxt->error) {
12964
0
    xmlXPathFreeObject(arg2);
12965
0
    break;
12966
0
      }
12967
98
            xmlXPathBooleanFunction(ctxt, 1);
12968
98
            if (ctxt->value != NULL)
12969
98
                ctxt->value->boolval &= arg2->boolval;
12970
98
      xmlXPathReleaseObject(ctxt->context, arg2);
12971
98
            break;
12972
1.48k
        case XPATH_OP_OR:
12973
1.48k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974
1.48k
      CHECK_ERROR0;
12975
1.48k
            xmlXPathBooleanFunction(ctxt, 1);
12976
1.48k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12977
0
                break;
12978
1.48k
            arg2 = valuePop(ctxt);
12979
1.48k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12980
1.48k
      if (ctxt->error) {
12981
0
    xmlXPathFreeObject(arg2);
12982
0
    break;
12983
0
      }
12984
1.48k
            xmlXPathBooleanFunction(ctxt, 1);
12985
1.48k
            if (ctxt->value != NULL)
12986
1.48k
                ctxt->value->boolval |= arg2->boolval;
12987
1.48k
      xmlXPathReleaseObject(ctxt->context, arg2);
12988
1.48k
            break;
12989
6.43k
        case XPATH_OP_EQUAL:
12990
6.43k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12991
6.43k
      CHECK_ERROR0;
12992
6.21k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12993
6.21k
      CHECK_ERROR0;
12994
6.13k
      if (op->value)
12995
3.43k
    equal = xmlXPathEqualValues(ctxt);
12996
2.70k
      else
12997
2.70k
    equal = xmlXPathNotEqualValues(ctxt);
12998
6.13k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12999
6.13k
            break;
13000
1.75k
        case XPATH_OP_CMP:
13001
1.75k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13002
1.75k
      CHECK_ERROR0;
13003
1.58k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13004
1.58k
      CHECK_ERROR0;
13005
1.57k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13006
1.57k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13007
1.57k
            break;
13008
186k
        case XPATH_OP_PLUS:
13009
186k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13010
186k
      CHECK_ERROR0;
13011
186k
            if (op->ch2 != -1) {
13012
3.09k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13013
3.09k
      }
13014
186k
      CHECK_ERROR0;
13015
186k
            if (op->value == 0)
13016
920
                xmlXPathSubValues(ctxt);
13017
185k
            else if (op->value == 1)
13018
2.16k
                xmlXPathAddValues(ctxt);
13019
183k
            else if (op->value == 2)
13020
182k
                xmlXPathValueFlipSign(ctxt);
13021
921
            else if (op->value == 3) {
13022
921
                CAST_TO_NUMBER;
13023
921
                CHECK_TYPE0(XPATH_NUMBER);
13024
921
            }
13025
186k
            break;
13026
186k
        case XPATH_OP_MULT:
13027
751
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13028
751
      CHECK_ERROR0;
13029
720
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13030
720
      CHECK_ERROR0;
13031
708
            if (op->value == 0)
13032
570
                xmlXPathMultValues(ctxt);
13033
138
            else if (op->value == 1)
13034
138
                xmlXPathDivValues(ctxt);
13035
0
            else if (op->value == 2)
13036
0
                xmlXPathModValues(ctxt);
13037
708
            break;
13038
13.2k
        case XPATH_OP_UNION:
13039
13.2k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13040
13.2k
      CHECK_ERROR0;
13041
9.14k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13042
9.14k
      CHECK_ERROR0;
13043
13044
9.14k
            arg2 = valuePop(ctxt);
13045
9.14k
            arg1 = valuePop(ctxt);
13046
9.14k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13047
9.14k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13048
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13049
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13050
0
                XP_ERROR0(XPATH_INVALID_TYPE);
13051
0
            }
13052
9.14k
            if ((ctxt->context->opLimit != 0) &&
13053
9.14k
                (((arg1->nodesetval != NULL) &&
13054
9.14k
                  (xmlXPathCheckOpLimit(ctxt,
13055
9.11k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13056
9.14k
                 ((arg2->nodesetval != NULL) &&
13057
9.14k
                  (xmlXPathCheckOpLimit(ctxt,
13058
9.04k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13059
2
          xmlXPathReleaseObject(ctxt->context, arg1);
13060
2
          xmlXPathReleaseObject(ctxt->context, arg2);
13061
2
                break;
13062
2
            }
13063
13064
9.14k
      if ((arg1->nodesetval == NULL) ||
13065
9.14k
    ((arg2->nodesetval != NULL) &&
13066
9.11k
     (arg2->nodesetval->nodeNr != 0)))
13067
7.51k
      {
13068
                /* TODO: Check memory error. */
13069
7.51k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13070
7.51k
              arg2->nodesetval);
13071
7.51k
      }
13072
13073
9.14k
            valuePush(ctxt, arg1);
13074
9.14k
      xmlXPathReleaseObject(ctxt->context, arg2);
13075
9.14k
            break;
13076
18.9k
        case XPATH_OP_ROOT:
13077
18.9k
            xmlXPathRoot(ctxt);
13078
18.9k
            break;
13079
384k
        case XPATH_OP_NODE:
13080
384k
            if (op->ch1 != -1)
13081
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13082
384k
      CHECK_ERROR0;
13083
384k
            if (op->ch2 != -1)
13084
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13085
384k
      CHECK_ERROR0;
13086
384k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13087
384k
    ctxt->context->node));
13088
384k
            break;
13089
283k
        case XPATH_OP_COLLECT:{
13090
283k
                if (op->ch1 == -1)
13091
0
                    break;
13092
13093
283k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13094
283k
    CHECK_ERROR0;
13095
13096
280k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13097
280k
                break;
13098
283k
            }
13099
12.1k
        case XPATH_OP_VALUE:
13100
12.1k
            valuePush(ctxt,
13101
12.1k
                      xmlXPathCacheObjectCopy(ctxt->context,
13102
12.1k
      (xmlXPathObjectPtr) op->value4));
13103
12.1k
            break;
13104
0
        case XPATH_OP_VARIABLE:{
13105
0
    xmlXPathObjectPtr val;
13106
13107
0
                if (op->ch1 != -1)
13108
0
                    total +=
13109
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13110
0
                if (op->value5 == NULL) {
13111
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13112
0
        if (val == NULL)
13113
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13114
0
                    valuePush(ctxt, val);
13115
0
    } else {
13116
0
                    const xmlChar *URI;
13117
13118
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13119
0
                    if (URI == NULL) {
13120
0
                        xmlGenericError(xmlGenericErrorContext,
13121
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13122
0
                                    (char *) op->value4, (char *)op->value5);
13123
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13124
0
                        break;
13125
0
                    }
13126
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13127
0
                                                       op->value4, URI);
13128
0
        if (val == NULL)
13129
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13130
0
                    valuePush(ctxt, val);
13131
0
                }
13132
0
                break;
13133
0
            }
13134
500k
        case XPATH_OP_FUNCTION:{
13135
500k
                xmlXPathFunction func;
13136
500k
                const xmlChar *oldFunc, *oldFuncURI;
13137
500k
    int i;
13138
500k
                int frame;
13139
13140
500k
                frame = ctxt->valueNr;
13141
500k
                if (op->ch1 != -1) {
13142
233k
                    total +=
13143
233k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13144
233k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
13145
472
                        break;
13146
233k
                }
13147
500k
    if (ctxt->valueNr < frame + op->value) {
13148
0
        xmlGenericError(xmlGenericErrorContext,
13149
0
          "xmlXPathCompOpEval: parameter error\n");
13150
0
        ctxt->error = XPATH_INVALID_OPERAND;
13151
0
        break;
13152
0
    }
13153
765k
    for (i = 0; i < op->value; i++) {
13154
264k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13155
0
      xmlGenericError(xmlGenericErrorContext,
13156
0
        "xmlXPathCompOpEval: parameter error\n");
13157
0
      ctxt->error = XPATH_INVALID_OPERAND;
13158
0
      break;
13159
0
        }
13160
264k
                }
13161
500k
                if (op->cache != NULL)
13162
499k
                    func = op->cache;
13163
247
                else {
13164
247
                    const xmlChar *URI = NULL;
13165
13166
247
                    if (op->value5 == NULL)
13167
73
                        func =
13168
73
                            xmlXPathFunctionLookup(ctxt->context,
13169
73
                                                   op->value4);
13170
174
                    else {
13171
174
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13172
174
                        if (URI == NULL) {
13173
1
                            xmlGenericError(xmlGenericErrorContext,
13174
1
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13175
1
                                    (char *)op->value4, (char *)op->value5);
13176
1
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13177
1
                            break;
13178
1
                        }
13179
173
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13180
173
                                                        op->value4, URI);
13181
173
                    }
13182
246
                    if (func == NULL) {
13183
2
                        xmlGenericError(xmlGenericErrorContext,
13184
2
                                "xmlXPathCompOpEval: function %s not found\n",
13185
2
                                        (char *)op->value4);
13186
2
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13187
0
                    }
13188
244
                    op->cache = func;
13189
244
                    op->cacheURI = (void *) URI;
13190
244
                }
13191
500k
                oldFunc = ctxt->context->function;
13192
500k
                oldFuncURI = ctxt->context->functionURI;
13193
500k
                ctxt->context->function = op->value4;
13194
500k
                ctxt->context->functionURI = op->cacheURI;
13195
500k
                func(ctxt, op->value);
13196
500k
                ctxt->context->function = oldFunc;
13197
500k
                ctxt->context->functionURI = oldFuncURI;
13198
500k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13199
500k
                    (ctxt->valueNr != frame + 1))
13200
500k
                    XP_ERROR0(XPATH_STACK_ERROR);
13201
500k
                break;
13202
500k
            }
13203
265k
        case XPATH_OP_ARG:
13204
265k
            if (op->ch1 != -1) {
13205
31.5k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206
31.5k
          CHECK_ERROR0;
13207
31.5k
            }
13208
265k
            if (op->ch2 != -1) {
13209
265k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13210
265k
          CHECK_ERROR0;
13211
265k
      }
13212
264k
            break;
13213
264k
        case XPATH_OP_PREDICATE:
13214
518
        case XPATH_OP_FILTER:{
13215
518
                xmlXPathObjectPtr obj;
13216
518
                xmlNodeSetPtr set;
13217
13218
                /*
13219
                 * Optimization for ()[1] selection i.e. the first elem
13220
                 */
13221
518
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13222
518
#ifdef XP_OPTIMIZED_FILTER_FIRST
13223
        /*
13224
        * FILTER TODO: Can we assume that the inner processing
13225
        *  will result in an ordered list if we have an
13226
        *  XPATH_OP_FILTER?
13227
        *  What about an additional field or flag on
13228
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13229
        *  to assume anything, so it would be more robust and
13230
        *  easier to optimize.
13231
        */
13232
518
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13233
518
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13234
#else
13235
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13236
#endif
13237
518
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13238
116
                    xmlXPathObjectPtr val;
13239
13240
116
                    val = comp->steps[op->ch2].value4;
13241
116
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13242
116
                        (val->floatval == 1.0)) {
13243
4
                        xmlNodePtr first = NULL;
13244
13245
4
                        total +=
13246
4
                            xmlXPathCompOpEvalFirst(ctxt,
13247
4
                                                    &comp->steps[op->ch1],
13248
4
                                                    &first);
13249
4
      CHECK_ERROR0;
13250
                        /*
13251
                         * The nodeset should be in document order,
13252
                         * Keep only the first value
13253
                         */
13254
3
                        if ((ctxt->value != NULL) &&
13255
3
                            (ctxt->value->type == XPATH_NODESET) &&
13256
3
                            (ctxt->value->nodesetval != NULL) &&
13257
3
                            (ctxt->value->nodesetval->nodeNr > 1))
13258
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13259
0
                                                        1, 1);
13260
3
                        break;
13261
4
                    }
13262
116
                }
13263
                /*
13264
                 * Optimization for ()[last()] selection i.e. the last elem
13265
                 */
13266
514
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13267
514
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13268
514
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13269
398
                    int f = comp->steps[op->ch2].ch1;
13270
13271
398
                    if ((f != -1) &&
13272
398
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13273
398
                        (comp->steps[f].value5 == NULL) &&
13274
398
                        (comp->steps[f].value == 0) &&
13275
398
                        (comp->steps[f].value4 != NULL) &&
13276
398
                        (xmlStrEqual
13277
89
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13278
89
                        xmlNodePtr last = NULL;
13279
13280
89
                        total +=
13281
89
                            xmlXPathCompOpEvalLast(ctxt,
13282
89
                                                   &comp->steps[op->ch1],
13283
89
                                                   &last);
13284
89
      CHECK_ERROR0;
13285
                        /*
13286
                         * The nodeset should be in document order,
13287
                         * Keep only the last value
13288
                         */
13289
9
                        if ((ctxt->value != NULL) &&
13290
9
                            (ctxt->value->type == XPATH_NODESET) &&
13291
9
                            (ctxt->value->nodesetval != NULL) &&
13292
9
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13293
9
                            (ctxt->value->nodesetval->nodeNr > 1))
13294
9
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13295
9
                        break;
13296
89
                    }
13297
398
                }
13298
    /*
13299
    * Process inner predicates first.
13300
    * Example "index[parent::book][1]":
13301
    * ...
13302
    *   PREDICATE   <-- we are here "[1]"
13303
    *     PREDICATE <-- process "[parent::book]" first
13304
    *       SORT
13305
    *         COLLECT  'parent' 'name' 'node' book
13306
    *           NODE
13307
    *     ELEM Object is a number : 1
13308
    */
13309
425
                if (op->ch1 != -1)
13310
425
                    total +=
13311
425
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13312
425
    CHECK_ERROR0;
13313
339
                if (op->ch2 == -1)
13314
0
                    break;
13315
339
                if (ctxt->value == NULL)
13316
0
                    break;
13317
13318
#ifdef LIBXML_XPTR_LOCS_ENABLED
13319
                /*
13320
                 * Hum are we filtering the result of an XPointer expression
13321
                 */
13322
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13323
                    xmlLocationSetPtr locset = ctxt->value->user;
13324
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13325
                                              1, locset->locNr);
13326
                    break;
13327
                }
13328
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13329
13330
                /*
13331
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
13332
                 * nodes from the stack. We have to temporarily remove the
13333
                 * nodeset object from the stack to avoid freeing it
13334
                 * prematurely.
13335
                 */
13336
339
                CHECK_TYPE0(XPATH_NODESET);
13337
339
                obj = valuePop(ctxt);
13338
339
                set = obj->nodesetval;
13339
339
                if (set != NULL)
13340
339
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13341
339
                                          1, set->nodeNr, 1);
13342
339
                valuePush(ctxt, obj);
13343
339
                break;
13344
339
            }
13345
449k
        case XPATH_OP_SORT:
13346
449k
            if (op->ch1 != -1)
13347
449k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13348
449k
      CHECK_ERROR0;
13349
448k
            if ((ctxt->value != NULL) &&
13350
448k
                (ctxt->value->type == XPATH_NODESET) &&
13351
448k
                (ctxt->value->nodesetval != NULL) &&
13352
448k
    (ctxt->value->nodesetval->nodeNr > 1))
13353
3.35k
      {
13354
3.35k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13355
3.35k
      }
13356
448k
            break;
13357
#ifdef LIBXML_XPTR_LOCS_ENABLED
13358
        case XPATH_OP_RANGETO:{
13359
                xmlXPathObjectPtr range;
13360
                xmlXPathObjectPtr res, obj;
13361
                xmlXPathObjectPtr tmp;
13362
                xmlLocationSetPtr newlocset = NULL;
13363
        xmlLocationSetPtr oldlocset;
13364
                xmlNodeSetPtr oldset;
13365
                xmlNodePtr oldnode = ctxt->context->node;
13366
                int oldcs = ctxt->context->contextSize;
13367
                int oldpp = ctxt->context->proximityPosition;
13368
                int i, j;
13369
13370
                if (op->ch1 != -1) {
13371
                    total +=
13372
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13373
                    CHECK_ERROR0;
13374
                }
13375
                if (ctxt->value == NULL) {
13376
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13377
                }
13378
                if (op->ch2 == -1)
13379
                    break;
13380
13381
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13382
                    /*
13383
                     * Extract the old locset, and then evaluate the result of the
13384
                     * expression for all the element in the locset. use it to grow
13385
                     * up a new locset.
13386
                     */
13387
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13388
13389
                    if ((ctxt->value->user == NULL) ||
13390
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13391
                        break;
13392
13393
                    obj = valuePop(ctxt);
13394
                    oldlocset = obj->user;
13395
13396
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13397
13398
                    for (i = 0; i < oldlocset->locNr; i++) {
13399
                        /*
13400
                         * Run the evaluation with a node list made of a
13401
                         * single item in the nodelocset.
13402
                         */
13403
                        ctxt->context->node = oldlocset->locTab[i]->user;
13404
                        ctxt->context->contextSize = oldlocset->locNr;
13405
                        ctxt->context->proximityPosition = i + 1;
13406
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13407
          ctxt->context->node);
13408
                        valuePush(ctxt, tmp);
13409
13410
                        if (op->ch2 != -1)
13411
                            total +=
13412
                                xmlXPathCompOpEval(ctxt,
13413
                                                   &comp->steps[op->ch2]);
13414
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13415
                            xmlXPtrFreeLocationSet(newlocset);
13416
                            goto rangeto_error;
13417
      }
13418
13419
                        res = valuePop(ctxt);
13420
      if (res->type == XPATH_LOCATIONSET) {
13421
          xmlLocationSetPtr rloc =
13422
              (xmlLocationSetPtr)res->user;
13423
          for (j=0; j<rloc->locNr; j++) {
13424
              range = xmlXPtrNewRange(
13425
          oldlocset->locTab[i]->user,
13426
          oldlocset->locTab[i]->index,
13427
          rloc->locTab[j]->user2,
13428
          rloc->locTab[j]->index2);
13429
        if (range != NULL) {
13430
            xmlXPtrLocationSetAdd(newlocset, range);
13431
        }
13432
          }
13433
      } else {
13434
          range = xmlXPtrNewRangeNodeObject(
13435
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13436
                            if (range != NULL) {
13437
                                xmlXPtrLocationSetAdd(newlocset,range);
13438
          }
13439
                        }
13440
13441
                        /*
13442
                         * Cleanup
13443
                         */
13444
                        if (res != NULL) {
13445
          xmlXPathReleaseObject(ctxt->context, res);
13446
      }
13447
                        if (ctxt->value == tmp) {
13448
                            res = valuePop(ctxt);
13449
          xmlXPathReleaseObject(ctxt->context, res);
13450
                        }
13451
                    }
13452
    } else {  /* Not a location set */
13453
                    CHECK_TYPE0(XPATH_NODESET);
13454
                    obj = valuePop(ctxt);
13455
                    oldset = obj->nodesetval;
13456
13457
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13458
13459
                    if (oldset != NULL) {
13460
                        for (i = 0; i < oldset->nodeNr; i++) {
13461
                            /*
13462
                             * Run the evaluation with a node list made of a single item
13463
                             * in the nodeset.
13464
                             */
13465
                            ctxt->context->node = oldset->nodeTab[i];
13466
          /*
13467
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13468
          */
13469
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13470
        ctxt->context->node);
13471
                            valuePush(ctxt, tmp);
13472
13473
                            if (op->ch2 != -1)
13474
                                total +=
13475
                                    xmlXPathCompOpEval(ctxt,
13476
                                                   &comp->steps[op->ch2]);
13477
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13478
                                xmlXPtrFreeLocationSet(newlocset);
13479
                                goto rangeto_error;
13480
          }
13481
13482
                            res = valuePop(ctxt);
13483
                            range =
13484
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13485
                                                      res);
13486
                            if (range != NULL) {
13487
                                xmlXPtrLocationSetAdd(newlocset, range);
13488
                            }
13489
13490
                            /*
13491
                             * Cleanup
13492
                             */
13493
                            if (res != NULL) {
13494
        xmlXPathReleaseObject(ctxt->context, res);
13495
          }
13496
                            if (ctxt->value == tmp) {
13497
                                res = valuePop(ctxt);
13498
        xmlXPathReleaseObject(ctxt->context, res);
13499
                            }
13500
                        }
13501
                    }
13502
                }
13503
13504
                /*
13505
                 * The result is used as the new evaluation set.
13506
                 */
13507
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13508
rangeto_error:
13509
    xmlXPathReleaseObject(ctxt->context, obj);
13510
                ctxt->context->node = oldnode;
13511
                ctxt->context->contextSize = oldcs;
13512
                ctxt->context->proximityPosition = oldpp;
13513
                break;
13514
            }
13515
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13516
0
        default:
13517
0
            xmlGenericError(xmlGenericErrorContext,
13518
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13519
0
            ctxt->error = XPATH_INVALID_OPERAND;
13520
0
            break;
13521
2.12M
    }
13522
13523
2.11M
    ctxt->context->depth -= 1;
13524
2.11M
    return (total);
13525
2.12M
}
13526
13527
/**
13528
 * xmlXPathCompOpEvalToBoolean:
13529
 * @ctxt:  the XPath parser context
13530
 *
13531
 * Evaluates if the expression evaluates to true.
13532
 *
13533
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13534
 */
13535
static int
13536
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13537
          xmlXPathStepOpPtr op,
13538
          int isPredicate)
13539
624k
{
13540
624k
    xmlXPathObjectPtr resObj = NULL;
13541
13542
815k
start:
13543
815k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13544
3
        return(0);
13545
    /* comp = ctxt->comp; */
13546
815k
    switch (op->op) {
13547
0
        case XPATH_OP_END:
13548
0
            return (0);
13549
148
  case XPATH_OP_VALUE:
13550
148
      resObj = (xmlXPathObjectPtr) op->value4;
13551
148
      if (isPredicate)
13552
148
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13553
0
      return(xmlXPathCastToBoolean(resObj));
13554
191k
  case XPATH_OP_SORT:
13555
      /*
13556
      * We don't need sorting for boolean results. Skip this one.
13557
      */
13558
191k
            if (op->ch1 != -1) {
13559
191k
    op = &ctxt->comp->steps[op->ch1];
13560
191k
    goto start;
13561
191k
      }
13562
0
      return(0);
13563
121k
  case XPATH_OP_COLLECT:
13564
121k
      if (op->ch1 == -1)
13565
0
    return(0);
13566
13567
121k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13568
121k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13569
1
    return(-1);
13570
13571
121k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13572
121k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13573
1
    return(-1);
13574
13575
121k
      resObj = valuePop(ctxt);
13576
121k
      if (resObj == NULL)
13577
0
    return(-1);
13578
121k
      break;
13579
502k
  default:
13580
      /*
13581
      * Fallback to call xmlXPathCompOpEval().
13582
      */
13583
502k
      xmlXPathCompOpEval(ctxt, op);
13584
502k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13585
58
    return(-1);
13586
13587
502k
      resObj = valuePop(ctxt);
13588
502k
      if (resObj == NULL)
13589
0
    return(-1);
13590
502k
      break;
13591
815k
    }
13592
13593
624k
    if (resObj) {
13594
624k
  int res;
13595
13596
624k
  if (resObj->type == XPATH_BOOLEAN) {
13597
6.82k
      res = resObj->boolval;
13598
617k
  } else if (isPredicate) {
13599
      /*
13600
      * For predicates a result of type "number" is handled
13601
      * differently:
13602
      * SPEC XPath 1.0:
13603
      * "If the result is a number, the result will be converted
13604
      *  to true if the number is equal to the context position
13605
      *  and will be converted to false otherwise;"
13606
      */
13607
617k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13608
617k
  } else {
13609
0
      res = xmlXPathCastToBoolean(resObj);
13610
0
  }
13611
624k
  xmlXPathReleaseObject(ctxt->context, resObj);
13612
624k
  return(res);
13613
624k
    }
13614
13615
0
    return(0);
13616
624k
}
13617
13618
#ifdef XPATH_STREAMING
13619
/**
13620
 * xmlXPathRunStreamEval:
13621
 * @ctxt:  the XPath parser context with the compiled expression
13622
 *
13623
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13624
 */
13625
static int
13626
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13627
          xmlXPathObjectPtr *resultSeq, int toBool)
13628
1.94k
{
13629
1.94k
    int max_depth, min_depth;
13630
1.94k
    int from_root;
13631
1.94k
    int ret, depth;
13632
1.94k
    int eval_all_nodes;
13633
1.94k
    xmlNodePtr cur = NULL, limit = NULL;
13634
1.94k
    xmlStreamCtxtPtr patstream = NULL;
13635
13636
1.94k
    if ((ctxt == NULL) || (comp == NULL))
13637
0
        return(-1);
13638
1.94k
    max_depth = xmlPatternMaxDepth(comp);
13639
1.94k
    if (max_depth == -1)
13640
0
        return(-1);
13641
1.94k
    if (max_depth == -2)
13642
123
        max_depth = 10000;
13643
1.94k
    min_depth = xmlPatternMinDepth(comp);
13644
1.94k
    if (min_depth == -1)
13645
0
        return(-1);
13646
1.94k
    from_root = xmlPatternFromRoot(comp);
13647
1.94k
    if (from_root < 0)
13648
0
        return(-1);
13649
#if 0
13650
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13651
#endif
13652
13653
1.94k
    if (! toBool) {
13654
1.94k
  if (resultSeq == NULL)
13655
0
      return(-1);
13656
1.94k
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13657
1.94k
  if (*resultSeq == NULL)
13658
0
      return(-1);
13659
1.94k
    }
13660
13661
    /*
13662
     * handle the special cases of "/" amd "." being matched
13663
     */
13664
1.94k
    if (min_depth == 0) {
13665
3
  if (from_root) {
13666
      /* Select "/" */
13667
0
      if (toBool)
13668
0
    return(1);
13669
            /* TODO: Check memory error. */
13670
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13671
0
                         (xmlNodePtr) ctxt->doc);
13672
3
  } else {
13673
      /* Select "self::node()" */
13674
3
      if (toBool)
13675
0
    return(1);
13676
            /* TODO: Check memory error. */
13677
3
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13678
3
  }
13679
3
    }
13680
1.94k
    if (max_depth == 0) {
13681
3
  return(0);
13682
3
    }
13683
13684
1.93k
    if (from_root) {
13685
74
        cur = (xmlNodePtr)ctxt->doc;
13686
1.86k
    } else if (ctxt->node != NULL) {
13687
1.86k
        switch (ctxt->node->type) {
13688
1.49k
            case XML_ELEMENT_NODE:
13689
1.83k
            case XML_DOCUMENT_NODE:
13690
1.83k
            case XML_DOCUMENT_FRAG_NODE:
13691
1.83k
            case XML_HTML_DOCUMENT_NODE:
13692
1.83k
          cur = ctxt->node;
13693
1.83k
    break;
13694
0
            case XML_ATTRIBUTE_NODE:
13695
26
            case XML_TEXT_NODE:
13696
26
            case XML_CDATA_SECTION_NODE:
13697
26
            case XML_ENTITY_REF_NODE:
13698
26
            case XML_ENTITY_NODE:
13699
26
            case XML_PI_NODE:
13700
27
            case XML_COMMENT_NODE:
13701
27
            case XML_NOTATION_NODE:
13702
27
            case XML_DTD_NODE:
13703
27
            case XML_DOCUMENT_TYPE_NODE:
13704
27
            case XML_ELEMENT_DECL:
13705
27
            case XML_ATTRIBUTE_DECL:
13706
27
            case XML_ENTITY_DECL:
13707
27
            case XML_NAMESPACE_DECL:
13708
27
            case XML_XINCLUDE_START:
13709
27
            case XML_XINCLUDE_END:
13710
27
    break;
13711
1.86k
  }
13712
1.86k
  limit = cur;
13713
1.86k
    }
13714
1.93k
    if (cur == NULL) {
13715
27
        return(0);
13716
27
    }
13717
13718
1.91k
    patstream = xmlPatternGetStreamCtxt(comp);
13719
1.91k
    if (patstream == NULL) {
13720
  /*
13721
  * QUESTION TODO: Is this an error?
13722
  */
13723
1
  return(0);
13724
1
    }
13725
13726
1.91k
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13727
13728
1.91k
    if (from_root) {
13729
74
  ret = xmlStreamPush(patstream, NULL, NULL);
13730
74
  if (ret < 0) {
13731
74
  } else if (ret == 1) {
13732
57
      if (toBool)
13733
0
    goto return_1;
13734
            /* TODO: Check memory error. */
13735
57
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13736
57
  }
13737
74
    }
13738
1.91k
    depth = 0;
13739
1.91k
    goto scan_children;
13740
93.6k
next_node:
13741
97.7k
    do {
13742
97.7k
        if (ctxt->opLimit != 0) {
13743
97.7k
            if (ctxt->opCount >= ctxt->opLimit) {
13744
0
                xmlGenericError(xmlGenericErrorContext,
13745
0
                        "XPath operation limit exceeded\n");
13746
0
                xmlFreeStreamCtxt(patstream);
13747
0
                return(-1);
13748
0
            }
13749
97.7k
            ctxt->opCount++;
13750
97.7k
        }
13751
13752
97.7k
  switch (cur->type) {
13753
94.1k
      case XML_ELEMENT_NODE:
13754
97.7k
      case XML_TEXT_NODE:
13755
97.7k
      case XML_CDATA_SECTION_NODE:
13756
97.7k
      case XML_COMMENT_NODE:
13757
97.7k
      case XML_PI_NODE:
13758
97.7k
    if (cur->type == XML_ELEMENT_NODE) {
13759
94.1k
        ret = xmlStreamPush(patstream, cur->name,
13760
94.1k
        (cur->ns ? cur->ns->href : NULL));
13761
94.1k
    } else if (eval_all_nodes)
13762
912
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13763
2.71k
    else
13764
2.71k
        break;
13765
13766
95.0k
    if (ret < 0) {
13767
        /* NOP. */
13768
95.0k
    } else if (ret == 1) {
13769
3.20k
        if (toBool)
13770
0
      goto return_1;
13771
3.20k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13772
3.20k
            < 0) {
13773
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13774
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13775
0
        }
13776
3.20k
    }
13777
95.0k
    if ((cur->children == NULL) || (depth >= max_depth)) {
13778
92.8k
        ret = xmlStreamPop(patstream);
13779
92.8k
        while (cur->next != NULL) {
13780
92.4k
      cur = cur->next;
13781
92.4k
      if ((cur->type != XML_ENTITY_DECL) &&
13782
92.4k
          (cur->type != XML_DTD_NODE))
13783
92.4k
          goto next_node;
13784
92.4k
        }
13785
92.8k
    }
13786
2.58k
      default:
13787
2.58k
    break;
13788
97.7k
  }
13789
13790
7.21k
scan_children:
13791
7.21k
  if (cur->type == XML_NAMESPACE_DECL) break;
13792
7.21k
  if ((cur->children != NULL) && (depth < max_depth)) {
13793
      /*
13794
       * Do not descend on entities declarations
13795
       */
13796
4.01k
      if (cur->children->type != XML_ENTITY_DECL) {
13797
4.01k
    cur = cur->children;
13798
4.01k
    depth++;
13799
    /*
13800
     * Skip DTDs
13801
     */
13802
4.01k
    if (cur->type != XML_DTD_NODE)
13803
4.01k
        continue;
13804
4.01k
      }
13805
4.01k
  }
13806
13807
3.19k
  if (cur == limit)
13808
115
      break;
13809
13810
3.08k
  while (cur->next != NULL) {
13811
1.22k
      cur = cur->next;
13812
1.22k
      if ((cur->type != XML_ENTITY_DECL) &&
13813
1.22k
    (cur->type != XML_DTD_NODE))
13814
1.22k
    goto next_node;
13815
1.22k
  }
13816
13817
4.01k
  do {
13818
4.01k
      cur = cur->parent;
13819
4.01k
      depth--;
13820
4.01k
      if ((cur == NULL) || (cur == limit) ||
13821
4.01k
                (cur->type == XML_DOCUMENT_NODE))
13822
1.79k
          goto done;
13823
2.22k
      if (cur->type == XML_ELEMENT_NODE) {
13824
2.22k
    ret = xmlStreamPop(patstream);
13825
2.22k
      } else if ((eval_all_nodes) &&
13826
0
    ((cur->type == XML_TEXT_NODE) ||
13827
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13828
0
     (cur->type == XML_COMMENT_NODE) ||
13829
0
     (cur->type == XML_PI_NODE)))
13830
0
      {
13831
0
    ret = xmlStreamPop(patstream);
13832
0
      }
13833
2.22k
      if (cur->next != NULL) {
13834
60
    cur = cur->next;
13835
60
    break;
13836
60
      }
13837
2.22k
  } while (cur != NULL);
13838
13839
4.07k
    } while ((cur != NULL) && (depth >= 0));
13840
13841
1.91k
done:
13842
13843
1.91k
    if (patstream)
13844
1.91k
  xmlFreeStreamCtxt(patstream);
13845
1.91k
    return(0);
13846
13847
0
return_1:
13848
0
    if (patstream)
13849
0
  xmlFreeStreamCtxt(patstream);
13850
0
    return(1);
13851
93.6k
}
13852
#endif /* XPATH_STREAMING */
13853
13854
/**
13855
 * xmlXPathRunEval:
13856
 * @ctxt:  the XPath parser context with the compiled expression
13857
 * @toBool:  evaluate to a boolean result
13858
 *
13859
 * Evaluate the Precompiled XPath expression in the given context.
13860
 */
13861
static int
13862
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13863
6.39k
{
13864
6.39k
    xmlXPathCompExprPtr comp;
13865
6.39k
    int oldDepth;
13866
13867
6.39k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13868
0
  return(-1);
13869
13870
6.39k
    if (ctxt->valueTab == NULL) {
13871
  /* Allocate the value stack */
13872
402
  ctxt->valueTab = (xmlXPathObjectPtr *)
13873
402
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13874
402
  if (ctxt->valueTab == NULL) {
13875
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13876
0
      return(-1);
13877
0
  }
13878
402
  ctxt->valueNr = 0;
13879
402
  ctxt->valueMax = 10;
13880
402
  ctxt->value = NULL;
13881
402
    }
13882
6.39k
#ifdef XPATH_STREAMING
13883
6.39k
    if (ctxt->comp->stream) {
13884
1.94k
  int res;
13885
13886
1.94k
  if (toBool) {
13887
      /*
13888
      * Evaluation to boolean result.
13889
      */
13890
0
      res = xmlXPathRunStreamEval(ctxt->context,
13891
0
    ctxt->comp->stream, NULL, 1);
13892
0
      if (res != -1)
13893
0
    return(res);
13894
1.94k
  } else {
13895
1.94k
      xmlXPathObjectPtr resObj = NULL;
13896
13897
      /*
13898
      * Evaluation to a sequence.
13899
      */
13900
1.94k
      res = xmlXPathRunStreamEval(ctxt->context,
13901
1.94k
    ctxt->comp->stream, &resObj, 0);
13902
13903
1.94k
      if ((res != -1) && (resObj != NULL)) {
13904
1.94k
    valuePush(ctxt, resObj);
13905
1.94k
    return(0);
13906
1.94k
      }
13907
0
      if (resObj != NULL)
13908
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13909
0
  }
13910
  /*
13911
  * QUESTION TODO: This falls back to normal XPath evaluation
13912
  * if res == -1. Is this intended?
13913
  */
13914
1.94k
    }
13915
4.44k
#endif
13916
4.44k
    comp = ctxt->comp;
13917
4.44k
    if (comp->last < 0) {
13918
0
  xmlGenericError(xmlGenericErrorContext,
13919
0
      "xmlXPathRunEval: last is less than zero\n");
13920
0
  return(-1);
13921
0
    }
13922
4.44k
    oldDepth = ctxt->context->depth;
13923
4.44k
    if (toBool)
13924
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13925
0
      &comp->steps[comp->last], 0));
13926
4.44k
    else
13927
4.44k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13928
4.44k
    ctxt->context->depth = oldDepth;
13929
13930
4.44k
    return(0);
13931
4.44k
}
13932
13933
/************************************************************************
13934
 *                  *
13935
 *      Public interfaces       *
13936
 *                  *
13937
 ************************************************************************/
13938
13939
/**
13940
 * xmlXPathEvalPredicate:
13941
 * @ctxt:  the XPath context
13942
 * @res:  the Predicate Expression evaluation result
13943
 *
13944
 * Evaluate a predicate result for the current node.
13945
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13946
 * the result to a boolean. If the result is a number, the result will
13947
 * be converted to true if the number is equal to the position of the
13948
 * context node in the context node list (as returned by the position
13949
 * function) and will be converted to false otherwise; if the result
13950
 * is not a number, then the result will be converted as if by a call
13951
 * to the boolean function.
13952
 *
13953
 * Returns 1 if predicate is true, 0 otherwise
13954
 */
13955
int
13956
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13957
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13958
0
    switch (res->type) {
13959
0
        case XPATH_BOOLEAN:
13960
0
      return(res->boolval);
13961
0
        case XPATH_NUMBER:
13962
0
      return(res->floatval == ctxt->proximityPosition);
13963
0
        case XPATH_NODESET:
13964
0
        case XPATH_XSLT_TREE:
13965
0
      if (res->nodesetval == NULL)
13966
0
    return(0);
13967
0
      return(res->nodesetval->nodeNr != 0);
13968
0
        case XPATH_STRING:
13969
0
      return((res->stringval != NULL) &&
13970
0
             (xmlStrlen(res->stringval) != 0));
13971
0
        default:
13972
0
      STRANGE
13973
0
    }
13974
0
    return(0);
13975
0
}
13976
13977
/**
13978
 * xmlXPathEvaluatePredicateResult:
13979
 * @ctxt:  the XPath Parser context
13980
 * @res:  the Predicate Expression evaluation result
13981
 *
13982
 * Evaluate a predicate result for the current node.
13983
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13984
 * the result to a boolean. If the result is a number, the result will
13985
 * be converted to true if the number is equal to the position of the
13986
 * context node in the context node list (as returned by the position
13987
 * function) and will be converted to false otherwise; if the result
13988
 * is not a number, then the result will be converted as if by a call
13989
 * to the boolean function.
13990
 *
13991
 * Returns 1 if predicate is true, 0 otherwise
13992
 */
13993
int
13994
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13995
617k
                                xmlXPathObjectPtr res) {
13996
617k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13997
617k
    switch (res->type) {
13998
0
        case XPATH_BOOLEAN:
13999
0
      return(res->boolval);
14000
468k
        case XPATH_NUMBER:
14001
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14002
      return((res->floatval == ctxt->context->proximityPosition) &&
14003
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14004
#else
14005
468k
      return(res->floatval == ctxt->context->proximityPosition);
14006
0
#endif
14007
148k
        case XPATH_NODESET:
14008
148k
        case XPATH_XSLT_TREE:
14009
148k
      if (res->nodesetval == NULL)
14010
17.0k
    return(0);
14011
131k
      return(res->nodesetval->nodeNr != 0);
14012
236
        case XPATH_STRING:
14013
236
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14014
#ifdef LIBXML_XPTR_LOCS_ENABLED
14015
  case XPATH_LOCATIONSET:{
14016
      xmlLocationSetPtr ptr = res->user;
14017
      if (ptr == NULL)
14018
          return(0);
14019
      return (ptr->locNr != 0);
14020
      }
14021
#endif
14022
0
        default:
14023
0
      STRANGE
14024
617k
    }
14025
0
    return(0);
14026
617k
}
14027
14028
#ifdef XPATH_STREAMING
14029
/**
14030
 * xmlXPathTryStreamCompile:
14031
 * @ctxt: an XPath context
14032
 * @str:  the XPath expression
14033
 *
14034
 * Try to compile the XPath expression as a streamable subset.
14035
 *
14036
 * Returns the compiled expression or NULL if failed to compile.
14037
 */
14038
static xmlXPathCompExprPtr
14039
6.10k
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14040
    /*
14041
     * Optimization: use streaming patterns when the XPath expression can
14042
     * be compiled to a stream lookup
14043
     */
14044
6.10k
    xmlPatternPtr stream;
14045
6.10k
    xmlXPathCompExprPtr comp;
14046
6.10k
    xmlDictPtr dict = NULL;
14047
6.10k
    const xmlChar **namespaces = NULL;
14048
6.10k
    xmlNsPtr ns;
14049
6.10k
    int i, j;
14050
14051
6.10k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14052
6.10k
        (!xmlStrchr(str, '@'))) {
14053
2.16k
  const xmlChar *tmp;
14054
14055
  /*
14056
   * We don't try to handle expressions using the verbose axis
14057
   * specifiers ("::"), just the simplified form at this point.
14058
   * Additionally, if there is no list of namespaces available and
14059
   *  there's a ":" in the expression, indicating a prefixed QName,
14060
   *  then we won't try to compile either. xmlPatterncompile() needs
14061
   *  to have a list of namespaces at compilation time in order to
14062
   *  compile prefixed name tests.
14063
   */
14064
2.16k
  tmp = xmlStrchr(str, ':');
14065
2.16k
  if ((tmp != NULL) &&
14066
2.16k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14067
543
      return(NULL);
14068
14069
1.61k
  if (ctxt != NULL) {
14070
1.61k
      dict = ctxt->dict;
14071
1.61k
      if (ctxt->nsNr > 0) {
14072
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14073
0
    if (namespaces == NULL) {
14074
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14075
0
        return(NULL);
14076
0
    }
14077
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14078
0
        ns = ctxt->namespaces[j];
14079
0
        namespaces[i++] = ns->href;
14080
0
        namespaces[i++] = ns->prefix;
14081
0
    }
14082
0
    namespaces[i++] = NULL;
14083
0
    namespaces[i] = NULL;
14084
0
      }
14085
1.61k
  }
14086
14087
1.61k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14088
1.61k
  if (namespaces != NULL) {
14089
0
      xmlFree((xmlChar **)namespaces);
14090
0
  }
14091
1.61k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14092
413
      comp = xmlXPathNewCompExpr();
14093
413
      if (comp == NULL) {
14094
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14095
0
          xmlFreePattern(stream);
14096
0
    return(NULL);
14097
0
      }
14098
413
      comp->stream = stream;
14099
413
      comp->dict = dict;
14100
413
      if (comp->dict)
14101
0
    xmlDictReference(comp->dict);
14102
413
      return(comp);
14103
413
  }
14104
1.20k
  xmlFreePattern(stream);
14105
1.20k
    }
14106
5.15k
    return(NULL);
14107
6.10k
}
14108
#endif /* XPATH_STREAMING */
14109
14110
static void
14111
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14112
                           xmlXPathStepOpPtr op)
14113
2.83M
{
14114
2.83M
    xmlXPathCompExprPtr comp = pctxt->comp;
14115
2.83M
    xmlXPathContextPtr ctxt;
14116
14117
    /*
14118
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14119
    * internal representation.
14120
    */
14121
14122
2.83M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14123
2.83M
        (op->ch1 != -1) &&
14124
2.83M
        (op->ch2 == -1 /* no predicate */))
14125
948k
    {
14126
948k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14127
14128
948k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14129
948k
            ((xmlXPathAxisVal) prevop->value ==
14130
7.38k
                AXIS_DESCENDANT_OR_SELF) &&
14131
948k
            (prevop->ch2 == -1) &&
14132
948k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14133
948k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14134
558
        {
14135
            /*
14136
            * This is a "descendant-or-self::node()" without predicates.
14137
            * Try to eliminate it.
14138
            */
14139
14140
558
            switch ((xmlXPathAxisVal) op->value) {
14141
521
                case AXIS_CHILD:
14142
521
                case AXIS_DESCENDANT:
14143
                    /*
14144
                    * Convert "descendant-or-self::node()/child::" or
14145
                    * "descendant-or-self::node()/descendant::" to
14146
                    * "descendant::"
14147
                    */
14148
521
                    op->ch1   = prevop->ch1;
14149
521
                    op->value = AXIS_DESCENDANT;
14150
521
                    break;
14151
0
                case AXIS_SELF:
14152
3
                case AXIS_DESCENDANT_OR_SELF:
14153
                    /*
14154
                    * Convert "descendant-or-self::node()/self::" or
14155
                    * "descendant-or-self::node()/descendant-or-self::" to
14156
                    * to "descendant-or-self::"
14157
                    */
14158
3
                    op->ch1   = prevop->ch1;
14159
3
                    op->value = AXIS_DESCENDANT_OR_SELF;
14160
3
                    break;
14161
34
                default:
14162
34
                    break;
14163
558
            }
14164
558
  }
14165
948k
    }
14166
14167
    /* OP_VALUE has invalid ch1. */
14168
2.83M
    if (op->op == XPATH_OP_VALUE)
14169
606
        return;
14170
14171
    /* Recurse */
14172
2.83M
    ctxt = pctxt->context;
14173
2.83M
    if (ctxt != NULL) {
14174
2.83M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14175
5.32k
            return;
14176
2.83M
        ctxt->depth += 1;
14177
2.83M
    }
14178
2.83M
    if (op->ch1 != -1)
14179
1.89M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14180
2.83M
    if (op->ch2 != -1)
14181
945k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14182
2.83M
    if (ctxt != NULL)
14183
2.83M
        ctxt->depth -= 1;
14184
2.83M
}
14185
14186
/**
14187
 * xmlXPathCtxtCompile:
14188
 * @ctxt: an XPath context
14189
 * @str:  the XPath expression
14190
 *
14191
 * Compile an XPath expression
14192
 *
14193
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14194
 *         the caller has to free the object.
14195
 */
14196
xmlXPathCompExprPtr
14197
5.70k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14198
5.70k
    xmlXPathParserContextPtr pctxt;
14199
5.70k
    xmlXPathCompExprPtr comp;
14200
5.70k
    int oldDepth = 0;
14201
14202
5.70k
#ifdef XPATH_STREAMING
14203
5.70k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14204
5.70k
    if (comp != NULL)
14205
413
        return(comp);
14206
5.29k
#endif
14207
14208
5.29k
    xmlInitParser();
14209
14210
5.29k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14211
5.29k
    if (pctxt == NULL)
14212
2
        return NULL;
14213
5.29k
    if (ctxt != NULL)
14214
5.29k
        oldDepth = ctxt->depth;
14215
5.29k
    xmlXPathCompileExpr(pctxt, 1);
14216
5.29k
    if (ctxt != NULL)
14217
5.29k
        ctxt->depth = oldDepth;
14218
14219
5.29k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14220
4.14k
    {
14221
4.14k
        xmlXPathFreeParserContext(pctxt);
14222
4.14k
        return(NULL);
14223
4.14k
    }
14224
14225
1.14k
    if (*pctxt->cur != 0) {
14226
  /*
14227
   * aleksey: in some cases this line prints *second* error message
14228
   * (see bug #78858) and probably this should be fixed.
14229
   * However, we are not sure that all error messages are printed
14230
   * out in other places. It's not critical so we leave it as-is for now
14231
   */
14232
742
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14233
742
  comp = NULL;
14234
742
    } else {
14235
403
  comp = pctxt->comp;
14236
403
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14237
328
            if (ctxt != NULL)
14238
328
                oldDepth = ctxt->depth;
14239
328
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14240
328
            if (ctxt != NULL)
14241
328
                ctxt->depth = oldDepth;
14242
328
  }
14243
403
  pctxt->comp = NULL;
14244
403
    }
14245
1.14k
    xmlXPathFreeParserContext(pctxt);
14246
14247
1.14k
    if (comp != NULL) {
14248
403
  comp->expr = xmlStrdup(str);
14249
#ifdef DEBUG_EVAL_COUNTS
14250
  comp->string = xmlStrdup(str);
14251
  comp->nb = 0;
14252
#endif
14253
403
    }
14254
1.14k
    return(comp);
14255
5.29k
}
14256
14257
/**
14258
 * xmlXPathCompile:
14259
 * @str:  the XPath expression
14260
 *
14261
 * Compile an XPath expression
14262
 *
14263
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14264
 *         the caller has to free the object.
14265
 */
14266
xmlXPathCompExprPtr
14267
0
xmlXPathCompile(const xmlChar *str) {
14268
0
    return(xmlXPathCtxtCompile(NULL, str));
14269
0
}
14270
14271
/**
14272
 * xmlXPathCompiledEvalInternal:
14273
 * @comp:  the compiled XPath expression
14274
 * @ctxt:  the XPath context
14275
 * @resObj: the resulting XPath object or NULL
14276
 * @toBool: 1 if only a boolean result is requested
14277
 *
14278
 * Evaluate the Precompiled XPath expression in the given context.
14279
 * The caller has to free @resObj.
14280
 *
14281
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14282
 *         the caller has to free the object.
14283
 */
14284
static int
14285
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14286
           xmlXPathContextPtr ctxt,
14287
           xmlXPathObjectPtr *resObjPtr,
14288
           int toBool)
14289
6.02k
{
14290
6.02k
    xmlXPathParserContextPtr pctxt;
14291
6.02k
    xmlXPathObjectPtr resObj;
14292
#ifndef LIBXML_THREAD_ENABLED
14293
    static int reentance = 0;
14294
#endif
14295
6.02k
    int res;
14296
14297
6.02k
    CHECK_CTXT_NEG(ctxt)
14298
14299
6.02k
    if (comp == NULL)
14300
0
  return(-1);
14301
6.02k
    xmlInitParser();
14302
14303
#ifndef LIBXML_THREAD_ENABLED
14304
    reentance++;
14305
    if (reentance > 1)
14306
  xmlXPathDisableOptimizer = 1;
14307
#endif
14308
14309
#ifdef DEBUG_EVAL_COUNTS
14310
    comp->nb++;
14311
    if ((comp->string != NULL) && (comp->nb > 100)) {
14312
  fprintf(stderr, "100 x %s\n", comp->string);
14313
  comp->nb = 0;
14314
    }
14315
#endif
14316
6.02k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14317
6.02k
    if (pctxt == NULL)
14318
33
        return(-1);
14319
5.98k
    res = xmlXPathRunEval(pctxt, toBool);
14320
14321
5.98k
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14322
619
        resObj = NULL;
14323
5.36k
    } else {
14324
5.36k
        resObj = valuePop(pctxt);
14325
5.36k
        if (resObj == NULL) {
14326
0
            if (!toBool)
14327
0
                xmlGenericError(xmlGenericErrorContext,
14328
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14329
5.36k
        } else if (pctxt->valueNr > 0) {
14330
0
            xmlGenericError(xmlGenericErrorContext,
14331
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14332
0
                pctxt->valueNr);
14333
0
        }
14334
5.36k
    }
14335
14336
5.98k
    if (resObjPtr)
14337
5.98k
        *resObjPtr = resObj;
14338
0
    else
14339
0
        xmlXPathReleaseObject(ctxt, resObj);
14340
14341
5.98k
    pctxt->comp = NULL;
14342
5.98k
    xmlXPathFreeParserContext(pctxt);
14343
#ifndef LIBXML_THREAD_ENABLED
14344
    reentance--;
14345
#endif
14346
14347
5.98k
    return(res);
14348
6.02k
}
14349
14350
/**
14351
 * xmlXPathCompiledEval:
14352
 * @comp:  the compiled XPath expression
14353
 * @ctx:  the XPath context
14354
 *
14355
 * Evaluate the Precompiled XPath expression in the given context.
14356
 *
14357
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14358
 *         the caller has to free the object.
14359
 */
14360
xmlXPathObjectPtr
14361
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14362
6.02k
{
14363
6.02k
    xmlXPathObjectPtr res = NULL;
14364
14365
6.02k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14366
6.02k
    return(res);
14367
6.02k
}
14368
14369
/**
14370
 * xmlXPathCompiledEvalToBoolean:
14371
 * @comp:  the compiled XPath expression
14372
 * @ctxt:  the XPath context
14373
 *
14374
 * Applies the XPath boolean() function on the result of the given
14375
 * compiled expression.
14376
 *
14377
 * Returns 1 if the expression evaluated to true, 0 if to false and
14378
 *         -1 in API and internal errors.
14379
 */
14380
int
14381
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14382
            xmlXPathContextPtr ctxt)
14383
0
{
14384
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14385
0
}
14386
14387
/**
14388
 * xmlXPathEvalExpr:
14389
 * @ctxt:  the XPath Parser context
14390
 *
14391
 * Parse and evaluate an XPath expression in the given context,
14392
 * then push the result on the context stack
14393
 */
14394
void
14395
402
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14396
402
#ifdef XPATH_STREAMING
14397
402
    xmlXPathCompExprPtr comp;
14398
402
#endif
14399
402
    int oldDepth = 0;
14400
14401
402
    if (ctxt == NULL) return;
14402
14403
402
#ifdef XPATH_STREAMING
14404
402
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14405
402
    if (comp != NULL) {
14406
0
        if (ctxt->comp != NULL)
14407
0
      xmlXPathFreeCompExpr(ctxt->comp);
14408
0
        ctxt->comp = comp;
14409
0
    } else
14410
402
#endif
14411
402
    {
14412
402
        if (ctxt->context != NULL)
14413
402
            oldDepth = ctxt->context->depth;
14414
402
  xmlXPathCompileExpr(ctxt, 1);
14415
402
        if (ctxt->context != NULL)
14416
402
            ctxt->context->depth = oldDepth;
14417
402
        CHECK_ERROR;
14418
14419
        /* Check for trailing characters. */
14420
402
        if (*ctxt->cur != 0)
14421
402
            XP_ERROR(XPATH_EXPR_ERROR);
14422
14423
402
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14424
402
            if (ctxt->context != NULL)
14425
402
                oldDepth = ctxt->context->depth;
14426
402
      xmlXPathOptimizeExpression(ctxt,
14427
402
    &ctxt->comp->steps[ctxt->comp->last]);
14428
402
            if (ctxt->context != NULL)
14429
402
                ctxt->context->depth = oldDepth;
14430
402
        }
14431
402
    }
14432
14433
402
    xmlXPathRunEval(ctxt, 0);
14434
402
}
14435
14436
/**
14437
 * xmlXPathEval:
14438
 * @str:  the XPath expression
14439
 * @ctx:  the XPath context
14440
 *
14441
 * Evaluate the XPath Location Path in the given context.
14442
 *
14443
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14444
 *         the caller has to free the object.
14445
 */
14446
xmlXPathObjectPtr
14447
402
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14448
402
    xmlXPathParserContextPtr ctxt;
14449
402
    xmlXPathObjectPtr res;
14450
14451
402
    CHECK_CTXT(ctx)
14452
14453
402
    xmlInitParser();
14454
14455
402
    ctxt = xmlXPathNewParserContext(str, ctx);
14456
402
    if (ctxt == NULL)
14457
0
        return NULL;
14458
402
    xmlXPathEvalExpr(ctxt);
14459
14460
402
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14461
4
  res = NULL;
14462
398
    } else {
14463
398
  res = valuePop(ctxt);
14464
398
        if (res == NULL) {
14465
0
            xmlGenericError(xmlGenericErrorContext,
14466
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14467
398
        } else if (ctxt->valueNr > 0) {
14468
0
            xmlGenericError(xmlGenericErrorContext,
14469
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14470
0
                ctxt->valueNr);
14471
0
        }
14472
398
    }
14473
14474
402
    xmlXPathFreeParserContext(ctxt);
14475
402
    return(res);
14476
402
}
14477
14478
/**
14479
 * xmlXPathSetContextNode:
14480
 * @node: the node to to use as the context node
14481
 * @ctx:  the XPath context
14482
 *
14483
 * Sets 'node' as the context node. The node must be in the same
14484
 * document as that associated with the context.
14485
 *
14486
 * Returns -1 in case of error or 0 if successful
14487
 */
14488
int
14489
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14490
0
    if ((node == NULL) || (ctx == NULL))
14491
0
        return(-1);
14492
14493
0
    if (node->doc == ctx->doc) {
14494
0
        ctx->node = node;
14495
0
  return(0);
14496
0
    }
14497
0
    return(-1);
14498
0
}
14499
14500
/**
14501
 * xmlXPathNodeEval:
14502
 * @node: the node to to use as the context node
14503
 * @str:  the XPath expression
14504
 * @ctx:  the XPath context
14505
 *
14506
 * Evaluate the XPath Location Path in the given context. The node 'node'
14507
 * is set as the context node. The context node is not restored.
14508
 *
14509
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14510
 *         the caller has to free the object.
14511
 */
14512
xmlXPathObjectPtr
14513
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14514
0
    if (str == NULL)
14515
0
        return(NULL);
14516
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14517
0
        return(NULL);
14518
0
    return(xmlXPathEval(str, ctx));
14519
0
}
14520
14521
/**
14522
 * xmlXPathEvalExpression:
14523
 * @str:  the XPath expression
14524
 * @ctxt:  the XPath context
14525
 *
14526
 * Alias for xmlXPathEval().
14527
 *
14528
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14529
 *         the caller has to free the object.
14530
 */
14531
xmlXPathObjectPtr
14532
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14533
0
    return(xmlXPathEval(str, ctxt));
14534
0
}
14535
14536
/************************************************************************
14537
 *                  *
14538
 *  Extra functions not pertaining to the XPath spec    *
14539
 *                  *
14540
 ************************************************************************/
14541
/**
14542
 * xmlXPathEscapeUriFunction:
14543
 * @ctxt:  the XPath Parser context
14544
 * @nargs:  the number of arguments
14545
 *
14546
 * Implement the escape-uri() XPath function
14547
 *    string escape-uri(string $str, bool $escape-reserved)
14548
 *
14549
 * This function applies the URI escaping rules defined in section 2 of [RFC
14550
 * 2396] to the string supplied as $uri-part, which typically represents all
14551
 * or part of a URI. The effect of the function is to replace any special
14552
 * character in the string by an escape sequence of the form %xx%yy...,
14553
 * where xxyy... is the hexadecimal representation of the octets used to
14554
 * represent the character in UTF-8.
14555
 *
14556
 * The set of characters that are escaped depends on the setting of the
14557
 * boolean argument $escape-reserved.
14558
 *
14559
 * If $escape-reserved is true, all characters are escaped other than lower
14560
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14561
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14562
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14563
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14564
 * A-F).
14565
 *
14566
 * If $escape-reserved is false, the behavior differs in that characters
14567
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14568
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14569
 *
14570
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14571
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14572
 * compared using string comparison functions, this function must always use
14573
 * the upper-case letters A-F.
14574
 *
14575
 * Generally, $escape-reserved should be set to true when escaping a string
14576
 * that is to form a single part of a URI, and to false when escaping an
14577
 * entire URI or URI reference.
14578
 *
14579
 * In the case of non-ascii characters, the string is encoded according to
14580
 * utf-8 and then converted according to RFC 2396.
14581
 *
14582
 * Examples
14583
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14584
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14585
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14586
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14587
 *
14588
 */
14589
static void
14590
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14591
0
    xmlXPathObjectPtr str;
14592
0
    int escape_reserved;
14593
0
    xmlBufPtr target;
14594
0
    xmlChar *cptr;
14595
0
    xmlChar escape[4];
14596
14597
0
    CHECK_ARITY(2);
14598
14599
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14600
14601
0
    CAST_TO_STRING;
14602
0
    str = valuePop(ctxt);
14603
14604
0
    target = xmlBufCreate();
14605
14606
0
    escape[0] = '%';
14607
0
    escape[3] = 0;
14608
14609
0
    if (target) {
14610
0
  for (cptr = str->stringval; *cptr; cptr++) {
14611
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14612
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14613
0
    (*cptr >= '0' && *cptr <= '9') ||
14614
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14615
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14616
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14617
0
    (*cptr == '%' &&
14618
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14619
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14620
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14621
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14622
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14623
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14624
0
    (!escape_reserved &&
14625
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14626
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14627
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14628
0
      *cptr == ','))) {
14629
0
    xmlBufAdd(target, cptr, 1);
14630
0
      } else {
14631
0
    if ((*cptr >> 4) < 10)
14632
0
        escape[1] = '0' + (*cptr >> 4);
14633
0
    else
14634
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14635
0
    if ((*cptr & 0xF) < 10)
14636
0
        escape[2] = '0' + (*cptr & 0xF);
14637
0
    else
14638
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14639
14640
0
    xmlBufAdd(target, &escape[0], 3);
14641
0
      }
14642
0
  }
14643
0
    }
14644
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14645
0
  xmlBufContent(target)));
14646
0
    xmlBufFree(target);
14647
0
    xmlXPathReleaseObject(ctxt->context, str);
14648
0
}
14649
14650
/**
14651
 * xmlXPathRegisterAllFunctions:
14652
 * @ctxt:  the XPath context
14653
 *
14654
 * Registers all default XPath functions in this context
14655
 */
14656
void
14657
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14658
404
{
14659
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14660
404
                         xmlXPathBooleanFunction);
14661
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14662
404
                         xmlXPathCeilingFunction);
14663
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14664
404
                         xmlXPathCountFunction);
14665
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14666
404
                         xmlXPathConcatFunction);
14667
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14668
404
                         xmlXPathContainsFunction);
14669
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14670
404
                         xmlXPathIdFunction);
14671
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14672
404
                         xmlXPathFalseFunction);
14673
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14674
404
                         xmlXPathFloorFunction);
14675
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14676
404
                         xmlXPathLastFunction);
14677
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14678
404
                         xmlXPathLangFunction);
14679
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14680
404
                         xmlXPathLocalNameFunction);
14681
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14682
404
                         xmlXPathNotFunction);
14683
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14684
404
                         xmlXPathNameFunction);
14685
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14686
404
                         xmlXPathNamespaceURIFunction);
14687
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14688
404
                         xmlXPathNormalizeFunction);
14689
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14690
404
                         xmlXPathNumberFunction);
14691
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14692
404
                         xmlXPathPositionFunction);
14693
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14694
404
                         xmlXPathRoundFunction);
14695
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14696
404
                         xmlXPathStringFunction);
14697
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14698
404
                         xmlXPathStringLengthFunction);
14699
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14700
404
                         xmlXPathStartsWithFunction);
14701
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14702
404
                         xmlXPathSubstringFunction);
14703
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14704
404
                         xmlXPathSubstringBeforeFunction);
14705
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14706
404
                         xmlXPathSubstringAfterFunction);
14707
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14708
404
                         xmlXPathSumFunction);
14709
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14710
404
                         xmlXPathTrueFunction);
14711
404
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14712
404
                         xmlXPathTranslateFunction);
14713
14714
404
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14715
404
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14716
404
                         xmlXPathEscapeUriFunction);
14717
404
}
14718
14719
#endif /* LIBXML_XPATH_ENABLED */