Coverage Report

Created: 2023-03-26 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
634
    xmlGenericError(xmlGenericErrorContext,       \
62
634
      "Unimplemented block at %s:%d\n",       \
63
634
            __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
26.0k
#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
21.2k
#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
2.71M
#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
static void
149
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
150
151
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
152
/**
153
 * xmlXPathCmpNodesExt:
154
 * @node1:  the first node
155
 * @node2:  the second node
156
 *
157
 * Compare two nodes w.r.t document order.
158
 * This one is optimized for handling of non-element nodes.
159
 *
160
 * Returns -2 in case of error 1 if first point < second point, 0 if
161
 *         it's the same node, -1 otherwise
162
 */
163
static int
164
765k
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
165
765k
    int depth1, depth2;
166
765k
    int misc = 0, precedence1 = 0, precedence2 = 0;
167
765k
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
168
765k
    xmlNodePtr cur, root;
169
765k
    ptrdiff_t l1, l2;
170
171
765k
    if ((node1 == NULL) || (node2 == NULL))
172
0
  return(-2);
173
174
765k
    if (node1 == node2)
175
0
  return(0);
176
177
    /*
178
     * a couple of optimizations which will avoid computations in most cases
179
     */
180
765k
    switch (node1->type) {
181
574k
  case XML_ELEMENT_NODE:
182
574k
      if (node2->type == XML_ELEMENT_NODE) {
183
446k
    if ((0 > (ptrdiff_t) node1->content) &&
184
446k
        (0 > (ptrdiff_t) node2->content) &&
185
446k
        (node1->doc == node2->doc))
186
284k
    {
187
284k
        l1 = -((ptrdiff_t) node1->content);
188
284k
        l2 = -((ptrdiff_t) node2->content);
189
284k
        if (l1 < l2)
190
283k
      return(1);
191
512
        if (l1 > l2)
192
512
      return(-1);
193
512
    } else
194
162k
        goto turtle_comparison;
195
446k
      }
196
128k
      break;
197
128k
  case XML_ATTRIBUTE_NODE:
198
0
      precedence1 = 1; /* element is owner */
199
0
      miscNode1 = node1;
200
0
      node1 = node1->parent;
201
0
      misc = 1;
202
0
      break;
203
108k
  case XML_TEXT_NODE:
204
108k
  case XML_CDATA_SECTION_NODE:
205
110k
  case XML_COMMENT_NODE:
206
114k
  case XML_PI_NODE: {
207
114k
      miscNode1 = node1;
208
      /*
209
      * Find nearest element node.
210
      */
211
114k
      if (node1->prev != NULL) {
212
132k
    do {
213
132k
        node1 = node1->prev;
214
132k
        if (node1->type == XML_ELEMENT_NODE) {
215
92.5k
      precedence1 = 3; /* element in prev-sibl axis */
216
92.5k
      break;
217
92.5k
        }
218
40.0k
        if (node1->prev == NULL) {
219
2.28k
      precedence1 = 2; /* element is parent */
220
      /*
221
      * URGENT TODO: Are there any cases, where the
222
      * parent of such a node is not an element node?
223
      */
224
2.28k
      node1 = node1->parent;
225
2.28k
      break;
226
2.28k
        }
227
40.0k
    } while (1);
228
94.8k
      } else {
229
19.6k
    precedence1 = 2; /* element is parent */
230
19.6k
    node1 = node1->parent;
231
19.6k
      }
232
114k
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
233
114k
    (0 <= (ptrdiff_t) node1->content)) {
234
    /*
235
    * Fallback for whatever case.
236
    */
237
2
    node1 = miscNode1;
238
2
    precedence1 = 0;
239
2
      } else
240
114k
    misc = 1;
241
114k
  }
242
0
      break;
243
69.6k
  case XML_NAMESPACE_DECL:
244
      /*
245
      * TODO: why do we return 1 for namespace nodes?
246
      */
247
69.6k
      return(1);
248
6.63k
  default:
249
6.63k
      break;
250
765k
    }
251
249k
    switch (node2->type) {
252
81.8k
  case XML_ELEMENT_NODE:
253
81.8k
      break;
254
0
  case XML_ATTRIBUTE_NODE:
255
0
      precedence2 = 1; /* element is owner */
256
0
      miscNode2 = node2;
257
0
      node2 = node2->parent;
258
0
      misc = 1;
259
0
      break;
260
107k
  case XML_TEXT_NODE:
261
107k
  case XML_CDATA_SECTION_NODE:
262
107k
  case XML_COMMENT_NODE:
263
111k
  case XML_PI_NODE: {
264
111k
      miscNode2 = node2;
265
111k
      if (node2->prev != NULL) {
266
146k
    do {
267
146k
        node2 = node2->prev;
268
146k
        if (node2->type == XML_ELEMENT_NODE) {
269
91.9k
      precedence2 = 3; /* element in prev-sibl axis */
270
91.9k
      break;
271
91.9k
        }
272
54.3k
        if (node2->prev == NULL) {
273
348
      precedence2 = 2; /* element is parent */
274
348
      node2 = node2->parent;
275
348
      break;
276
348
        }
277
54.3k
    } while (1);
278
92.3k
      } else {
279
19.4k
    precedence2 = 2; /* element is parent */
280
19.4k
    node2 = node2->parent;
281
19.4k
      }
282
111k
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
283
111k
    (0 <= (ptrdiff_t) node2->content))
284
1
      {
285
1
    node2 = miscNode2;
286
1
    precedence2 = 0;
287
1
      } else
288
111k
    misc = 1;
289
111k
  }
290
0
      break;
291
55.4k
  case XML_NAMESPACE_DECL:
292
55.4k
      return(1);
293
6
  default:
294
6
      break;
295
249k
    }
296
193k
    if (misc) {
297
187k
  if (node1 == node2) {
298
85.5k
      if (precedence1 == precedence2) {
299
    /*
300
    * The ugly case; but normally there aren't many
301
    * adjacent non-element nodes around.
302
    */
303
4.32k
    cur = miscNode2->prev;
304
4.39k
    while (cur != NULL) {
305
4.39k
        if (cur == miscNode1)
306
4.31k
      return(1);
307
84
        if (cur->type == XML_ELEMENT_NODE)
308
17
      return(-1);
309
67
        cur = cur->prev;
310
67
    }
311
0
    return (-1);
312
81.1k
      } else {
313
    /*
314
    * Evaluate based on higher precedence wrt to the element.
315
    * TODO: This assumes attributes are sorted before content.
316
    *   Is this 100% correct?
317
    */
318
81.1k
    if (precedence1 < precedence2)
319
80.8k
        return(1);
320
327
    else
321
327
        return(-1);
322
81.1k
      }
323
85.5k
  }
324
  /*
325
  * Special case: One of the helper-elements is contained by the other.
326
  * <foo>
327
  *   <node2>
328
  *     <node1>Text-1(precedence1 == 2)</node1>
329
  *   </node2>
330
  *   Text-6(precedence2 == 3)
331
  * </foo>
332
  */
333
101k
  if ((precedence2 == 3) && (precedence1 > 1)) {
334
7.58k
      cur = node1->parent;
335
310k
      while (cur) {
336
302k
    if (cur == node2)
337
198
        return(1);
338
302k
    cur = cur->parent;
339
302k
      }
340
7.58k
  }
341
101k
  if ((precedence1 == 3) && (precedence2 > 1)) {
342
7.06k
      cur = node2->parent;
343
298k
      while (cur) {
344
291k
    if (cur == node1)
345
56
        return(-1);
346
291k
    cur = cur->parent;
347
291k
      }
348
7.06k
  }
349
101k
    }
350
351
    /*
352
     * Speedup using document order if available.
353
     */
354
107k
    if ((node1->type == XML_ELEMENT_NODE) &&
355
107k
  (node2->type == XML_ELEMENT_NODE) &&
356
107k
  (0 > (ptrdiff_t) node1->content) &&
357
107k
  (0 > (ptrdiff_t) node2->content) &&
358
107k
  (node1->doc == node2->doc)) {
359
360
101k
  l1 = -((ptrdiff_t) node1->content);
361
101k
  l2 = -((ptrdiff_t) node2->content);
362
101k
  if (l1 < l2)
363
99.9k
      return(1);
364
1.31k
  if (l1 > l2)
365
1.31k
      return(-1);
366
1.31k
    }
367
368
169k
turtle_comparison:
369
370
169k
    if (node1 == node2->prev)
371
162k
  return(1);
372
6.64k
    if (node1 == node2->next)
373
0
  return(-1);
374
    /*
375
     * compute depth to root
376
     */
377
6.89k
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
378
6.88k
  if (cur->parent == node1)
379
6.63k
      return(1);
380
250
  depth2++;
381
250
    }
382
6
    root = cur;
383
16
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
384
16
  if (cur->parent == node2)
385
6
      return(-1);
386
10
  depth1++;
387
10
    }
388
    /*
389
     * Distinct document (or distinct entities :-( ) case.
390
     */
391
0
    if (root != cur) {
392
0
  return(-2);
393
0
    }
394
    /*
395
     * get the nearest common ancestor.
396
     */
397
0
    while (depth1 > depth2) {
398
0
  depth1--;
399
0
  node1 = node1->parent;
400
0
    }
401
0
    while (depth2 > depth1) {
402
0
  depth2--;
403
0
  node2 = node2->parent;
404
0
    }
405
0
    while (node1->parent != node2->parent) {
406
0
  node1 = node1->parent;
407
0
  node2 = node2->parent;
408
  /* should not happen but just in case ... */
409
0
  if ((node1 == NULL) || (node2 == NULL))
410
0
      return(-2);
411
0
    }
412
    /*
413
     * Find who's first.
414
     */
415
0
    if (node1 == node2->prev)
416
0
  return(1);
417
0
    if (node1 == node2->next)
418
0
  return(-1);
419
    /*
420
     * Speedup using document order if available.
421
     */
422
0
    if ((node1->type == XML_ELEMENT_NODE) &&
423
0
  (node2->type == XML_ELEMENT_NODE) &&
424
0
  (0 > (ptrdiff_t) node1->content) &&
425
0
  (0 > (ptrdiff_t) node2->content) &&
426
0
  (node1->doc == node2->doc)) {
427
428
0
  l1 = -((ptrdiff_t) node1->content);
429
0
  l2 = -((ptrdiff_t) node2->content);
430
0
  if (l1 < l2)
431
0
      return(1);
432
0
  if (l1 > l2)
433
0
      return(-1);
434
0
    }
435
436
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
437
0
  if (cur == node2)
438
0
      return(1);
439
0
    return(-1); /* assume there is no sibling list corruption */
440
0
}
441
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
442
443
/*
444
 * Wrapper for the Timsort algorithm from timsort.h
445
 */
446
#ifdef WITH_TIM_SORT
447
#define SORT_NAME libxml_domnode
448
27.2k
#define SORT_TYPE xmlNodePtr
449
/**
450
 * wrap_cmp:
451
 * @x: a node
452
 * @y: another node
453
 *
454
 * Comparison function for the Timsort implementation
455
 *
456
 * Returns -2 in case of error -1 if first point < second point, 0 if
457
 *         it's the same node, +1 otherwise
458
 */
459
static
460
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
461
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
462
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463
710k
    {
464
710k
        int res = xmlXPathCmpNodesExt(x, y);
465
710k
        return res == -2 ? res : -res;
466
710k
    }
467
#else
468
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
469
    {
470
        int res = xmlXPathCmpNodes(x, y);
471
        return res == -2 ? res : -res;
472
    }
473
#endif
474
710k
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
475
#include "timsort.h"
476
#endif /* WITH_TIM_SORT */
477
478
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
479
480
/************************************************************************
481
 *                  *
482
 *      Floating point stuff        *
483
 *                  *
484
 ************************************************************************/
485
486
double xmlXPathNAN = 0.0;
487
double xmlXPathPINF = 0.0;
488
double xmlXPathNINF = 0.0;
489
490
/**
491
 * xmlXPathInit:
492
 *
493
 * DEPRECATED: Alias for xmlInitParser.
494
 */
495
void
496
0
xmlXPathInit(void) {
497
0
    xmlInitParser();
498
0
}
499
500
/**
501
 * xmlInitXPathInternal:
502
 *
503
 * Initialize the XPath environment
504
 */
505
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
506
void
507
2
xmlInitXPathInternal(void) {
508
2
#if defined(NAN) && defined(INFINITY)
509
2
    xmlXPathNAN = NAN;
510
2
    xmlXPathPINF = INFINITY;
511
2
    xmlXPathNINF = -INFINITY;
512
#else
513
    /* MSVC doesn't allow division by zero in constant expressions. */
514
    double zero = 0.0;
515
    xmlXPathNAN = 0.0 / zero;
516
    xmlXPathPINF = 1.0 / zero;
517
    xmlXPathNINF = -xmlXPathPINF;
518
#endif
519
2
}
520
521
/**
522
 * xmlXPathIsNaN:
523
 * @val:  a double value
524
 *
525
 * Returns 1 if the value is a NaN, 0 otherwise
526
 */
527
int
528
479k
xmlXPathIsNaN(double val) {
529
479k
#ifdef isnan
530
479k
    return isnan(val);
531
#else
532
    return !(val == val);
533
#endif
534
479k
}
535
536
/**
537
 * xmlXPathIsInf:
538
 * @val:  a double value
539
 *
540
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
541
 */
542
int
543
472k
xmlXPathIsInf(double val) {
544
472k
#ifdef isinf
545
472k
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
546
#else
547
    if (val >= xmlXPathPINF)
548
        return 1;
549
    if (val <= -xmlXPathPINF)
550
        return -1;
551
    return 0;
552
#endif
553
472k
}
554
555
#endif /* SCHEMAS or XPATH */
556
557
#ifdef LIBXML_XPATH_ENABLED
558
559
/*
560
 * TODO: when compatibility allows remove all "fake node libxslt" strings
561
 *       the test should just be name[0] = ' '
562
 */
563
#ifdef DEBUG_XPATH_EXPRESSION
564
#define DEBUG_STEP
565
#define DEBUG_EXPR
566
#define DEBUG_EVAL_COUNTS
567
#endif
568
569
static xmlNs xmlXPathXMLNamespaceStruct = {
570
    NULL,
571
    XML_NAMESPACE_DECL,
572
    XML_XML_NAMESPACE,
573
    BAD_CAST "xml",
574
    NULL,
575
    NULL
576
};
577
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578
#ifndef LIBXML_THREAD_ENABLED
579
/*
580
 * Optimizer is disabled only when threaded apps are detected while
581
 * the library ain't compiled for thread safety.
582
 */
583
static int xmlXPathDisableOptimizer = 0;
584
#endif
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
54
    { 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
14.9k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
635
14.9k
       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
147
{
646
147
    if (ctxt != NULL) {
647
14
        xmlResetError(&ctxt->lastError);
648
14
        if (extra) {
649
13
            xmlChar buf[200];
650
651
13
            xmlStrPrintf(buf, 200,
652
13
                         "Memory allocation failed : %s\n",
653
13
                         extra);
654
13
            ctxt->lastError.message = (char *) xmlStrdup(buf);
655
13
        } else {
656
1
            ctxt->lastError.message = (char *)
657
1
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
658
1
        }
659
14
        ctxt->lastError.domain = XML_FROM_XPATH;
660
14
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
661
14
  if (ctxt->error != NULL)
662
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
663
133
    } else {
664
133
        if (extra)
665
133
            __xmlRaiseError(NULL, NULL, NULL,
666
133
                            NULL, NULL, XML_FROM_XPATH,
667
133
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668
133
                            extra, NULL, NULL, 0, 0,
669
133
                            "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
133
    }
677
147
}
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
13
{
689
13
    if (ctxt == NULL)
690
0
  xmlXPathErrMemory(NULL, extra);
691
13
    else {
692
13
  ctxt->error = XPATH_MEMORY_ERROR;
693
13
  xmlXPathErrMemory(ctxt->context, extra);
694
13
    }
695
13
}
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
14.9k
{
707
14.9k
    if ((error < 0) || (error > MAXERRNO))
708
0
  error = MAXERRNO;
709
14.9k
    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
14.9k
    if (ctxt->error != 0)
720
268
        return;
721
14.7k
    ctxt->error = error;
722
14.7k
    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
14.7k
    xmlResetError(&ctxt->context->lastError);
735
736
14.7k
    ctxt->context->lastError.domain = XML_FROM_XPATH;
737
14.7k
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738
14.7k
                           XPATH_EXPRESSION_OK;
739
14.7k
    ctxt->context->lastError.level = XML_ERR_ERROR;
740
14.7k
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741
14.7k
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742
14.7k
    ctxt->context->lastError.node = ctxt->context->debugNode;
743
14.7k
    if (ctxt->context->error != NULL) {
744
0
  ctxt->context->error(ctxt->context->userData,
745
0
                       &ctxt->context->lastError);
746
14.7k
    } else {
747
14.7k
  __xmlRaiseError(NULL, NULL, NULL,
748
14.7k
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749
14.7k
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750
14.7k
      XML_ERR_ERROR, NULL, 0,
751
14.7k
      (const char *) ctxt->base, NULL, NULL,
752
14.7k
      ctxt->cur - ctxt->base, 0,
753
14.7k
      "%s", xmlXPathErrorMessages[error]);
754
14.7k
    }
755
756
14.7k
}
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
488
              int line ATTRIBUTE_UNUSED, int no) {
770
488
    xmlXPathErr(ctxt, no);
771
488
}
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
7.82M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783
7.82M
    xmlXPathContextPtr xpctxt = ctxt->context;
784
785
7.82M
    if ((opCount > xpctxt->opLimit) ||
786
7.82M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787
105
        xpctxt->opCount = xpctxt->opLimit;
788
105
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789
105
        return(-1);
790
105
    }
791
792
7.82M
    xpctxt->opCount += opCount;
793
7.82M
    return(0);
794
7.82M
}
795
796
#define OP_LIMIT_EXCEEDED(ctxt, n) \
797
7.76M
    ((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
1.74M
{
826
1.74M
    if (list->size <= list->number) {
827
551
        void **tmp;
828
551
        size_t newSize;
829
830
551
        if (list->size == 0) {
831
355
            if (initialSize <= 0)
832
0
                initialSize = 1;
833
355
            newSize = initialSize;
834
355
        } else {
835
196
            if (list->size > 50000000) {
836
0
                xmlXPathErrMemory(NULL,
837
0
                    "xmlPointerListAddSize: re-allocating item\n");
838
0
                return(-1);
839
0
            }
840
196
      newSize = list->size * 2;
841
196
        }
842
551
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843
551
  if (tmp == NULL) {
844
0
      xmlXPathErrMemory(NULL,
845
0
    "xmlPointerListAddSize: re-allocating item\n");
846
0
      return(-1);
847
0
  }
848
551
        list->items = tmp;
849
551
        list->size = newSize;
850
551
    }
851
1.74M
    list->items[list->number++] = item;
852
1.74M
    return(0);
853
1.74M
}
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
356
{
865
356
    xmlPointerListPtr ret;
866
867
356
    ret = xmlMalloc(sizeof(xmlPointerList));
868
356
    if (ret == NULL) {
869
1
  xmlXPathErrMemory(NULL,
870
1
      "xmlPointerListCreate: allocating item\n");
871
1
  return (NULL);
872
1
    }
873
355
    memset(ret, 0, sizeof(xmlPointerList));
874
355
    if (initialSize > 0) {
875
355
  xmlPointerListAddSize(ret, NULL, initialSize);
876
355
  ret->number = 0;
877
355
    }
878
355
    return (ret);
879
356
}
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
355
{
890
355
    if (list == NULL)
891
0
  return;
892
355
    if (list->items != NULL)
893
355
  xmlFree(list->items);
894
355
    xmlFree(list);
895
355
}
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
22.5k
xmlXPathNewCompExpr(void) {
1028
22.5k
    xmlXPathCompExprPtr cur;
1029
1030
22.5k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031
22.5k
    if (cur == NULL) {
1032
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1033
0
  return(NULL);
1034
0
    }
1035
22.5k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1036
22.5k
    cur->maxStep = 10;
1037
22.5k
    cur->nbStep = 0;
1038
22.5k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039
22.5k
                                     sizeof(xmlXPathStepOp));
1040
22.5k
    if (cur->steps == NULL) {
1041
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1042
0
  xmlFree(cur);
1043
0
  return(NULL);
1044
0
    }
1045
22.5k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046
22.5k
    cur->last = -1;
1047
#ifdef DEBUG_EVAL_COUNTS
1048
    cur->nb = 0;
1049
#endif
1050
22.5k
    return(cur);
1051
22.5k
}
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
22.5k
{
1062
22.5k
    xmlXPathStepOpPtr op;
1063
22.5k
    int i;
1064
1065
22.5k
    if (comp == NULL)
1066
0
        return;
1067
22.5k
    if (comp->dict == NULL) {
1068
2.24M
  for (i = 0; i < comp->nbStep; i++) {
1069
2.21M
      op = &comp->steps[i];
1070
2.21M
      if (op->value4 != NULL) {
1071
7.54k
    if (op->op == XPATH_OP_VALUE)
1072
844
        xmlXPathFreeObject(op->value4);
1073
6.70k
    else
1074
6.70k
        xmlFree(op->value4);
1075
7.54k
      }
1076
2.21M
      if (op->value5 != NULL)
1077
497k
    xmlFree(op->value5);
1078
2.21M
  }
1079
22.5k
    } 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
22.5k
    if (comp->steps != NULL) {
1090
22.5k
        xmlFree(comp->steps);
1091
22.5k
    }
1092
#ifdef DEBUG_EVAL_COUNTS
1093
    if (comp->string != NULL) {
1094
        xmlFree(comp->string);
1095
    }
1096
#endif
1097
22.5k
#ifdef XPATH_STREAMING
1098
22.5k
    if (comp->stream != NULL) {
1099
1.05k
        xmlFreePatternList(comp->stream);
1100
1.05k
    }
1101
22.5k
#endif
1102
22.5k
    if (comp->expr != NULL) {
1103
6.76k
        xmlFree(comp->expr);
1104
6.76k
    }
1105
1106
22.5k
    xmlFree(comp);
1107
22.5k
}
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
2.21M
   int value2, int value3, void *value4, void *value5) {
1129
2.21M
    xmlXPathCompExprPtr comp = ctxt->comp;
1130
2.21M
    if (comp->nbStep >= comp->maxStep) {
1131
26.0k
  xmlXPathStepOp *real;
1132
1133
26.0k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1134
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1135
0
      return(-1);
1136
0
        }
1137
26.0k
  comp->maxStep *= 2;
1138
26.0k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139
26.0k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1140
26.0k
  if (real == NULL) {
1141
0
      comp->maxStep /= 2;
1142
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1143
0
      return(-1);
1144
0
  }
1145
26.0k
  comp->steps = real;
1146
26.0k
    }
1147
2.21M
    comp->last = comp->nbStep;
1148
2.21M
    comp->steps[comp->nbStep].ch1 = ch1;
1149
2.21M
    comp->steps[comp->nbStep].ch2 = ch2;
1150
2.21M
    comp->steps[comp->nbStep].op = op;
1151
2.21M
    comp->steps[comp->nbStep].value = value;
1152
2.21M
    comp->steps[comp->nbStep].value2 = value2;
1153
2.21M
    comp->steps[comp->nbStep].value3 = value3;
1154
2.21M
    if ((comp->dict != NULL) &&
1155
2.21M
        ((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
2.21M
    } else {
1170
2.21M
  comp->steps[comp->nbStep].value4 = value4;
1171
2.21M
  comp->steps[comp->nbStep].value5 = value5;
1172
2.21M
    }
1173
2.21M
    comp->steps[comp->nbStep].cache = NULL;
1174
2.21M
    return(comp->nbStep++);
1175
2.21M
}
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
545
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186
545
    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
545
    tmp = op->ch1;
1199
545
    op->ch1 = op->ch2;
1200
545
    op->ch2 = tmp;
1201
545
}
1202
1203
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204
571k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1205
571k
                  (op), (val), (val2), (val3), (val4), (val5))
1206
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1207
119k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1208
119k
                  (op), (val), (val2), (val3), (val4), (val5))
1209
1210
954k
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1211
954k
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212
1213
65.7k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1214
65.7k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215
1216
506k
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1217
506k
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1218
506k
      (val), (val2), 0 ,NULL ,NULL)
1219
1220
/************************************************************************
1221
 *                  *
1222
 *    XPath object cache structures       *
1223
 *                  *
1224
 ************************************************************************/
1225
1226
/* #define XP_DEFAULT_CACHE_ON */
1227
1228
619k
#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
154
{
2216
154
    xmlXPathContextCachePtr ret;
2217
2218
154
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219
154
    if (ret == NULL) {
2220
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2221
0
  return(NULL);
2222
0
    }
2223
154
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2224
154
    ret->maxNodeset = 100;
2225
154
    ret->maxString = 100;
2226
154
    ret->maxBoolean = 100;
2227
154
    ret->maxNumber = 100;
2228
154
    ret->maxMisc = 100;
2229
154
    return(ret);
2230
154
}
2231
2232
static void
2233
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234
355
{
2235
355
    int i;
2236
355
    xmlXPathObjectPtr obj;
2237
2238
355
    if (list == NULL)
2239
0
  return;
2240
2241
5.74k
    for (i = 0; i < list->number; i++) {
2242
5.38k
  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
5.38k
  if (obj->nodesetval != NULL) {
2248
3.00k
      if (obj->nodesetval->nodeTab != NULL)
2249
2.82k
    xmlFree(obj->nodesetval->nodeTab);
2250
3.00k
      xmlFree(obj->nodesetval);
2251
3.00k
  }
2252
5.38k
  xmlFree(obj);
2253
#ifdef XP_DEBUG_OBJ_USAGE
2254
  xmlXPathDebugObjCounterAll--;
2255
#endif
2256
5.38k
    }
2257
355
    xmlPointerListFree(list);
2258
355
}
2259
2260
static void
2261
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262
152
{
2263
152
    if (cache == NULL)
2264
0
  return;
2265
152
    if (cache->nodesetObjs)
2266
152
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267
152
    if (cache->stringObjs)
2268
35
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2269
152
    if (cache->booleanObjs)
2270
24
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271
152
    if (cache->numberObjs)
2272
32
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2273
152
    if (cache->miscObjs)
2274
112
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2275
152
    xmlFree(cache);
2276
152
}
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
154
{
2306
154
    if (ctxt == NULL)
2307
0
  return(-1);
2308
154
    if (active) {
2309
154
  xmlXPathContextCachePtr cache;
2310
2311
154
  if (ctxt->cache == NULL) {
2312
154
      ctxt->cache = xmlXPathNewCache();
2313
154
      if (ctxt->cache == NULL)
2314
0
    return(-1);
2315
154
  }
2316
154
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2317
154
  if (options == 0) {
2318
154
      if (value < 0)
2319
154
    value = 100;
2320
154
      cache->maxNodeset = value;
2321
154
      cache->maxString = value;
2322
154
      cache->maxNumber = value;
2323
154
      cache->maxBoolean = value;
2324
154
      cache->maxMisc = value;
2325
154
  }
2326
154
    } else if (ctxt->cache != NULL) {
2327
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328
0
  ctxt->cache = NULL;
2329
0
    }
2330
154
    return(0);
2331
154
}
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
93.4k
{
2348
93.4k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349
93.4k
  xmlXPathContextCachePtr cache =
2350
93.4k
      (xmlXPathContextCachePtr) ctxt->cache;
2351
2352
93.4k
  if ((cache->miscObjs != NULL) &&
2353
93.4k
      (cache->miscObjs->number != 0))
2354
90.9k
  {
2355
90.9k
      xmlXPathObjectPtr ret;
2356
2357
90.9k
      ret = (xmlXPathObjectPtr)
2358
90.9k
    cache->miscObjs->items[--cache->miscObjs->number];
2359
90.9k
      ret->type = XPATH_NODESET;
2360
90.9k
      ret->nodesetval = val;
2361
#ifdef XP_DEBUG_OBJ_USAGE
2362
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363
#endif
2364
90.9k
      return(ret);
2365
90.9k
  }
2366
93.4k
    }
2367
2368
2.56k
    return(xmlXPathWrapNodeSet(val));
2369
2370
93.4k
}
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
167k
{
2385
167k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386
167k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387
2388
167k
  if ((cache->stringObjs != NULL) &&
2389
167k
      (cache->stringObjs->number != 0))
2390
165k
  {
2391
2392
165k
      xmlXPathObjectPtr ret;
2393
2394
165k
      ret = (xmlXPathObjectPtr)
2395
165k
    cache->stringObjs->items[--cache->stringObjs->number];
2396
165k
      ret->type = XPATH_STRING;
2397
165k
      ret->stringval = val;
2398
#ifdef XP_DEBUG_OBJ_USAGE
2399
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400
#endif
2401
165k
      return(ret);
2402
165k
  } else if ((cache->miscObjs != NULL) &&
2403
1.99k
      (cache->miscObjs->number != 0))
2404
1.85k
  {
2405
1.85k
      xmlXPathObjectPtr ret;
2406
      /*
2407
      * Fallback to misc-cache.
2408
      */
2409
1.85k
      ret = (xmlXPathObjectPtr)
2410
1.85k
    cache->miscObjs->items[--cache->miscObjs->number];
2411
2412
1.85k
      ret->type = XPATH_STRING;
2413
1.85k
      ret->stringval = val;
2414
#ifdef XP_DEBUG_OBJ_USAGE
2415
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416
#endif
2417
1.85k
      return(ret);
2418
1.85k
  }
2419
167k
    }
2420
134
    return(xmlXPathWrapString(val));
2421
167k
}
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
226k
{
2437
226k
    if ((ctxt != NULL) && (ctxt->cache)) {
2438
226k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439
2440
226k
  if ((cache->nodesetObjs != NULL) &&
2441
226k
      (cache->nodesetObjs->number != 0))
2442
226k
  {
2443
226k
      xmlXPathObjectPtr ret;
2444
      /*
2445
      * Use the nodeset-cache.
2446
      */
2447
226k
      ret = (xmlXPathObjectPtr)
2448
226k
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449
226k
      ret->type = XPATH_NODESET;
2450
226k
      ret->boolval = 0;
2451
226k
      if (val) {
2452
225k
    if ((ret->nodesetval->nodeMax == 0) ||
2453
225k
        (val->type == XML_NAMESPACE_DECL))
2454
1.92k
    {
2455
                    /* TODO: Check memory error. */
2456
1.92k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457
223k
    } else {
2458
223k
        ret->nodesetval->nodeTab[0] = val;
2459
223k
        ret->nodesetval->nodeNr = 1;
2460
223k
    }
2461
225k
      }
2462
#ifdef XP_DEBUG_OBJ_USAGE
2463
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464
#endif
2465
226k
      return(ret);
2466
226k
  } else if ((cache->miscObjs != NULL) &&
2467
254
      (cache->miscObjs->number != 0))
2468
87
  {
2469
87
      xmlXPathObjectPtr ret;
2470
87
            xmlNodeSetPtr set;
2471
      /*
2472
      * Fallback to misc-cache.
2473
      */
2474
2475
87
      set = xmlXPathNodeSetCreate(val);
2476
87
      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
87
      ret = (xmlXPathObjectPtr)
2483
87
    cache->miscObjs->items[--cache->miscObjs->number];
2484
2485
87
      ret->type = XPATH_NODESET;
2486
87
      ret->boolval = 0;
2487
87
      ret->nodesetval = set;
2488
#ifdef XP_DEBUG_OBJ_USAGE
2489
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490
#endif
2491
87
      return(ret);
2492
87
  }
2493
226k
    }
2494
167
    return(xmlXPathNewNodeSet(val));
2495
226k
}
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
313k
{
2510
313k
    if ((ctxt != NULL) && (ctxt->cache)) {
2511
313k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512
2513
313k
  if ((cache->stringObjs != NULL) &&
2514
313k
      (cache->stringObjs->number != 0))
2515
313k
  {
2516
313k
      xmlXPathObjectPtr ret;
2517
313k
            xmlChar *copy;
2518
2519
313k
            if (val == NULL)
2520
0
                val = BAD_CAST "";
2521
313k
            copy = xmlStrdup(val);
2522
313k
            if (copy == NULL) {
2523
1
                xmlXPathErrMemory(ctxt, NULL);
2524
1
                return(NULL);
2525
1
            }
2526
2527
313k
      ret = (xmlXPathObjectPtr)
2528
313k
    cache->stringObjs->items[--cache->stringObjs->number];
2529
313k
      ret->type = XPATH_STRING;
2530
313k
            ret->stringval = copy;
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
313k
      return(ret);
2535
313k
  } else if ((cache->miscObjs != NULL) &&
2536
156
      (cache->miscObjs->number != 0))
2537
45
  {
2538
45
      xmlXPathObjectPtr ret;
2539
45
            xmlChar *copy;
2540
2541
45
            if (val == NULL)
2542
0
                val = BAD_CAST "";
2543
45
            copy = xmlStrdup(val);
2544
45
            if (copy == NULL) {
2545
0
                xmlXPathErrMemory(ctxt, NULL);
2546
0
                return(NULL);
2547
0
            }
2548
2549
45
      ret = (xmlXPathObjectPtr)
2550
45
    cache->miscObjs->items[--cache->miscObjs->number];
2551
2552
45
      ret->type = XPATH_STRING;
2553
45
            ret->stringval = copy;
2554
#ifdef XP_DEBUG_OBJ_USAGE
2555
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556
#endif
2557
45
      return(ret);
2558
45
  }
2559
313k
    }
2560
111
    return(xmlXPathNewString(val));
2561
313k
}
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
0
{
2576
0
    return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2577
0
}
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
333k
{
2592
333k
    if ((ctxt != NULL) && (ctxt->cache)) {
2593
333k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595
333k
  if ((cache->booleanObjs != NULL) &&
2596
333k
      (cache->booleanObjs->number != 0))
2597
328k
  {
2598
328k
      xmlXPathObjectPtr ret;
2599
2600
328k
      ret = (xmlXPathObjectPtr)
2601
328k
    cache->booleanObjs->items[--cache->booleanObjs->number];
2602
328k
      ret->type = XPATH_BOOLEAN;
2603
328k
      ret->boolval = (val != 0);
2604
#ifdef XP_DEBUG_OBJ_USAGE
2605
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606
#endif
2607
328k
      return(ret);
2608
328k
  } else if ((cache->miscObjs != NULL) &&
2609
5.22k
      (cache->miscObjs->number != 0))
2610
18
  {
2611
18
      xmlXPathObjectPtr ret;
2612
2613
18
      ret = (xmlXPathObjectPtr)
2614
18
    cache->miscObjs->items[--cache->miscObjs->number];
2615
2616
18
      ret->type = XPATH_BOOLEAN;
2617
18
      ret->boolval = (val != 0);
2618
#ifdef XP_DEBUG_OBJ_USAGE
2619
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620
#endif
2621
18
      return(ret);
2622
18
  }
2623
333k
    }
2624
5.21k
    return(xmlXPathNewBoolean(val));
2625
333k
}
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
680k
{
2640
680k
     if ((ctxt != NULL) && (ctxt->cache)) {
2641
680k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643
680k
  if ((cache->numberObjs != NULL) &&
2644
680k
      (cache->numberObjs->number != 0))
2645
609k
  {
2646
609k
      xmlXPathObjectPtr ret;
2647
2648
609k
      ret = (xmlXPathObjectPtr)
2649
609k
    cache->numberObjs->items[--cache->numberObjs->number];
2650
609k
      ret->type = XPATH_NUMBER;
2651
609k
      ret->floatval = val;
2652
#ifdef XP_DEBUG_OBJ_USAGE
2653
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654
#endif
2655
609k
      return(ret);
2656
609k
  } else if ((cache->miscObjs != NULL) &&
2657
71.4k
      (cache->miscObjs->number != 0))
2658
6.54k
  {
2659
6.54k
      xmlXPathObjectPtr ret;
2660
2661
6.54k
      ret = (xmlXPathObjectPtr)
2662
6.54k
    cache->miscObjs->items[--cache->miscObjs->number];
2663
2664
6.54k
      ret->type = XPATH_NUMBER;
2665
6.54k
      ret->floatval = val;
2666
#ifdef XP_DEBUG_OBJ_USAGE
2667
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668
#endif
2669
6.54k
      return(ret);
2670
6.54k
  }
2671
680k
    }
2672
64.8k
    return(xmlXPathNewFloat(val));
2673
680k
}
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
169k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689
169k
    xmlChar *res = NULL;
2690
2691
169k
    if (val == NULL)
2692
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694
169k
    switch (val->type) {
2695
0
    case XPATH_UNDEFINED:
2696
#ifdef DEBUG_EXPR
2697
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698
#endif
2699
0
  break;
2700
2.01k
    case XPATH_NODESET:
2701
2.01k
    case XPATH_XSLT_TREE:
2702
2.01k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2703
2.01k
  break;
2704
1.97k
    case XPATH_STRING:
2705
1.97k
  return(val);
2706
82.7k
    case XPATH_BOOLEAN:
2707
82.7k
  res = xmlXPathCastBooleanToString(val->boolval);
2708
82.7k
  break;
2709
82.7k
    case XPATH_NUMBER:
2710
82.7k
  res = xmlXPathCastNumberToString(val->floatval);
2711
82.7k
  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
169k
    }
2721
167k
    xmlXPathReleaseObject(ctxt, val);
2722
167k
    if (res == NULL)
2723
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2724
167k
    return(xmlXPathCacheWrapString(ctxt, res));
2725
167k
}
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
619k
{
2740
619k
    if (val == NULL)
2741
0
  return(NULL);
2742
2743
619k
    if (XP_HAS_CACHE(ctxt)) {
2744
619k
  switch (val->type) {
2745
0
      case XPATH_NODESET:
2746
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2747
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748
147k
      case XPATH_STRING:
2749
147k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2750
0
      case XPATH_BOOLEAN:
2751
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752
472k
      case XPATH_NUMBER:
2753
472k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754
0
      default:
2755
0
    break;
2756
619k
  }
2757
619k
    }
2758
0
    return(xmlXPathObjectCopy(val));
2759
619k
}
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
165k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
165k
    xmlXPathObjectPtr ret;
2775
2776
165k
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2778
165k
    if (val->type == XPATH_BOOLEAN)
2779
0
  return(val);
2780
165k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781
165k
    xmlXPathReleaseObject(ctxt, val);
2782
165k
    return(ret);
2783
165k
}
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
197k
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798
197k
    xmlXPathObjectPtr ret;
2799
2800
197k
    if (val == NULL)
2801
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802
197k
    if (val->type == XPATH_NUMBER)
2803
0
  return(val);
2804
197k
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805
197k
    xmlXPathReleaseObject(ctxt, val);
2806
197k
    return(ret);
2807
197k
}
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
1.97M
{
2826
1.97M
    xmlXPathObjectPtr ret;
2827
2828
1.97M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829
1
        return (NULL);
2830
2831
1.97M
    ctxt->valueNr--;
2832
1.97M
    if (ctxt->valueNr > 0)
2833
1.14M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834
829k
    else
2835
829k
        ctxt->value = NULL;
2836
1.97M
    ret = ctxt->valueTab[ctxt->valueNr];
2837
1.97M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2838
1.97M
    return (ret);
2839
1.97M
}
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
1.97M
{
2855
1.97M
    if (ctxt == NULL) return(-1);
2856
1.97M
    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
4
  ctxt->error = XPATH_MEMORY_ERROR;
2862
4
        return(-1);
2863
4
    }
2864
1.97M
    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
1.97M
    ctxt->valueTab[ctxt->valueNr] = value;
2884
1.97M
    ctxt->value = value;
2885
1.97M
    return (ctxt->valueNr++);
2886
1.97M
}
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
2
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899
2
    xmlXPathObjectPtr obj;
2900
2
    int ret;
2901
2902
2
    obj = valuePop(ctxt);
2903
2
    if (obj == NULL) {
2904
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905
0
  return(0);
2906
0
    }
2907
2
    if (obj->type != XPATH_BOOLEAN)
2908
2
  ret = xmlXPathCastToBoolean(obj);
2909
0
    else
2910
0
        ret = obj->boolval;
2911
2
    xmlXPathReleaseObject(ctxt->context, obj);
2912
2
    return(ret);
2913
2
}
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
25.8k
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953
25.8k
    xmlXPathObjectPtr obj;
2954
25.8k
    xmlChar * ret;
2955
2956
25.8k
    obj = valuePop(ctxt);
2957
25.8k
    if (obj == NULL) {
2958
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959
0
  return(NULL);
2960
0
    }
2961
25.8k
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2962
    /* TODO: needs refactoring somewhere else */
2963
25.8k
    if (obj->stringval == ret)
2964
1
  obj->stringval = NULL;
2965
25.8k
    xmlXPathReleaseObject(ctxt->context, obj);
2966
25.8k
    return(ret);
2967
25.8k
}
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
23.8k
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980
23.8k
    xmlXPathObjectPtr obj;
2981
23.8k
    xmlNodeSetPtr ret;
2982
2983
23.8k
    if (ctxt == NULL) return(NULL);
2984
23.8k
    if (ctxt->value == NULL) {
2985
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986
0
  return(NULL);
2987
0
    }
2988
23.8k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2989
0
  xmlXPathSetTypeError(ctxt);
2990
0
  return(NULL);
2991
0
    }
2992
23.8k
    obj = valuePop(ctxt);
2993
23.8k
    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
23.8k
    obj->nodesetval = NULL;
3000
23.8k
    xmlXPathReleaseObject(ctxt->context, obj);
3001
23.8k
    return(ret);
3002
23.8k
}
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
17.1M
#define CUR (*ctxt->cur)
3057
112k
#define SKIP(val) ctxt->cur += (val)
3058
4.23M
#define NXT(val) ctxt->cur[(val)]
3059
240
#define CUR_PTR ctxt->cur
3060
2.15M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061
3062
#define COPY_BUF(l,b,i,v)                                              \
3063
542k
    if (l == 1) b[i++] = v;                                            \
3064
542k
    else i += xmlCopyChar(l,&b[i],v)
3065
3066
1.13M
#define NEXTL(l)  ctxt->cur += l
3067
3068
#define SKIP_BLANKS             \
3069
7.71M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070
3071
#define CURRENT (*ctxt->cur)
3072
8.00M
#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
11
#define UPPER_DOUBLE 1E9
3083
11
#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
0
#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
217
{
3101
217
    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
217
    default:
3111
217
  if (xmlXPathIsNaN(number)) {
3112
0
      if (buffersize > (int)sizeof("NaN"))
3113
0
    snprintf(buffer, buffersize, "NaN");
3114
217
  } else if (number == 0) {
3115
            /* Omit sign for negative zero. */
3116
0
      snprintf(buffer, buffersize, "0");
3117
217
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3118
217
                   (number == (int) number)) {
3119
206
      char work[30];
3120
206
      char *ptr, *cur;
3121
206
      int value = (int) number;
3122
3123
206
            ptr = &buffer[0];
3124
206
      if (value == 0) {
3125
0
    *ptr++ = '0';
3126
206
      } else {
3127
206
    snprintf(work, 29, "%d", value);
3128
206
    cur = &work[0];
3129
620
    while ((*cur) && (ptr - buffer < buffersize)) {
3130
414
        *ptr++ = *cur++;
3131
414
    }
3132
206
      }
3133
206
      if (ptr - buffer < buffersize) {
3134
206
    *ptr = 0;
3135
206
      } else if (buffersize > 0) {
3136
0
    ptr--;
3137
0
    *ptr = 0;
3138
0
      }
3139
206
  } 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
11
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3150
11
      int integer_place, fraction_place;
3151
11
      char *ptr;
3152
11
      char *after_fraction;
3153
11
      double absolute_value;
3154
11
      int size;
3155
3156
11
      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
11
      if ( ((absolute_value > UPPER_DOUBLE) ||
3164
11
      (absolute_value < LOWER_DOUBLE)) &&
3165
11
     (absolute_value != 0.0) ) {
3166
    /* Use scientific notation */
3167
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3168
0
    fraction_place = DBL_DIG - 1;
3169
0
    size = snprintf(work, sizeof(work),"%*.*e",
3170
0
       integer_place, fraction_place, number);
3171
0
    while ((size > 0) && (work[size] != 'e')) size--;
3172
3173
0
      }
3174
11
      else {
3175
    /* Use regular notation */
3176
11
    if (absolute_value > 0.0) {
3177
11
        integer_place = (int)log10(absolute_value);
3178
11
        if (integer_place > 0)
3179
0
            fraction_place = DBL_DIG - integer_place - 1;
3180
11
        else
3181
11
            fraction_place = DBL_DIG - integer_place;
3182
11
    } else {
3183
0
        fraction_place = 1;
3184
0
    }
3185
11
    size = snprintf(work, sizeof(work), "%0.*f",
3186
11
        fraction_place, number);
3187
11
      }
3188
3189
      /* Remove leading spaces sometimes inserted by snprintf */
3190
11
      while (work[0] == ' ') {
3191
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192
0
    size--;
3193
0
      }
3194
3195
      /* Remove fractional trailing zeroes */
3196
11
      after_fraction = work + size;
3197
11
      ptr = after_fraction;
3198
176
      while (*(--ptr) == '0')
3199
165
    ;
3200
11
      if (*ptr != '.')
3201
11
          ptr++;
3202
11
      while ((*ptr++ = *after_fraction++) != 0);
3203
3204
      /* Finally copy result back to caller */
3205
11
      size = strlen(work) + 1;
3206
11
      if (size > buffersize) {
3207
0
    work[buffersize - 1] = 0;
3208
0
    size = buffersize;
3209
0
      }
3210
11
      memmove(buffer, work, size);
3211
11
  }
3212
217
  break;
3213
217
    }
3214
217
}
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
152
xmlXPathOrderDocElems(xmlDocPtr doc) {
3238
152
    ptrdiff_t count = 0;
3239
152
    xmlNodePtr cur;
3240
3241
152
    if (doc == NULL)
3242
0
  return(-1);
3243
152
    cur = doc->children;
3244
50.3k
    while (cur != NULL) {
3245
50.2k
  if (cur->type == XML_ELEMENT_NODE) {
3246
27.8k
      cur->content = (void *) (-(++count));
3247
27.8k
      if (cur->children != NULL) {
3248
4.26k
    cur = cur->children;
3249
4.26k
    continue;
3250
4.26k
      }
3251
27.8k
  }
3252
45.9k
  if (cur->next != NULL) {
3253
45.6k
      cur = cur->next;
3254
45.6k
      continue;
3255
45.6k
  }
3256
4.38k
  do {
3257
4.38k
      cur = cur->parent;
3258
4.38k
      if (cur == NULL)
3259
0
    break;
3260
4.38k
      if (cur == (xmlNodePtr) doc) {
3261
119
    cur = NULL;
3262
119
    break;
3263
119
      }
3264
4.26k
      if (cur->next != NULL) {
3265
152
    cur = cur->next;
3266
152
    break;
3267
152
      }
3268
4.26k
  } while (cur != NULL);
3269
271
    }
3270
152
    return(count);
3271
152
}
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
157k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285
157k
    int depth1, depth2;
3286
157k
    int attr1 = 0, attr2 = 0;
3287
157k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288
157k
    xmlNodePtr cur, root;
3289
3290
157k
    if ((node1 == NULL) || (node2 == NULL))
3291
0
  return(-2);
3292
    /*
3293
     * a couple of optimizations which will avoid computations in most cases
3294
     */
3295
157k
    if (node1 == node2)    /* trivial case */
3296
0
  return(0);
3297
157k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3298
0
  attr1 = 1;
3299
0
  attrNode1 = node1;
3300
0
  node1 = node1->parent;
3301
0
    }
3302
157k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr2 = 1;
3304
0
  attrNode2 = node2;
3305
0
  node2 = node2->parent;
3306
0
    }
3307
157k
    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
157k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3326
157k
        (node2->type == XML_NAMESPACE_DECL))
3327
0
  return(1);
3328
157k
    if (node1 == node2->prev)
3329
571
  return(1);
3330
156k
    if (node1 == node2->next)
3331
0
  return(-1);
3332
3333
    /*
3334
     * Speedup using document order if available.
3335
     */
3336
156k
    if ((node1->type == XML_ELEMENT_NODE) &&
3337
156k
  (node2->type == XML_ELEMENT_NODE) &&
3338
156k
  (0 > (ptrdiff_t) node1->content) &&
3339
156k
  (0 > (ptrdiff_t) node2->content) &&
3340
156k
  (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
313k
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355
156k
  if (cur->parent == node1)
3356
0
      return(1);
3357
156k
  depth2++;
3358
156k
    }
3359
156k
    root = cur;
3360
313k
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361
156k
  if (cur->parent == node2)
3362
0
      return(-1);
3363
156k
  depth1++;
3364
156k
    }
3365
    /*
3366
     * Distinct document (or distinct entities :-( ) case.
3367
     */
3368
156k
    if (root != cur) {
3369
0
  return(-2);
3370
0
    }
3371
    /*
3372
     * get the nearest common ancestor.
3373
     */
3374
156k
    while (depth1 > depth2) {
3375
0
  depth1--;
3376
0
  node1 = node1->parent;
3377
0
    }
3378
156k
    while (depth2 > depth1) {
3379
0
  depth2--;
3380
0
  node2 = node2->parent;
3381
0
    }
3382
156k
    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
156k
    if (node1 == node2->prev)
3393
0
  return(1);
3394
156k
    if (node1 == node2->next)
3395
0
  return(-1);
3396
    /*
3397
     * Speedup using document order if available.
3398
     */
3399
156k
    if ((node1->type == XML_ELEMENT_NODE) &&
3400
156k
  (node2->type == XML_ELEMENT_NODE) &&
3401
156k
  (0 > (ptrdiff_t) node1->content) &&
3402
156k
  (0 > (ptrdiff_t) node2->content) &&
3403
156k
  (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
21.7M
    for (cur = node1->next;cur != NULL;cur = cur->next)
3415
21.7M
  if (cur == node2)
3416
156k
      return(1);
3417
0
    return(-1); /* assume there is no sibling list corruption */
3418
156k
}
3419
3420
/**
3421
 * xmlXPathNodeSetSort:
3422
 * @set:  the node set
3423
 *
3424
 * Sort the node set in document order
3425
 */
3426
void
3427
18.3k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428
#ifndef WITH_TIM_SORT
3429
    int i, j, incr, len;
3430
    xmlNodePtr tmp;
3431
#endif
3432
3433
18.3k
    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
18.3k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465
18.3k
#endif /* WITH_TIM_SORT */
3466
18.3k
}
3467
3468
246k
#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
179k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482
179k
    xmlNsPtr cur;
3483
3484
179k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485
0
  return(NULL);
3486
179k
    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
179k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493
179k
    if (cur == NULL) {
3494
1
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495
1
  return(NULL);
3496
1
    }
3497
179k
    memset(cur, 0, sizeof(xmlNs));
3498
179k
    cur->type = XML_NAMESPACE_DECL;
3499
179k
    if (ns->href != NULL)
3500
179k
  cur->href = xmlStrdup(ns->href);
3501
179k
    if (ns->prefix != NULL)
3502
158k
  cur->prefix = xmlStrdup(ns->prefix);
3503
179k
    cur->next = (xmlNsPtr) node;
3504
179k
    return((xmlNodePtr) cur);
3505
179k
}
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
179k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517
179k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518
0
  return;
3519
3520
179k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521
179k
  if (ns->href != NULL)
3522
179k
      xmlFree((xmlChar *)ns->href);
3523
179k
  if (ns->prefix != NULL)
3524
158k
      xmlFree((xmlChar *)ns->prefix);
3525
179k
  xmlFree(ns);
3526
179k
    }
3527
179k
}
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
120k
xmlXPathNodeSetCreate(xmlNodePtr val) {
3539
120k
    xmlNodeSetPtr ret;
3540
3541
120k
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542
120k
    if (ret == NULL) {
3543
127
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3544
127
  return(NULL);
3545
127
    }
3546
120k
    memset(ret, 0 , sizeof(xmlNodeSet));
3547
120k
    if (val != NULL) {
3548
4.19k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549
4.19k
               sizeof(xmlNodePtr));
3550
4.19k
  if (ret->nodeTab == NULL) {
3551
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3552
0
      xmlFree(ret);
3553
0
      return(NULL);
3554
0
  }
3555
4.19k
  memset(ret->nodeTab, 0 ,
3556
4.19k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557
4.19k
        ret->nodeMax = XML_NODESET_DEFAULT;
3558
4.19k
  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
4.19k
      ret->nodeTab[ret->nodeNr++] = val;
3569
4.19k
    }
3570
120k
    return(ret);
3571
120k
}
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
109k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622
109k
    int i;
3623
109k
    xmlNodePtr nsNode;
3624
3625
109k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626
109k
        (ns->type != XML_NAMESPACE_DECL) ||
3627
109k
  (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
377k
    for (i = 0;i < cur->nodeNr;i++) {
3635
267k
        if ((cur->nodeTab[i] != NULL) &&
3636
267k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637
267k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638
267k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639
0
      return(0);
3640
267k
    }
3641
3642
    /*
3643
     * grow the nodeTab if needed
3644
     */
3645
109k
    if (cur->nodeMax == 0) {
3646
431
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647
431
               sizeof(xmlNodePtr));
3648
431
  if (cur->nodeTab == NULL) {
3649
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3650
0
      return(-1);
3651
0
  }
3652
431
  memset(cur->nodeTab, 0 ,
3653
431
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654
431
        cur->nodeMax = XML_NODESET_DEFAULT;
3655
109k
    } else if (cur->nodeNr == cur->nodeMax) {
3656
139
        xmlNodePtr *temp;
3657
3658
139
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660
0
            return(-1);
3661
0
        }
3662
139
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663
139
              sizeof(xmlNodePtr));
3664
139
  if (temp == NULL) {
3665
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3666
0
      return(-1);
3667
0
  }
3668
139
        cur->nodeMax *= 2;
3669
139
  cur->nodeTab = temp;
3670
139
    }
3671
109k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3672
109k
    if(nsNode == NULL)
3673
1
        return(-1);
3674
109k
    cur->nodeTab[cur->nodeNr++] = nsNode;
3675
109k
    return(0);
3676
109k
}
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
104
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3689
104
    int i;
3690
3691
104
    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
104
    for (i = 0;i < cur->nodeNr;i++)
3698
0
        if (cur->nodeTab[i] == val) return(0);
3699
3700
    /*
3701
     * grow the nodeTab if needed
3702
     */
3703
104
    if (cur->nodeMax == 0) {
3704
104
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705
104
               sizeof(xmlNodePtr));
3706
104
  if (cur->nodeTab == NULL) {
3707
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3708
0
      return(-1);
3709
0
  }
3710
104
  memset(cur->nodeTab, 0 ,
3711
104
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712
104
        cur->nodeMax = XML_NODESET_DEFAULT;
3713
104
    } else if (cur->nodeNr == cur->nodeMax) {
3714
0
        xmlNodePtr *temp;
3715
3716
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3717
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3718
0
            return(-1);
3719
0
        }
3720
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3721
0
              sizeof(xmlNodePtr));
3722
0
  if (temp == NULL) {
3723
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3724
0
      return(-1);
3725
0
  }
3726
0
        cur->nodeMax *= 2;
3727
0
  cur->nodeTab = temp;
3728
0
    }
3729
104
    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
104
  cur->nodeTab[cur->nodeNr++] = val;
3738
104
    return(0);
3739
104
}
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
5.42M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753
5.42M
    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
5.42M
    if (cur->nodeMax == 0) {
3760
47.8k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761
47.8k
               sizeof(xmlNodePtr));
3762
47.8k
  if (cur->nodeTab == NULL) {
3763
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3764
0
      return(-1);
3765
0
  }
3766
47.8k
  memset(cur->nodeTab, 0 ,
3767
47.8k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768
47.8k
        cur->nodeMax = XML_NODESET_DEFAULT;
3769
5.37M
    } else if (cur->nodeNr == cur->nodeMax) {
3770
14.8k
        xmlNodePtr *temp;
3771
3772
14.8k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774
0
            return(-1);
3775
0
        }
3776
14.8k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777
14.8k
              sizeof(xmlNodePtr));
3778
14.8k
  if (temp == NULL) {
3779
1
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3780
1
      return(-1);
3781
1
  }
3782
14.8k
  cur->nodeTab = temp;
3783
14.8k
        cur->nodeMax *= 2;
3784
14.8k
    }
3785
5.42M
    if (val->type == XML_NAMESPACE_DECL) {
3786
17.3k
  xmlNsPtr ns = (xmlNsPtr) val;
3787
17.3k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788
3789
17.3k
        if (nsNode == NULL)
3790
0
            return(-1);
3791
17.3k
  cur->nodeTab[cur->nodeNr++] = nsNode;
3792
17.3k
    } else
3793
5.40M
  cur->nodeTab[cur->nodeNr++] = val;
3794
5.42M
    return(0);
3795
5.42M
}
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
32.7k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811
32.7k
    int i, j, initNr, skip;
3812
32.7k
    xmlNodePtr n1, n2;
3813
3814
32.7k
    if (val2 == NULL) return(val1);
3815
32.7k
    if (val1 == NULL) {
3816
244
  val1 = xmlXPathNodeSetCreate(NULL);
3817
244
        if (val1 == NULL)
3818
1
            return (NULL);
3819
244
    }
3820
3821
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822
32.6k
    initNr = val1->nodeNr;
3823
3824
300k
    for (i = 0;i < val2->nodeNr;i++) {
3825
268k
  n2 = val2->nodeTab[i];
3826
  /*
3827
   * check against duplicates
3828
   */
3829
268k
  skip = 0;
3830
258M
  for (j = 0; j < initNr; j++) {
3831
258M
      n1 = val1->nodeTab[j];
3832
258M
      if (n1 == n2) {
3833
175
    skip = 1;
3834
175
    break;
3835
258M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836
258M
           (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
258M
  }
3846
268k
  if (skip)
3847
175
      continue;
3848
3849
  /*
3850
   * grow the nodeTab if needed
3851
   */
3852
268k
  if (val1->nodeMax == 0) {
3853
24.5k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854
24.5k
                sizeof(xmlNodePtr));
3855
24.5k
      if (val1->nodeTab == NULL) {
3856
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3857
0
    goto error;
3858
0
      }
3859
24.5k
      memset(val1->nodeTab, 0 ,
3860
24.5k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861
24.5k
      val1->nodeMax = XML_NODESET_DEFAULT;
3862
243k
  } else if (val1->nodeNr == val1->nodeMax) {
3863
3.85k
      xmlNodePtr *temp;
3864
3865
3.85k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867
0
                goto error;
3868
0
            }
3869
3.85k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870
3.85k
               sizeof(xmlNodePtr));
3871
3.85k
      if (temp == NULL) {
3872
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3873
0
    goto error;
3874
0
      }
3875
3.85k
      val1->nodeTab = temp;
3876
3.85k
      val1->nodeMax *= 2;
3877
3.85k
  }
3878
268k
  if (n2->type == XML_NAMESPACE_DECL) {
3879
52.4k
      xmlNsPtr ns = (xmlNsPtr) n2;
3880
52.4k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881
3882
52.4k
            if (nsNode == NULL)
3883
0
                goto error;
3884
52.4k
      val1->nodeTab[val1->nodeNr++] = nsNode;
3885
52.4k
  } else
3886
215k
      val1->nodeTab[val1->nodeNr++] = n2;
3887
268k
    }
3888
3889
32.6k
    return(val1);
3890
3891
0
error:
3892
0
    xmlXPathFreeNodeSet(val1);
3893
0
    return(NULL);
3894
32.6k
}
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
19.7k
{
3912
19.7k
    {
3913
19.7k
  int i, j, initNbSet1;
3914
19.7k
  xmlNodePtr n1, n2;
3915
3916
19.7k
  initNbSet1 = set1->nodeNr;
3917
359k
  for (i = 0;i < set2->nodeNr;i++) {
3918
339k
      n2 = set2->nodeTab[i];
3919
      /*
3920
      * Skip duplicates.
3921
      */
3922
346M
      for (j = 0; j < initNbSet1; j++) {
3923
346M
    n1 = set1->nodeTab[j];
3924
346M
    if (n1 == n2) {
3925
319k
        goto skip_node;
3926
346M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3927
346M
        (n2->type == XML_NAMESPACE_DECL))
3928
143M
    {
3929
143M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930
143M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931
83.1k
      ((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
143M
    }
3940
346M
      }
3941
      /*
3942
      * grow the nodeTab if needed
3943
      */
3944
19.7k
      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
19.7k
      } else if (set1->nodeNr >= set1->nodeMax) {
3955
76
    xmlNodePtr *temp;
3956
3957
76
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959
0
                    goto error;
3960
0
                }
3961
76
    temp = (xmlNodePtr *) xmlRealloc(
3962
76
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963
76
    if (temp == NULL) {
3964
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3965
0
        goto error;
3966
0
    }
3967
76
    set1->nodeTab = temp;
3968
76
    set1->nodeMax *= 2;
3969
76
      }
3970
19.7k
      set1->nodeTab[set1->nodeNr++] = n2;
3971
339k
skip_node:
3972
339k
            set2->nodeTab[i] = NULL;
3973
339k
  }
3974
19.7k
    }
3975
19.7k
    set2->nodeNr = 0;
3976
19.7k
    return(set1);
3977
3978
0
error:
3979
0
    xmlXPathFreeNodeSet(set1);
3980
0
    xmlXPathNodeSetClear(set2, 1);
3981
0
    return(NULL);
3982
19.7k
}
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
22.4k
{
3999
22.4k
    {
4000
22.4k
  int i;
4001
22.4k
  xmlNodePtr n2;
4002
4003
199k
  for (i = 0;i < set2->nodeNr;i++) {
4004
177k
      n2 = set2->nodeTab[i];
4005
177k
      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
177k
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
2.35k
    xmlNodePtr *temp;
4017
4018
2.35k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    goto error;
4021
0
                }
4022
2.35k
    temp = (xmlNodePtr *) xmlRealloc(
4023
2.35k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
2.35k
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        goto error;
4027
0
    }
4028
2.35k
    set1->nodeTab = temp;
4029
2.35k
    set1->nodeMax *= 2;
4030
2.35k
      }
4031
177k
      set1->nodeTab[set1->nodeNr++] = n2;
4032
177k
            set2->nodeTab[i] = NULL;
4033
177k
  }
4034
22.4k
    }
4035
22.4k
    set2->nodeNr = 0;
4036
22.4k
    return(set1);
4037
4038
0
error:
4039
0
    xmlXPathFreeNodeSet(set1);
4040
0
    xmlXPathNodeSetClear(set2, 1);
4041
0
    return(NULL);
4042
22.4k
}
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
117k
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109
117k
    if (obj == NULL) return;
4110
117k
    if (obj->nodeTab != NULL) {
4111
74.3k
  int i;
4112
4113
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114
3.85M
  for (i = 0;i < obj->nodeNr;i++)
4115
3.78M
      if ((obj->nodeTab[i] != NULL) &&
4116
3.78M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117
160k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118
74.3k
  xmlFree(obj->nodeTab);
4119
74.3k
    }
4120
117k
    xmlFree(obj);
4121
117k
}
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
242
{
4135
242
    if ((set == NULL) || (pos >= set->nodeNr))
4136
0
  return;
4137
242
    else if ((hasNsNodes)) {
4138
242
  int i;
4139
242
  xmlNodePtr node;
4140
4141
81.2k
  for (i = pos; i < set->nodeNr; i++) {
4142
81.0k
      node = set->nodeTab[i];
4143
81.0k
      if ((node != NULL) &&
4144
81.0k
    (node->type == XML_NAMESPACE_DECL))
4145
17.3k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146
81.0k
  }
4147
242
    }
4148
242
    set->nodeNr = pos;
4149
242
}
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
560
{
4176
560
    int i;
4177
560
    xmlNodePtr node;
4178
4179
560
    if ((set == NULL) || (set->nodeNr <= 1))
4180
0
  return;
4181
126k
    for (i = 0; i < set->nodeNr - 1; i++) {
4182
125k
        node = set->nodeTab[i];
4183
125k
        if ((node != NULL) &&
4184
125k
            (node->type == XML_NAMESPACE_DECL))
4185
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
125k
    }
4187
560
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188
560
    set->nodeNr = 1;
4189
560
}
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
30.8k
xmlXPathNewNodeSet(xmlNodePtr val) {
4271
30.8k
    xmlXPathObjectPtr ret;
4272
4273
30.8k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274
30.8k
    if (ret == NULL) {
4275
1
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4276
1
  return(NULL);
4277
1
    }
4278
30.8k
    memset(ret, 0 , sizeof(xmlXPathObject));
4279
30.8k
    ret->type = XPATH_NODESET;
4280
30.8k
    ret->boolval = 0;
4281
    /* TODO: Check memory error. */
4282
30.8k
    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
30.8k
    return(ret);
4288
30.8k
}
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
2.77k
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364
2.77k
    xmlXPathObjectPtr ret;
4365
4366
2.77k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367
2.77k
    if (ret == NULL) {
4368
1
        xmlXPathErrMemory(NULL, "creating node set object\n");
4369
1
        xmlXPathFreeNodeSet(val);
4370
1
  return(NULL);
4371
1
    }
4372
2.77k
    memset(ret, 0 , sizeof(xmlXPathObject));
4373
2.77k
    ret->type = XPATH_NODESET;
4374
2.77k
    ret->nodesetval = val;
4375
#ifdef XP_DEBUG_OBJ_USAGE
4376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377
#endif
4378
2.77k
    return(ret);
4379
2.77k
}
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
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4410
0
    xmlNodeSetPtr ret;
4411
0
    int i, l1;
4412
0
    xmlNodePtr cur;
4413
4414
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4415
0
  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
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4484
0
    xmlNodeSetPtr ret;
4485
0
    xmlHashTablePtr hash;
4486
0
    int i, l;
4487
0
    xmlChar * strval;
4488
0
    xmlNodePtr cur;
4489
4490
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4491
0
  return(nodes);
4492
4493
0
    ret = xmlXPathNodeSetCreate(NULL);
4494
0
    if (ret == NULL)
4495
0
        return(ret);
4496
0
    l = xmlXPathNodeSetGetLength(nodes);
4497
0
    hash = xmlHashCreate (l);
4498
0
    for (i = 0; i < l; i++) {
4499
0
  cur = xmlXPathNodeSetItem(nodes, i);
4500
0
  strval = xmlXPathCastNodeToString(cur);
4501
0
  if (xmlHashLookup(hash, strval) == NULL) {
4502
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
4503
0
                xmlFree(strval);
4504
0
                goto error;
4505
0
            }
4506
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4507
0
          goto error;
4508
0
  } else {
4509
0
      xmlFree(strval);
4510
0
  }
4511
0
    }
4512
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4513
0
    return(ret);
4514
4515
0
error:
4516
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4517
0
    xmlXPathFreeNodeSet(ret);
4518
0
    return(NULL);
4519
0
}
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
5.55k
         xmlXPathFunction f) {
4803
5.55k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4804
5.55k
}
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
5.70k
           const xmlChar *ns_uri, xmlXPathFunction f) {
4820
5.70k
    if (ctxt == NULL)
4821
0
  return(-1);
4822
5.70k
    if (name == NULL)
4823
0
  return(-1);
4824
4825
5.70k
    if (ctxt->funcHash == NULL)
4826
0
  ctxt->funcHash = xmlHashCreate(0);
4827
5.70k
    if (ctxt->funcHash == NULL)
4828
0
  return(-1);
4829
5.70k
    if (f == NULL)
4830
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831
5.70k
XML_IGNORE_FPTR_CAST_WARNINGS
4832
5.70k
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833
5.70k
XML_POP_WARNINGS
4834
5.70k
}
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
152
          void *funcCtxt) {
4848
152
    if (ctxt == NULL)
4849
0
  return;
4850
152
    ctxt->funcLookupFunc = f;
4851
152
    ctxt->funcLookupData = funcCtxt;
4852
152
}
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
30
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4866
30
    if (ctxt == NULL)
4867
0
  return (NULL);
4868
4869
30
    if (ctxt->funcLookupFunc != NULL) {
4870
30
  xmlXPathFunction ret;
4871
30
  xmlXPathFuncLookupFunc f;
4872
4873
30
  f = ctxt->funcLookupFunc;
4874
30
  ret = f(ctxt->funcLookupData, name, NULL);
4875
30
  if (ret != NULL)
4876
0
      return(ret);
4877
30
    }
4878
30
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4879
30
}
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
6.60k
       const xmlChar *ns_uri) {
4895
6.60k
    xmlXPathFunction ret;
4896
4897
6.60k
    if (ctxt == NULL)
4898
0
  return(NULL);
4899
6.60k
    if (name == NULL)
4900
0
  return(NULL);
4901
4902
6.60k
    if (ctxt->funcLookupFunc != NULL) {
4903
6.60k
  xmlXPathFuncLookupFunc f;
4904
4905
6.60k
  f = ctxt->funcLookupFunc;
4906
6.60k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4907
6.60k
  if (ret != NULL)
4908
6.56k
      return(ret);
4909
6.60k
    }
4910
4911
36
    if (ctxt->funcHash == NULL)
4912
0
  return(NULL);
4913
4914
36
XML_IGNORE_FPTR_CAST_WARNINGS
4915
36
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4916
36
XML_POP_WARNINGS
4917
36
    return(ret);
4918
36
}
4919
4920
/**
4921
 * xmlXPathRegisteredFuncsCleanup:
4922
 * @ctxt:  the XPath context
4923
 *
4924
 * Cleanup the XPath context data associated to registered functions
4925
 */
4926
void
4927
153
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928
153
    if (ctxt == NULL)
4929
0
  return;
4930
4931
153
    xmlHashFree(ctxt->funcHash, NULL);
4932
153
    ctxt->funcHash = NULL;
4933
153
}
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
608
       xmlXPathObjectPtr value) {
4955
608
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956
608
}
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
608
         xmlXPathObjectPtr value) {
4974
608
    if (ctxt == NULL)
4975
0
  return(-1);
4976
608
    if (name == NULL)
4977
0
  return(-1);
4978
4979
608
    if (ctxt->varHash == NULL)
4980
152
  ctxt->varHash = xmlHashCreate(0);
4981
608
    if (ctxt->varHash == NULL)
4982
0
  return(-1);
4983
608
    if (value == NULL)
4984
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985
0
                             xmlXPathFreeObjectEntry));
4986
608
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987
608
             (void *) value, xmlXPathFreeObjectEntry));
4988
608
}
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
152
   xmlXPathVariableLookupFunc f, void *data) {
5001
152
    if (ctxt == NULL)
5002
0
  return;
5003
152
    ctxt->varLookupFunc = f;
5004
152
    ctxt->varLookupData = data;
5005
152
}
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
153
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074
153
    if (ctxt == NULL)
5075
0
  return;
5076
5077
153
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078
153
    ctxt->varHash = NULL;
5079
153
}
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
1.67k
         const xmlChar *ns_uri) {
5095
1.67k
    xmlChar *copy;
5096
5097
1.67k
    if (ctxt == NULL)
5098
0
  return(-1);
5099
1.67k
    if (prefix == NULL)
5100
0
  return(-1);
5101
1.67k
    if (prefix[0] == 0)
5102
0
  return(-1);
5103
5104
1.67k
    if (ctxt->nsHash == NULL)
5105
152
  ctxt->nsHash = xmlHashCreate(10);
5106
1.67k
    if (ctxt->nsHash == NULL)
5107
0
  return(-1);
5108
1.67k
    if (ns_uri == NULL)
5109
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110
0
                            xmlHashDefaultDeallocator));
5111
5112
1.67k
    copy = xmlStrdup(ns_uri);
5113
1.67k
    if (copy == NULL)
5114
0
        return(-1);
5115
1.67k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116
1.67k
                           xmlHashDefaultDeallocator) < 0) {
5117
0
        xmlFree(copy);
5118
0
        return(-1);
5119
0
    }
5120
5121
1.67k
    return(0);
5122
1.67k
}
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
6.59k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136
6.59k
    if (ctxt == NULL)
5137
0
  return(NULL);
5138
6.59k
    if (prefix == NULL)
5139
0
  return(NULL);
5140
5141
6.59k
#ifdef XML_XML_NAMESPACE
5142
6.59k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143
0
  return(XML_XML_NAMESPACE);
5144
6.59k
#endif
5145
5146
6.59k
    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
6.59k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157
6.59k
}
5158
5159
/**
5160
 * xmlXPathRegisteredNsCleanup:
5161
 * @ctxt:  the XPath context
5162
 *
5163
 * Cleanup the XPath context data associated to registered variables
5164
 */
5165
void
5166
313
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167
313
    if (ctxt == NULL)
5168
8
  return;
5169
5170
305
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171
305
    ctxt->nsHash = NULL;
5172
305
}
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
69.9k
xmlXPathNewFloat(double val) {
5192
69.9k
    xmlXPathObjectPtr ret;
5193
5194
69.9k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195
69.9k
    if (ret == NULL) {
5196
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5197
0
  return(NULL);
5198
0
    }
5199
69.9k
    memset(ret, 0 , sizeof(xmlXPathObject));
5200
69.9k
    ret->type = XPATH_NUMBER;
5201
69.9k
    ret->floatval = val;
5202
#ifdef XP_DEBUG_OBJ_USAGE
5203
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204
#endif
5205
69.9k
    return(ret);
5206
69.9k
}
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
5.36k
xmlXPathNewBoolean(int val) {
5218
5.36k
    xmlXPathObjectPtr ret;
5219
5220
5.36k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221
5.36k
    if (ret == NULL) {
5222
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5223
0
  return(NULL);
5224
0
    }
5225
5.36k
    memset(ret, 0 , sizeof(xmlXPathObject));
5226
5.36k
    ret->type = XPATH_BOOLEAN;
5227
5.36k
    ret->boolval = (val != 0);
5228
#ifdef XP_DEBUG_OBJ_USAGE
5229
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230
#endif
5231
5.36k
    return(ret);
5232
5.36k
}
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
64.3k
xmlXPathNewString(const xmlChar *val) {
5244
64.3k
    xmlXPathObjectPtr ret;
5245
5246
64.3k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
64.3k
    if (ret == NULL) {
5248
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5249
0
  return(NULL);
5250
0
    }
5251
64.3k
    memset(ret, 0 , sizeof(xmlXPathObject));
5252
64.3k
    ret->type = XPATH_STRING;
5253
64.3k
    if (val == NULL)
5254
0
        val = BAD_CAST "";
5255
64.3k
    ret->stringval = xmlStrdup(val);
5256
64.3k
    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
64.3k
    return(ret);
5264
64.3k
}
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
19.3k
xmlXPathWrapString (xmlChar *val) {
5278
19.3k
    xmlXPathObjectPtr ret;
5279
5280
19.3k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281
19.3k
    if (ret == NULL) {
5282
1
        xmlXPathErrMemory(NULL, "creating string object\n");
5283
1
        xmlFree(val);
5284
1
  return(NULL);
5285
1
    }
5286
19.3k
    memset(ret, 0 , sizeof(xmlXPathObject));
5287
19.3k
    ret->type = XPATH_STRING;
5288
19.3k
    ret->stringval = val;
5289
#ifdef XP_DEBUG_OBJ_USAGE
5290
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291
#endif
5292
19.3k
    return(ret);
5293
19.3k
}
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
38
xmlXPathNewCString(const char *val) {
5305
38
    return(xmlXPathNewString(BAD_CAST val));
5306
38
}
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
634
xmlXPathWrapExternal (void *val) {
5331
634
    xmlXPathObjectPtr ret;
5332
5333
634
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334
634
    if (ret == NULL) {
5335
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5336
0
  return(NULL);
5337
0
    }
5338
634
    memset(ret, 0 , sizeof(xmlXPathObject));
5339
634
    ret->type = XPATH_USERS;
5340
634
    ret->user = val;
5341
#ifdef XP_DEBUG_OBJ_USAGE
5342
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343
#endif
5344
634
    return(ret);
5345
634
}
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
236k
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453
236k
    if (obj == NULL) return;
5454
152k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455
9.63k
  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
9.63k
  } else {
5466
9.63k
      if (obj->nodesetval != NULL)
5467
9.61k
    xmlXPathFreeNodeSet(obj->nodesetval);
5468
9.63k
  }
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
143k
    } else if (obj->type == XPATH_STRING) {
5475
66.3k
  if (obj->stringval != NULL)
5476
66.3k
      xmlFree(obj->stringval);
5477
66.3k
    }
5478
#ifdef XP_DEBUG_OBJ_USAGE
5479
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480
#endif
5481
152k
    xmlFree(obj);
5482
152k
}
5483
5484
static void
5485
608
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486
608
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487
608
}
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
1.78M
{
5499
1.78M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500
356
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501
1.74M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502
5503
1.88M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504
5505
1.78M
    if (obj == NULL)
5506
0
  return;
5507
1.78M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508
1
   xmlXPathFreeObject(obj);
5509
1.78M
    } else {
5510
1.78M
  xmlXPathContextCachePtr cache =
5511
1.78M
      (xmlXPathContextCachePtr) ctxt->cache;
5512
5513
1.78M
  switch (obj->type) {
5514
341k
      case XPATH_NODESET:
5515
341k
      case XPATH_XSLT_TREE:
5516
341k
    if (obj->nodesetval != NULL) {
5517
312k
        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
312k
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5527
312k
      (XP_CACHE_WANTS(cache->nodesetObjs,
5528
310k
          cache->maxNodeset)))
5529
229k
        {
5530
229k
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5531
229k
      goto obj_cached;
5532
229k
        } else {
5533
83.6k
      xmlXPathFreeNodeSet(obj->nodesetval);
5534
83.6k
      obj->nodesetval = NULL;
5535
83.6k
        }
5536
312k
    }
5537
111k
    break;
5538
497k
      case XPATH_STRING:
5539
497k
    if (obj->stringval != NULL)
5540
497k
        xmlFree(obj->stringval);
5541
5542
497k
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543
479k
        XP_CACHE_ADD(cache->stringObjs, obj);
5544
479k
        goto obj_cached;
5545
479k
    }
5546
18.7k
    break;
5547
328k
      case XPATH_BOOLEAN:
5548
328k
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549
328k
        XP_CACHE_ADD(cache->booleanObjs, obj);
5550
328k
        goto obj_cached;
5551
328k
    }
5552
0
    break;
5553
614k
      case XPATH_NUMBER:
5554
614k
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555
609k
        XP_CACHE_ADD(cache->numberObjs, obj);
5556
609k
        goto obj_cached;
5557
609k
    }
5558
4.47k
    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
4.47k
      default:
5567
634
    goto free_obj;
5568
1.78M
  }
5569
5570
  /*
5571
  * Fallback to adding to the misc-objects slot.
5572
  */
5573
135k
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574
100k
      XP_CACHE_ADD(cache->miscObjs, obj);
5575
100k
  } else
5576
34.5k
      goto free_obj;
5577
5578
1.74M
obj_cached:
5579
5580
#ifdef XP_DEBUG_OBJ_USAGE
5581
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582
#endif
5583
5584
1.74M
  if (obj->nodesetval != NULL) {
5585
229k
      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
229k
      if (tmpset->nodeNr > 1) {
5594
287
    int i;
5595
287
    xmlNodePtr node;
5596
5597
2.32k
    for (i = 0; i < tmpset->nodeNr; i++) {
5598
2.04k
        node = tmpset->nodeTab[i];
5599
2.04k
        if ((node != NULL) &&
5600
2.04k
      (node->type == XML_NAMESPACE_DECL))
5601
801
        {
5602
801
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603
801
        }
5604
2.04k
    }
5605
228k
      } else if (tmpset->nodeNr == 1) {
5606
226k
    if ((tmpset->nodeTab[0] != NULL) &&
5607
226k
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609
226k
      }
5610
229k
      tmpset->nodeNr = 0;
5611
229k
      memset(obj, 0, sizeof(xmlXPathObject));
5612
229k
      obj->nodesetval = tmpset;
5613
229k
  } else
5614
1.51M
      memset(obj, 0, sizeof(xmlXPathObject));
5615
5616
1.74M
  return;
5617
5618
35.1k
free_obj:
5619
  /*
5620
  * Cache is full; free the object.
5621
  */
5622
35.1k
  if (obj->nodesetval != NULL)
5623
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5624
#ifdef XP_DEBUG_OBJ_USAGE
5625
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626
#endif
5627
35.1k
  xmlFree(obj);
5628
35.1k
    }
5629
35.1k
    return;
5630
1.78M
}
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
82.8k
xmlXPathCastBooleanToString (int val) {
5649
82.8k
    xmlChar *ret;
5650
82.8k
    if (val)
5651
91
  ret = xmlStrdup((const xmlChar *) "true");
5652
82.7k
    else
5653
82.7k
  ret = xmlStrdup((const xmlChar *) "false");
5654
82.8k
    return(ret);
5655
82.8k
}
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
89.4k
xmlXPathCastNumberToString (double val) {
5667
89.4k
    xmlChar *ret;
5668
89.4k
    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
89.4k
    default:
5676
89.4k
  if (xmlXPathIsNaN(val)) {
5677
89.1k
      ret = xmlStrdup((const xmlChar *) "NaN");
5678
89.1k
  } else if (val == 0) {
5679
            /* Omit sign for negative zero. */
5680
1
      ret = xmlStrdup((const xmlChar *) "0");
5681
217
  } else {
5682
      /* could be improved */
5683
217
      char buf[100];
5684
217
      xmlXPathFormatNumber(val, buf, 99);
5685
217
      buf[99] = 0;
5686
217
      ret = xmlStrdup((const xmlChar *) buf);
5687
217
  }
5688
89.4k
    }
5689
89.4k
    return(ret);
5690
89.4k
}
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
137k
xmlXPathCastNodeToString (xmlNodePtr node) {
5702
137k
xmlChar *ret;
5703
137k
    if ((ret = xmlNodeGetContent(node)) == NULL)
5704
0
  ret = xmlStrdup((const xmlChar *) "");
5705
137k
    return(ret);
5706
137k
}
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
54.4k
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718
54.4k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719
9.23k
  return(xmlStrdup((const xmlChar *) ""));
5720
5721
45.2k
    if (ns->nodeNr > 1)
5722
101
  xmlXPathNodeSetSort(ns);
5723
45.2k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724
54.4k
}
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
25.8k
xmlXPathCastToString(xmlXPathObjectPtr val) {
5737
25.8k
    xmlChar *ret = NULL;
5738
5739
25.8k
    if (val == NULL)
5740
0
  return(xmlStrdup((const xmlChar *) ""));
5741
25.8k
    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
24.2k
        case XPATH_NODESET:
5749
24.2k
        case XPATH_XSLT_TREE:
5750
24.2k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751
24.2k
      break;
5752
1.36k
  case XPATH_STRING:
5753
1.36k
      return(xmlStrdup(val->stringval));
5754
101
        case XPATH_BOOLEAN:
5755
101
      ret = xmlXPathCastBooleanToString(val->boolval);
5756
101
      break;
5757
204
  case XPATH_NUMBER: {
5758
204
      ret = xmlXPathCastNumberToString(val->floatval);
5759
204
      break;
5760
24.2k
  }
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
25.8k
    }
5771
24.5k
    return(ret);
5772
25.8k
}
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
0
xmlXPathCastBooleanToNumber(int val) {
5833
0
    if (val)
5834
0
  return(1.0);
5835
0
    return(0.0);
5836
0
}
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
222k
xmlXPathCastStringToNumber(const xmlChar * val) {
5848
222k
    return(xmlXPathStringEvalNumber(val));
5849
222k
}
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
9.85k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861
9.85k
    xmlChar *strval;
5862
9.85k
    double ret;
5863
5864
9.85k
    if (node == NULL)
5865
0
  return(xmlXPathNAN);
5866
9.85k
    strval = xmlXPathCastNodeToString(node);
5867
9.85k
    if (strval == NULL)
5868
0
  return(xmlXPathNAN);
5869
9.85k
    ret = xmlXPathCastStringToNumber(strval);
5870
9.85k
    xmlFree(strval);
5871
5872
9.85k
    return(ret);
5873
9.85k
}
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
32.5k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885
32.5k
    xmlChar *str;
5886
32.5k
    double ret;
5887
5888
32.5k
    if (ns == NULL)
5889
4.27k
  return(xmlXPathNAN);
5890
28.2k
    str = xmlXPathCastNodeSetToString(ns);
5891
28.2k
    ret = xmlXPathCastStringToNumber(str);
5892
28.2k
    xmlFree(str);
5893
28.2k
    return(ret);
5894
32.5k
}
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
223k
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906
223k
    double ret = 0.0;
5907
5908
223k
    if (val == NULL)
5909
0
  return(xmlXPathNAN);
5910
223k
    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
32.5k
    case XPATH_NODESET:
5918
32.5k
    case XPATH_XSLT_TREE:
5919
32.5k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920
32.5k
  break;
5921
184k
    case XPATH_STRING:
5922
184k
  ret = xmlXPathCastStringToNumber(val->stringval);
5923
184k
  break;
5924
6.71k
    case XPATH_NUMBER:
5925
6.71k
  ret = val->floatval;
5926
6.71k
  break;
5927
0
    case XPATH_BOOLEAN:
5928
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5929
0
  break;
5930
634
    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
634
  TODO;
5937
634
  ret = xmlXPathNAN;
5938
634
  break;
5939
223k
    }
5940
223k
    return(ret);
5941
223k
}
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
82.7k
xmlXPathCastNumberToBoolean (double val) {
5975
82.7k
     if (xmlXPathIsNaN(val) || (val == 0.0))
5976
10
   return(0);
5977
82.7k
     return(1);
5978
82.7k
}
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
82.7k
xmlXPathCastStringToBoolean (const xmlChar *val) {
5990
82.7k
    if ((val == NULL) || (xmlStrlen(val) == 0))
5991
82.7k
  return(0);
5992
0
    return(1);
5993
82.7k
}
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
3
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005
3
    if ((ns == NULL) || (ns->nodeNr == 0))
6006
3
  return(0);
6007
0
    return(1);
6008
3
}
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
165k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020
165k
    int ret = 0;
6021
6022
165k
    if (val == NULL)
6023
0
  return(0);
6024
165k
    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
3
    case XPATH_NODESET:
6032
3
    case XPATH_XSLT_TREE:
6033
3
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034
3
  break;
6035
82.7k
    case XPATH_STRING:
6036
82.7k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6037
82.7k
  break;
6038
82.7k
    case XPATH_NUMBER:
6039
82.7k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040
82.7k
  break;
6041
0
    case XPATH_BOOLEAN:
6042
0
  ret = val->boolval;
6043
0
  break;
6044
0
    case XPATH_USERS:
6045
#ifdef LIBXML_XPTR_LOCS_ENABLED
6046
    case XPATH_POINT:
6047
    case XPATH_RANGE:
6048
    case XPATH_LOCATIONSET:
6049
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6050
0
  TODO;
6051
0
  ret = 0;
6052
0
  break;
6053
165k
    }
6054
165k
    return(ret);
6055
165k
}
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
155
xmlXPathNewContext(xmlDocPtr doc) {
6096
155
    xmlXPathContextPtr ret;
6097
6098
155
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099
155
    if (ret == NULL) {
6100
0
        xmlXPathErrMemory(NULL, "creating context\n");
6101
0
  return(NULL);
6102
0
    }
6103
155
    memset(ret, 0 , sizeof(xmlXPathContext));
6104
155
    ret->doc = doc;
6105
155
    ret->node = NULL;
6106
6107
155
    ret->varHash = NULL;
6108
6109
155
    ret->nb_types = 0;
6110
155
    ret->max_types = 0;
6111
155
    ret->types = NULL;
6112
6113
155
    ret->funcHash = xmlHashCreate(0);
6114
6115
155
    ret->nb_axis = 0;
6116
155
    ret->max_axis = 0;
6117
155
    ret->axis = NULL;
6118
6119
155
    ret->nsHash = NULL;
6120
155
    ret->user = NULL;
6121
6122
155
    ret->contextSize = -1;
6123
155
    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
155
    xmlXPathRegisterAllFunctions(ret);
6133
6134
155
    return(ret);
6135
155
}
6136
6137
/**
6138
 * xmlXPathFreeContext:
6139
 * @ctxt:  the context to free
6140
 *
6141
 * Free up an xmlXPathContext
6142
 */
6143
void
6144
153
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145
153
    if (ctxt == NULL) return;
6146
6147
153
    if (ctxt->cache != NULL)
6148
152
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149
153
    xmlXPathRegisteredNsCleanup(ctxt);
6150
153
    xmlXPathRegisteredFuncsCleanup(ctxt);
6151
153
    xmlXPathRegisteredVariablesCleanup(ctxt);
6152
153
    xmlResetError(&ctxt->lastError);
6153
153
    xmlFree(ctxt);
6154
153
}
6155
6156
/************************************************************************
6157
 *                  *
6158
 *    Routines to handle XPath parser contexts    *
6159
 *                  *
6160
 ************************************************************************/
6161
6162
#define CHECK_CTXT(ctxt)            \
6163
152
    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
12.3k
    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
21.4k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204
21.4k
    xmlXPathParserContextPtr ret;
6205
6206
21.4k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207
21.4k
    if (ret == NULL) {
6208
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6209
0
  return(NULL);
6210
0
    }
6211
21.4k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6212
21.4k
    ret->cur = ret->base = str;
6213
21.4k
    ret->context = ctxt;
6214
6215
21.4k
    ret->comp = xmlXPathNewCompExpr();
6216
21.4k
    if (ret->comp == NULL) {
6217
0
  xmlFree(ret->valueTab);
6218
0
  xmlFree(ret);
6219
0
  return(NULL);
6220
0
    }
6221
21.4k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222
0
        ret->comp->dict = ctxt->dict;
6223
0
  xmlDictReference(ret->comp->dict);
6224
0
    }
6225
6226
21.4k
    return(ret);
6227
21.4k
}
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
12.3k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240
12.3k
    xmlXPathParserContextPtr ret;
6241
6242
12.3k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243
12.3k
    if (ret == NULL) {
6244
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245
0
  return(NULL);
6246
0
    }
6247
12.3k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6248
6249
    /* Allocate the value stack */
6250
12.3k
    ret->valueTab = (xmlXPathObjectPtr *)
6251
12.3k
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252
12.3k
    if (ret->valueTab == NULL) {
6253
0
  xmlFree(ret);
6254
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255
0
  return(NULL);
6256
0
    }
6257
12.3k
    ret->valueNr = 0;
6258
12.3k
    ret->valueMax = 10;
6259
12.3k
    ret->value = NULL;
6260
6261
12.3k
    ret->context = ctxt;
6262
12.3k
    ret->comp = comp;
6263
6264
12.3k
    return(ret);
6265
12.3k
}
6266
6267
/**
6268
 * xmlXPathFreeParserContext:
6269
 * @ctxt:  the context to free
6270
 *
6271
 * Free up an xmlXPathParserContext
6272
 */
6273
void
6274
33.8k
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275
33.8k
    int i;
6276
6277
33.8k
    if (ctxt->valueTab != NULL) {
6278
12.7k
        for (i = 0; i < ctxt->valueNr; i++) {
6279
259
            if (ctxt->context)
6280
259
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281
0
            else
6282
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6283
259
        }
6284
12.5k
        xmlFree(ctxt->valueTab);
6285
12.5k
    }
6286
33.8k
    if (ctxt->comp != NULL) {
6287
14.7k
#ifdef XPATH_STREAMING
6288
14.7k
  if (ctxt->comp->stream != NULL) {
6289
0
      xmlFreePatternList(ctxt->comp->stream);
6290
0
      ctxt->comp->stream = NULL;
6291
0
  }
6292
14.7k
#endif
6293
14.7k
  xmlXPathFreeCompExpr(ctxt->comp);
6294
14.7k
    }
6295
33.8k
    xmlFree(ctxt);
6296
33.8k
}
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
10.5k
xmlXPathNodeValHash(xmlNodePtr node) {
6315
10.5k
    int len = 2;
6316
10.5k
    const xmlChar * string = NULL;
6317
10.5k
    xmlNodePtr tmp = NULL;
6318
10.5k
    unsigned int ret = 0;
6319
6320
10.5k
    if (node == NULL)
6321
0
  return(0);
6322
6323
10.5k
    if (node->type == XML_DOCUMENT_NODE) {
6324
5.28k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325
5.28k
  if (tmp == NULL)
6326
0
      node = node->children;
6327
5.28k
  else
6328
5.28k
      node = tmp;
6329
6330
5.28k
  if (node == NULL)
6331
0
      return(0);
6332
5.28k
    }
6333
6334
10.5k
    switch (node->type) {
6335
0
  case XML_COMMENT_NODE:
6336
0
  case XML_PI_NODE:
6337
0
  case XML_CDATA_SECTION_NODE:
6338
2.63k
  case XML_TEXT_NODE:
6339
2.63k
      string = node->content;
6340
2.63k
      if (string == NULL)
6341
0
    return(0);
6342
2.63k
      if (string[0] == 0)
6343
0
    return(0);
6344
2.63k
      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
7.92k
  case XML_ELEMENT_NODE:
6356
7.92k
      tmp = node->children;
6357
7.92k
      break;
6358
0
  default:
6359
0
      return(0);
6360
10.5k
    }
6361
8.03k
    while (tmp != NULL) {
6362
6.64k
  switch (tmp->type) {
6363
0
      case XML_CDATA_SECTION_NODE:
6364
6.53k
      case XML_TEXT_NODE:
6365
6.53k
    string = tmp->content;
6366
6.53k
    break;
6367
115
      default:
6368
115
                string = NULL;
6369
115
    break;
6370
6.64k
  }
6371
6.64k
  if ((string != NULL) && (string[0] != 0)) {
6372
6.53k
      if (len == 1) {
6373
0
    return(ret + (string[0] << 8));
6374
0
      }
6375
6.53k
      if (string[1] == 0) {
6376
0
    len = 1;
6377
0
    ret = string[0];
6378
6.53k
      } else {
6379
6.53k
    return(string[0] + (string[1] << 8));
6380
6.53k
      }
6381
6.53k
  }
6382
  /*
6383
   * Skip to next node
6384
   */
6385
115
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6386
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6387
0
    tmp = tmp->children;
6388
0
    continue;
6389
0
      }
6390
0
  }
6391
115
  if (tmp == node)
6392
0
      break;
6393
6394
115
  if (tmp->next != NULL) {
6395
115
      tmp = tmp->next;
6396
115
      continue;
6397
115
  }
6398
6399
0
  do {
6400
0
      tmp = tmp->parent;
6401
0
      if (tmp == NULL)
6402
0
    break;
6403
0
      if (tmp == node) {
6404
0
    tmp = NULL;
6405
0
    break;
6406
0
      }
6407
0
      if (tmp->next != NULL) {
6408
0
    tmp = tmp->next;
6409
0
    break;
6410
0
      }
6411
0
  } while (tmp != NULL);
6412
0
    }
6413
1.38k
    return(ret);
6414
7.92k
}
6415
6416
/**
6417
 * xmlXPathStringHash:
6418
 * @string:  a string
6419
 *
6420
 * Function computing the beginning of the string value of the node,
6421
 * used to speed up comparisons
6422
 *
6423
 * Returns an int usable as a hash
6424
 */
6425
static unsigned int
6426
0
xmlXPathStringHash(const xmlChar * string) {
6427
0
    if (string == NULL)
6428
0
  return(0);
6429
0
    if (string[0] == 0)
6430
0
  return(0);
6431
0
    return(string[0] + (string[1] << 8));
6432
0
}
6433
6434
/**
6435
 * xmlXPathCompareNodeSetFloat:
6436
 * @ctxt:  the XPath Parser context
6437
 * @inf:  less than (1) or greater than (0)
6438
 * @strict:  is the comparison strict
6439
 * @arg:  the node set
6440
 * @f:  the value
6441
 *
6442
 * Implement the compare operation between a nodeset and a number
6443
 *     @ns < @val    (1, 1, ...
6444
 *     @ns <= @val   (1, 0, ...
6445
 *     @ns > @val    (0, 1, ...
6446
 *     @ns >= @val   (0, 0, ...
6447
 *
6448
 * If one object to be compared is a node-set and the other is a number,
6449
 * then the comparison will be true if and only if there is a node in the
6450
 * node-set such that the result of performing the comparison on the number
6451
 * to be compared and on the result of converting the string-value of that
6452
 * node to a number using the number function is true.
6453
 *
6454
 * Returns 0 or 1 depending on the results of the test.
6455
 */
6456
static int
6457
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6458
82.7k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6459
82.7k
    int i, ret = 0;
6460
82.7k
    xmlNodeSetPtr ns;
6461
82.7k
    xmlChar *str2;
6462
6463
82.7k
    if ((f == NULL) || (arg == NULL) ||
6464
82.7k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6465
0
  xmlXPathReleaseObject(ctxt->context, arg);
6466
0
  xmlXPathReleaseObject(ctxt->context, f);
6467
0
        return(0);
6468
0
    }
6469
82.7k
    ns = arg->nodesetval;
6470
82.7k
    if (ns != NULL) {
6471
165k
  for (i = 0;i < ns->nodeNr;i++) {
6472
82.7k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6473
82.7k
       if (str2 != NULL) {
6474
82.7k
     valuePush(ctxt,
6475
82.7k
         xmlXPathCacheNewString(ctxt->context, str2));
6476
82.7k
     xmlFree(str2);
6477
82.7k
     xmlXPathNumberFunction(ctxt, 1);
6478
82.7k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6479
82.7k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6480
82.7k
     if (ret)
6481
4
         break;
6482
82.7k
       }
6483
82.7k
  }
6484
82.7k
    }
6485
82.7k
    xmlXPathReleaseObject(ctxt->context, arg);
6486
82.7k
    xmlXPathReleaseObject(ctxt->context, f);
6487
82.7k
    return(ret);
6488
82.7k
}
6489
6490
/**
6491
 * xmlXPathCompareNodeSetString:
6492
 * @ctxt:  the XPath Parser context
6493
 * @inf:  less than (1) or greater than (0)
6494
 * @strict:  is the comparison strict
6495
 * @arg:  the node set
6496
 * @s:  the value
6497
 *
6498
 * Implement the compare operation between a nodeset and a string
6499
 *     @ns < @val    (1, 1, ...
6500
 *     @ns <= @val   (1, 0, ...
6501
 *     @ns > @val    (0, 1, ...
6502
 *     @ns >= @val   (0, 0, ...
6503
 *
6504
 * If one object to be compared is a node-set and the other is a string,
6505
 * then the comparison will be true if and only if there is a node in
6506
 * the node-set such that the result of performing the comparison on the
6507
 * string-value of the node and the other string is true.
6508
 *
6509
 * Returns 0 or 1 depending on the results of the test.
6510
 */
6511
static int
6512
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6513
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6514
0
    int i, ret = 0;
6515
0
    xmlNodeSetPtr ns;
6516
0
    xmlChar *str2;
6517
6518
0
    if ((s == NULL) || (arg == NULL) ||
6519
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6520
0
  xmlXPathReleaseObject(ctxt->context, arg);
6521
0
  xmlXPathReleaseObject(ctxt->context, s);
6522
0
        return(0);
6523
0
    }
6524
0
    ns = arg->nodesetval;
6525
0
    if (ns != NULL) {
6526
0
  for (i = 0;i < ns->nodeNr;i++) {
6527
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6528
0
       if (str2 != NULL) {
6529
0
     valuePush(ctxt,
6530
0
         xmlXPathCacheNewString(ctxt->context, str2));
6531
0
     xmlFree(str2);
6532
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6533
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6534
0
     if (ret)
6535
0
         break;
6536
0
       }
6537
0
  }
6538
0
    }
6539
0
    xmlXPathReleaseObject(ctxt->context, arg);
6540
0
    xmlXPathReleaseObject(ctxt->context, s);
6541
0
    return(ret);
6542
0
}
6543
6544
/**
6545
 * xmlXPathCompareNodeSets:
6546
 * @inf:  less than (1) or greater than (0)
6547
 * @strict:  is the comparison strict
6548
 * @arg1:  the first node set object
6549
 * @arg2:  the second node set object
6550
 *
6551
 * Implement the compare operation on nodesets:
6552
 *
6553
 * If both objects to be compared are node-sets, then the comparison
6554
 * will be true if and only if there is a node in the first node-set
6555
 * and a node in the second node-set such that the result of performing
6556
 * the comparison on the string-values of the two nodes is true.
6557
 * ....
6558
 * When neither object to be compared is a node-set and the operator
6559
 * is <=, <, >= or >, then the objects are compared by converting both
6560
 * objects to numbers and comparing the numbers according to IEEE 754.
6561
 * ....
6562
 * The number function converts its argument to a number as follows:
6563
 *  - a string that consists of optional whitespace followed by an
6564
 *    optional minus sign followed by a Number followed by whitespace
6565
 *    is converted to the IEEE 754 number that is nearest (according
6566
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6567
 *    represented by the string; any other string is converted to NaN
6568
 *
6569
 * Conclusion all nodes need to be converted first to their string value
6570
 * and then the comparison must be done when possible
6571
 */
6572
static int
6573
xmlXPathCompareNodeSets(int inf, int strict,
6574
17
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6575
17
    int i, j, init = 0;
6576
17
    double val1;
6577
17
    double *values2;
6578
17
    int ret = 0;
6579
17
    xmlNodeSetPtr ns1;
6580
17
    xmlNodeSetPtr ns2;
6581
6582
17
    if ((arg1 == NULL) ||
6583
17
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6584
0
  xmlXPathFreeObject(arg2);
6585
0
        return(0);
6586
0
    }
6587
17
    if ((arg2 == NULL) ||
6588
17
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6589
0
  xmlXPathFreeObject(arg1);
6590
0
  xmlXPathFreeObject(arg2);
6591
0
        return(0);
6592
0
    }
6593
6594
17
    ns1 = arg1->nodesetval;
6595
17
    ns2 = arg2->nodesetval;
6596
6597
17
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6598
1
  xmlXPathFreeObject(arg1);
6599
1
  xmlXPathFreeObject(arg2);
6600
1
  return(0);
6601
1
    }
6602
16
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6603
16
  xmlXPathFreeObject(arg1);
6604
16
  xmlXPathFreeObject(arg2);
6605
16
  return(0);
6606
16
    }
6607
6608
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6609
0
    if (values2 == NULL) {
6610
        /* TODO: Propagate memory error. */
6611
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6612
0
  xmlXPathFreeObject(arg1);
6613
0
  xmlXPathFreeObject(arg2);
6614
0
  return(0);
6615
0
    }
6616
0
    for (i = 0;i < ns1->nodeNr;i++) {
6617
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6618
0
  if (xmlXPathIsNaN(val1))
6619
0
      continue;
6620
0
  for (j = 0;j < ns2->nodeNr;j++) {
6621
0
      if (init == 0) {
6622
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6623
0
      }
6624
0
      if (xmlXPathIsNaN(values2[j]))
6625
0
    continue;
6626
0
      if (inf && strict)
6627
0
    ret = (val1 < values2[j]);
6628
0
      else if (inf && !strict)
6629
0
    ret = (val1 <= values2[j]);
6630
0
      else if (!inf && strict)
6631
0
    ret = (val1 > values2[j]);
6632
0
      else if (!inf && !strict)
6633
0
    ret = (val1 >= values2[j]);
6634
0
      if (ret)
6635
0
    break;
6636
0
  }
6637
0
  if (ret)
6638
0
      break;
6639
0
  init = 1;
6640
0
    }
6641
0
    xmlFree(values2);
6642
0
    xmlXPathFreeObject(arg1);
6643
0
    xmlXPathFreeObject(arg2);
6644
0
    return(ret);
6645
0
}
6646
6647
/**
6648
 * xmlXPathCompareNodeSetValue:
6649
 * @ctxt:  the XPath Parser context
6650
 * @inf:  less than (1) or greater than (0)
6651
 * @strict:  is the comparison strict
6652
 * @arg:  the node set
6653
 * @val:  the value
6654
 *
6655
 * Implement the compare operation between a nodeset and a value
6656
 *     @ns < @val    (1, 1, ...
6657
 *     @ns <= @val   (1, 0, ...
6658
 *     @ns > @val    (0, 1, ...
6659
 *     @ns >= @val   (0, 0, ...
6660
 *
6661
 * If one object to be compared is a node-set and the other is a boolean,
6662
 * then the comparison will be true if and only if the result of performing
6663
 * the comparison on the boolean and on the result of converting
6664
 * the node-set to a boolean using the boolean function is true.
6665
 *
6666
 * Returns 0 or 1 depending on the results of the test.
6667
 */
6668
static int
6669
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6670
82.7k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6671
82.7k
    if ((val == NULL) || (arg == NULL) ||
6672
82.7k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6673
0
        return(0);
6674
6675
82.7k
    switch(val->type) {
6676
82.7k
        case XPATH_NUMBER:
6677
82.7k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6678
0
        case XPATH_NODESET:
6679
0
        case XPATH_XSLT_TREE:
6680
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6681
0
        case XPATH_STRING:
6682
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6683
0
        case XPATH_BOOLEAN:
6684
0
      valuePush(ctxt, arg);
6685
0
      xmlXPathBooleanFunction(ctxt, 1);
6686
0
      valuePush(ctxt, val);
6687
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
6688
0
  default:
6689
0
            xmlGenericError(xmlGenericErrorContext,
6690
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6691
0
                    "and object of type %d\n",
6692
0
                    val->type);
6693
0
            xmlXPathReleaseObject(ctxt->context, arg);
6694
0
            xmlXPathReleaseObject(ctxt->context, val);
6695
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6696
82.7k
    }
6697
0
    return(0);
6698
82.7k
}
6699
6700
/**
6701
 * xmlXPathEqualNodeSetString:
6702
 * @arg:  the nodeset object argument
6703
 * @str:  the string to compare to.
6704
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6705
 *
6706
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6707
 * If one object to be compared is a node-set and the other is a string,
6708
 * then the comparison will be true if and only if there is a node in
6709
 * the node-set such that the result of performing the comparison on the
6710
 * string-value of the node and the other string is true.
6711
 *
6712
 * Returns 0 or 1 depending on the results of the test.
6713
 */
6714
static int
6715
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6716
12
{
6717
12
    int i;
6718
12
    xmlNodeSetPtr ns;
6719
12
    xmlChar *str2;
6720
12
    unsigned int hash;
6721
6722
12
    if ((str == NULL) || (arg == NULL) ||
6723
12
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6724
0
        return (0);
6725
12
    ns = arg->nodesetval;
6726
    /*
6727
     * A NULL nodeset compared with a string is always false
6728
     * (since there is no node equal, and no node not equal)
6729
     */
6730
12
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6731
12
        return (0);
6732
0
    hash = xmlXPathStringHash(str);
6733
0
    for (i = 0; i < ns->nodeNr; i++) {
6734
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6735
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6736
0
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6737
0
                xmlFree(str2);
6738
0
    if (neq)
6739
0
        continue;
6740
0
                return (1);
6741
0
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6742
0
    if (neq)
6743
0
        continue;
6744
0
                return (1);
6745
0
            } else if (neq) {
6746
0
    if (str2 != NULL)
6747
0
        xmlFree(str2);
6748
0
    return (1);
6749
0
      }
6750
0
            if (str2 != NULL)
6751
0
                xmlFree(str2);
6752
0
        } else if (neq)
6753
0
      return (1);
6754
0
    }
6755
0
    return (0);
6756
0
}
6757
6758
/**
6759
 * xmlXPathEqualNodeSetFloat:
6760
 * @arg:  the nodeset object argument
6761
 * @f:  the float to compare to
6762
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6763
 *
6764
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6765
 * If one object to be compared is a node-set and the other is a number,
6766
 * then the comparison will be true if and only if there is a node in
6767
 * the node-set such that the result of performing the comparison on the
6768
 * number to be compared and on the result of converting the string-value
6769
 * of that node to a number using the number function is true.
6770
 *
6771
 * Returns 0 or 1 depending on the results of the test.
6772
 */
6773
static int
6774
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6775
6
    xmlXPathObjectPtr arg, double f, int neq) {
6776
6
  int i, ret=0;
6777
6
  xmlNodeSetPtr ns;
6778
6
  xmlChar *str2;
6779
6
  xmlXPathObjectPtr val;
6780
6
  double v;
6781
6782
6
    if ((arg == NULL) ||
6783
6
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6784
0
        return(0);
6785
6786
6
    ns = arg->nodesetval;
6787
6
    if (ns != NULL) {
6788
12
  for (i=0;i<ns->nodeNr;i++) {
6789
6
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6790
6
      if (str2 != NULL) {
6791
6
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6792
6
    xmlFree(str2);
6793
6
    xmlXPathNumberFunction(ctxt, 1);
6794
6
                CHECK_ERROR0;
6795
6
    val = valuePop(ctxt);
6796
6
    v = val->floatval;
6797
6
    xmlXPathReleaseObject(ctxt->context, val);
6798
6
    if (!xmlXPathIsNaN(v)) {
6799
0
        if ((!neq) && (v==f)) {
6800
0
      ret = 1;
6801
0
      break;
6802
0
        } else if ((neq) && (v!=f)) {
6803
0
      ret = 1;
6804
0
      break;
6805
0
        }
6806
6
    } else { /* NaN is unequal to any value */
6807
6
        if (neq)
6808
0
      ret = 1;
6809
6
    }
6810
6
      }
6811
6
  }
6812
6
    }
6813
6814
6
    return(ret);
6815
6
}
6816
6817
6818
/**
6819
 * xmlXPathEqualNodeSets:
6820
 * @arg1:  first nodeset object argument
6821
 * @arg2:  second nodeset object argument
6822
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6823
 *
6824
 * Implement the equal / not equal operation on XPath nodesets:
6825
 * @arg1 == @arg2  or  @arg1 != @arg2
6826
 * If both objects to be compared are node-sets, then the comparison
6827
 * will be true if and only if there is a node in the first node-set and
6828
 * a node in the second node-set such that the result of performing the
6829
 * comparison on the string-values of the two nodes is true.
6830
 *
6831
 * (needless to say, this is a costly operation)
6832
 *
6833
 * Returns 0 or 1 depending on the results of the test.
6834
 */
6835
static int
6836
5.27k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6837
5.27k
    int i, j;
6838
5.27k
    unsigned int *hashs1;
6839
5.27k
    unsigned int *hashs2;
6840
5.27k
    xmlChar **values1;
6841
5.27k
    xmlChar **values2;
6842
5.27k
    int ret = 0;
6843
5.27k
    xmlNodeSetPtr ns1;
6844
5.27k
    xmlNodeSetPtr ns2;
6845
6846
5.27k
    if ((arg1 == NULL) ||
6847
5.27k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6848
0
        return(0);
6849
5.27k
    if ((arg2 == NULL) ||
6850
5.27k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6851
0
        return(0);
6852
6853
5.27k
    ns1 = arg1->nodesetval;
6854
5.27k
    ns2 = arg2->nodesetval;
6855
6856
5.27k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6857
0
  return(0);
6858
5.27k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6859
0
  return(0);
6860
6861
    /*
6862
     * for equal, check if there is a node pertaining to both sets
6863
     */
6864
5.27k
    if (neq == 0)
6865
0
  for (i = 0;i < ns1->nodeNr;i++)
6866
0
      for (j = 0;j < ns2->nodeNr;j++)
6867
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6868
0
        return(1);
6869
6870
5.27k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6871
5.27k
    if (values1 == NULL) {
6872
        /* TODO: Propagate memory error. */
6873
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6874
0
  return(0);
6875
0
    }
6876
5.27k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6877
5.27k
    if (hashs1 == NULL) {
6878
        /* TODO: Propagate memory error. */
6879
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6880
0
  xmlFree(values1);
6881
0
  return(0);
6882
0
    }
6883
5.27k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6884
5.27k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6885
5.27k
    if (values2 == NULL) {
6886
        /* TODO: Propagate memory error. */
6887
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6888
0
  xmlFree(hashs1);
6889
0
  xmlFree(values1);
6890
0
  return(0);
6891
0
    }
6892
5.27k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6893
5.27k
    if (hashs2 == NULL) {
6894
        /* TODO: Propagate memory error. */
6895
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
0
  xmlFree(hashs1);
6897
0
  xmlFree(values1);
6898
0
  xmlFree(values2);
6899
0
  return(0);
6900
0
    }
6901
5.27k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902
5.30k
    for (i = 0;i < ns1->nodeNr;i++) {
6903
5.27k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904
5.30k
  for (j = 0;j < ns2->nodeNr;j++) {
6905
5.27k
      if (i == 0)
6906
5.27k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907
5.27k
      if (hashs1[i] != hashs2[j]) {
6908
4.70k
    if (neq) {
6909
4.70k
        ret = 1;
6910
4.70k
        break;
6911
4.70k
    }
6912
4.70k
      }
6913
570
      else {
6914
570
    if (values1[i] == NULL)
6915
570
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916
570
    if (values2[j] == NULL)
6917
570
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918
570
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919
570
    if (ret)
6920
546
        break;
6921
570
      }
6922
5.27k
  }
6923
5.27k
  if (ret)
6924
5.25k
      break;
6925
5.27k
    }
6926
10.5k
    for (i = 0;i < ns1->nodeNr;i++)
6927
5.27k
  if (values1[i] != NULL)
6928
570
      xmlFree(values1[i]);
6929
10.5k
    for (j = 0;j < ns2->nodeNr;j++)
6930
5.27k
  if (values2[j] != NULL)
6931
570
      xmlFree(values2[j]);
6932
5.27k
    xmlFree(values1);
6933
5.27k
    xmlFree(values2);
6934
5.27k
    xmlFree(hashs1);
6935
5.27k
    xmlFree(hashs2);
6936
5.27k
    return(ret);
6937
5.27k
}
6938
6939
static int
6940
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941
79.8k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942
79.8k
    int ret = 0;
6943
    /*
6944
     *At this point we are assured neither arg1 nor arg2
6945
     *is a nodeset, so we can just pick the appropriate routine.
6946
     */
6947
79.8k
    switch (arg1->type) {
6948
0
        case XPATH_UNDEFINED:
6949
#ifdef DEBUG_EXPR
6950
      xmlGenericError(xmlGenericErrorContext,
6951
        "Equal: undefined\n");
6952
#endif
6953
0
      break;
6954
0
        case XPATH_BOOLEAN:
6955
0
      switch (arg2->type) {
6956
0
          case XPATH_UNDEFINED:
6957
#ifdef DEBUG_EXPR
6958
        xmlGenericError(xmlGenericErrorContext,
6959
          "Equal: undefined\n");
6960
#endif
6961
0
        break;
6962
0
    case XPATH_BOOLEAN:
6963
#ifdef DEBUG_EXPR
6964
        xmlGenericError(xmlGenericErrorContext,
6965
          "Equal: %d boolean %d \n",
6966
          arg1->boolval, arg2->boolval);
6967
#endif
6968
0
        ret = (arg1->boolval == arg2->boolval);
6969
0
        break;
6970
0
    case XPATH_NUMBER:
6971
0
        ret = (arg1->boolval ==
6972
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
6973
0
        break;
6974
0
    case XPATH_STRING:
6975
0
        if ((arg2->stringval == NULL) ||
6976
0
      (arg2->stringval[0] == 0)) ret = 0;
6977
0
        else
6978
0
      ret = 1;
6979
0
        ret = (arg1->boolval == ret);
6980
0
        break;
6981
0
    case XPATH_USERS:
6982
#ifdef LIBXML_XPTR_LOCS_ENABLED
6983
    case XPATH_POINT:
6984
    case XPATH_RANGE:
6985
    case XPATH_LOCATIONSET:
6986
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6987
0
        TODO
6988
0
        break;
6989
0
    case XPATH_NODESET:
6990
0
    case XPATH_XSLT_TREE:
6991
0
        break;
6992
0
      }
6993
0
      break;
6994
79.8k
        case XPATH_NUMBER:
6995
79.8k
      switch (arg2->type) {
6996
0
          case XPATH_UNDEFINED:
6997
#ifdef DEBUG_EXPR
6998
        xmlGenericError(xmlGenericErrorContext,
6999
          "Equal: undefined\n");
7000
#endif
7001
0
        break;
7002
0
    case XPATH_BOOLEAN:
7003
0
        ret = (arg2->boolval==
7004
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
7005
0
        break;
7006
0
    case XPATH_STRING:
7007
0
        valuePush(ctxt, arg2);
7008
0
        xmlXPathNumberFunction(ctxt, 1);
7009
0
        arg2 = valuePop(ctxt);
7010
0
                    if (ctxt->error)
7011
0
                        break;
7012
                    /* Falls through. */
7013
79.8k
    case XPATH_NUMBER:
7014
        /* Hand check NaN and Infinity equalities */
7015
79.8k
        if (xmlXPathIsNaN(arg1->floatval) ||
7016
79.8k
          xmlXPathIsNaN(arg2->floatval)) {
7017
0
            ret = 0;
7018
79.8k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7019
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
7020
0
          ret = 1;
7021
0
      else
7022
0
          ret = 0;
7023
79.8k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7024
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7025
0
          ret = 1;
7026
0
      else
7027
0
          ret = 0;
7028
79.8k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7029
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7030
0
          ret = 1;
7031
0
      else
7032
0
          ret = 0;
7033
79.8k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7034
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7035
0
          ret = 1;
7036
0
      else
7037
0
          ret = 0;
7038
79.8k
        } else {
7039
79.8k
            ret = (arg1->floatval == arg2->floatval);
7040
79.8k
        }
7041
79.8k
        break;
7042
0
    case XPATH_USERS:
7043
#ifdef LIBXML_XPTR_LOCS_ENABLED
7044
    case XPATH_POINT:
7045
    case XPATH_RANGE:
7046
    case XPATH_LOCATIONSET:
7047
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7048
0
        TODO
7049
0
        break;
7050
0
    case XPATH_NODESET:
7051
0
    case XPATH_XSLT_TREE:
7052
0
        break;
7053
79.8k
      }
7054
79.8k
      break;
7055
79.8k
        case XPATH_STRING:
7056
0
      switch (arg2->type) {
7057
0
          case XPATH_UNDEFINED:
7058
#ifdef DEBUG_EXPR
7059
        xmlGenericError(xmlGenericErrorContext,
7060
          "Equal: undefined\n");
7061
#endif
7062
0
        break;
7063
0
    case XPATH_BOOLEAN:
7064
0
        if ((arg1->stringval == NULL) ||
7065
0
      (arg1->stringval[0] == 0)) ret = 0;
7066
0
        else
7067
0
      ret = 1;
7068
0
        ret = (arg2->boolval == ret);
7069
0
        break;
7070
0
    case XPATH_STRING:
7071
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072
0
        break;
7073
0
    case XPATH_NUMBER:
7074
0
        valuePush(ctxt, arg1);
7075
0
        xmlXPathNumberFunction(ctxt, 1);
7076
0
        arg1 = valuePop(ctxt);
7077
0
                    if (ctxt->error)
7078
0
                        break;
7079
        /* Hand check NaN and Infinity equalities */
7080
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7081
0
          xmlXPathIsNaN(arg2->floatval)) {
7082
0
            ret = 0;
7083
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7084
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7085
0
          ret = 1;
7086
0
      else
7087
0
          ret = 0;
7088
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7089
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7090
0
          ret = 1;
7091
0
      else
7092
0
          ret = 0;
7093
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7094
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7095
0
          ret = 1;
7096
0
      else
7097
0
          ret = 0;
7098
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7099
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7100
0
          ret = 1;
7101
0
      else
7102
0
          ret = 0;
7103
0
        } else {
7104
0
            ret = (arg1->floatval == arg2->floatval);
7105
0
        }
7106
0
        break;
7107
0
    case XPATH_USERS:
7108
#ifdef LIBXML_XPTR_LOCS_ENABLED
7109
    case XPATH_POINT:
7110
    case XPATH_RANGE:
7111
    case XPATH_LOCATIONSET:
7112
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7113
0
        TODO
7114
0
        break;
7115
0
    case XPATH_NODESET:
7116
0
    case XPATH_XSLT_TREE:
7117
0
        break;
7118
0
      }
7119
0
      break;
7120
0
        case XPATH_USERS:
7121
#ifdef LIBXML_XPTR_LOCS_ENABLED
7122
  case XPATH_POINT:
7123
  case XPATH_RANGE:
7124
  case XPATH_LOCATIONSET:
7125
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7126
0
      TODO
7127
0
      break;
7128
0
  case XPATH_NODESET:
7129
0
  case XPATH_XSLT_TREE:
7130
0
      break;
7131
79.8k
    }
7132
79.8k
    xmlXPathReleaseObject(ctxt->context, arg1);
7133
79.8k
    xmlXPathReleaseObject(ctxt->context, arg2);
7134
79.8k
    return(ret);
7135
79.8k
}
7136
7137
/**
7138
 * xmlXPathEqualValues:
7139
 * @ctxt:  the XPath Parser context
7140
 *
7141
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7142
 *
7143
 * Returns 0 or 1 depending on the results of the test.
7144
 */
7145
int
7146
79.8k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7147
79.8k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7148
79.8k
    int ret = 0;
7149
7150
79.8k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7151
79.8k
    arg2 = valuePop(ctxt);
7152
79.8k
    arg1 = valuePop(ctxt);
7153
79.8k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7154
0
  if (arg1 != NULL)
7155
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7156
0
  else
7157
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7158
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7159
0
    }
7160
7161
79.8k
    if (arg1 == arg2) {
7162
#ifdef DEBUG_EXPR
7163
        xmlGenericError(xmlGenericErrorContext,
7164
    "Equal: by pointer\n");
7165
#endif
7166
0
  xmlXPathFreeObject(arg1);
7167
0
        return(1);
7168
0
    }
7169
7170
    /*
7171
     *If either argument is a nodeset, it's a 'special case'
7172
     */
7173
79.8k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7174
79.8k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7175
  /*
7176
   *Hack it to assure arg1 is the nodeset
7177
   */
7178
18
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7179
9
    argtmp = arg2;
7180
9
    arg2 = arg1;
7181
9
    arg1 = argtmp;
7182
9
  }
7183
18
  switch (arg2->type) {
7184
0
      case XPATH_UNDEFINED:
7185
#ifdef DEBUG_EXPR
7186
    xmlGenericError(xmlGenericErrorContext,
7187
      "Equal: undefined\n");
7188
#endif
7189
0
    break;
7190
0
      case XPATH_NODESET:
7191
0
      case XPATH_XSLT_TREE:
7192
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7193
0
    break;
7194
0
      case XPATH_BOOLEAN:
7195
0
    if ((arg1->nodesetval == NULL) ||
7196
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7197
0
    else
7198
0
        ret = 1;
7199
0
    ret = (ret == arg2->boolval);
7200
0
    break;
7201
6
      case XPATH_NUMBER:
7202
6
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7203
6
    break;
7204
12
      case XPATH_STRING:
7205
12
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7206
12
    break;
7207
0
      case XPATH_USERS:
7208
#ifdef LIBXML_XPTR_LOCS_ENABLED
7209
      case XPATH_POINT:
7210
      case XPATH_RANGE:
7211
      case XPATH_LOCATIONSET:
7212
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7213
0
    TODO
7214
0
    break;
7215
18
  }
7216
18
  xmlXPathReleaseObject(ctxt->context, arg1);
7217
18
  xmlXPathReleaseObject(ctxt->context, arg2);
7218
18
  return(ret);
7219
18
    }
7220
7221
79.8k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7222
79.8k
}
7223
7224
/**
7225
 * xmlXPathNotEqualValues:
7226
 * @ctxt:  the XPath Parser context
7227
 *
7228
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7229
 *
7230
 * Returns 0 or 1 depending on the results of the test.
7231
 */
7232
int
7233
5.27k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7234
5.27k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7235
5.27k
    int ret = 0;
7236
7237
5.27k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7238
5.27k
    arg2 = valuePop(ctxt);
7239
5.27k
    arg1 = valuePop(ctxt);
7240
5.27k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7241
0
  if (arg1 != NULL)
7242
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7243
0
  else
7244
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7245
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7246
0
    }
7247
7248
5.27k
    if (arg1 == arg2) {
7249
#ifdef DEBUG_EXPR
7250
        xmlGenericError(xmlGenericErrorContext,
7251
    "NotEqual: by pointer\n");
7252
#endif
7253
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7254
0
        return(0);
7255
0
    }
7256
7257
    /*
7258
     *If either argument is a nodeset, it's a 'special case'
7259
     */
7260
5.27k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7261
5.27k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7262
  /*
7263
   *Hack it to assure arg1 is the nodeset
7264
   */
7265
5.27k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7266
0
    argtmp = arg2;
7267
0
    arg2 = arg1;
7268
0
    arg1 = argtmp;
7269
0
  }
7270
5.27k
  switch (arg2->type) {
7271
0
      case XPATH_UNDEFINED:
7272
#ifdef DEBUG_EXPR
7273
    xmlGenericError(xmlGenericErrorContext,
7274
      "NotEqual: undefined\n");
7275
#endif
7276
0
    break;
7277
5.27k
      case XPATH_NODESET:
7278
5.27k
      case XPATH_XSLT_TREE:
7279
5.27k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7280
5.27k
    break;
7281
0
      case XPATH_BOOLEAN:
7282
0
    if ((arg1->nodesetval == NULL) ||
7283
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7284
0
    else
7285
0
        ret = 1;
7286
0
    ret = (ret != arg2->boolval);
7287
0
    break;
7288
0
      case XPATH_NUMBER:
7289
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7290
0
    break;
7291
0
      case XPATH_STRING:
7292
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7293
0
    break;
7294
0
      case XPATH_USERS:
7295
#ifdef LIBXML_XPTR_LOCS_ENABLED
7296
      case XPATH_POINT:
7297
      case XPATH_RANGE:
7298
      case XPATH_LOCATIONSET:
7299
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7300
0
    TODO
7301
0
    break;
7302
5.27k
  }
7303
5.27k
  xmlXPathReleaseObject(ctxt->context, arg1);
7304
5.27k
  xmlXPathReleaseObject(ctxt->context, arg2);
7305
5.27k
  return(ret);
7306
5.27k
    }
7307
7308
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7309
5.27k
}
7310
7311
/**
7312
 * xmlXPathCompareValues:
7313
 * @ctxt:  the XPath Parser context
7314
 * @inf:  less than (1) or greater than (0)
7315
 * @strict:  is the comparison strict
7316
 *
7317
 * Implement the compare operation on XPath objects:
7318
 *     @arg1 < @arg2    (1, 1, ...
7319
 *     @arg1 <= @arg2   (1, 0, ...
7320
 *     @arg1 > @arg2    (0, 1, ...
7321
 *     @arg1 >= @arg2   (0, 0, ...
7322
 *
7323
 * When neither object to be compared is a node-set and the operator is
7324
 * <=, <, >=, >, then the objects are compared by converted both objects
7325
 * to numbers and comparing the numbers according to IEEE 754. The <
7326
 * comparison will be true if and only if the first number is less than the
7327
 * second number. The <= comparison will be true if and only if the first
7328
 * number is less than or equal to the second number. The > comparison
7329
 * will be true if and only if the first number is greater than the second
7330
 * number. The >= comparison will be true if and only if the first number
7331
 * is greater than or equal to the second number.
7332
 *
7333
 * Returns 1 if the comparison succeeded, 0 if it failed
7334
 */
7335
int
7336
165k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7337
165k
    int ret = 0, arg1i = 0, arg2i = 0;
7338
165k
    xmlXPathObjectPtr arg1, arg2;
7339
7340
165k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7341
165k
    arg2 = valuePop(ctxt);
7342
165k
    arg1 = valuePop(ctxt);
7343
165k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7344
0
  if (arg1 != NULL)
7345
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7346
0
  else
7347
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7348
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7349
0
    }
7350
7351
165k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7352
165k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7353
  /*
7354
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7355
   * are not freed from within this routine; they will be freed from the
7356
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7357
   */
7358
82.7k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7359
82.7k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7360
17
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7361
82.7k
  } else {
7362
82.7k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7363
82.7k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7364
82.7k
                                arg1, arg2);
7365
82.7k
      } else {
7366
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7367
0
                                arg2, arg1);
7368
0
      }
7369
82.7k
  }
7370
82.7k
  return(ret);
7371
82.7k
    }
7372
7373
82.7k
    if (arg1->type != XPATH_NUMBER) {
7374
0
  valuePush(ctxt, arg1);
7375
0
  xmlXPathNumberFunction(ctxt, 1);
7376
0
  arg1 = valuePop(ctxt);
7377
0
    }
7378
82.7k
    if (arg2->type != XPATH_NUMBER) {
7379
0
  valuePush(ctxt, arg2);
7380
0
  xmlXPathNumberFunction(ctxt, 1);
7381
0
  arg2 = valuePop(ctxt);
7382
0
    }
7383
82.7k
    if (ctxt->error)
7384
0
        goto error;
7385
    /*
7386
     * Add tests for infinity and nan
7387
     * => feedback on 3.4 for Inf and NaN
7388
     */
7389
    /* Hand check NaN and Infinity comparisons */
7390
82.7k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7391
82.7k
  ret=0;
7392
82.7k
    } else {
7393
4
  arg1i=xmlXPathIsInf(arg1->floatval);
7394
4
  arg2i=xmlXPathIsInf(arg2->floatval);
7395
4
  if (inf && strict) {
7396
4
      if ((arg1i == -1 && arg2i != -1) ||
7397
4
    (arg2i == 1 && arg1i != 1)) {
7398
0
    ret = 1;
7399
4
      } else if (arg1i == 0 && arg2i == 0) {
7400
4
    ret = (arg1->floatval < arg2->floatval);
7401
4
      } else {
7402
0
    ret = 0;
7403
0
      }
7404
4
  }
7405
0
  else if (inf && !strict) {
7406
0
      if (arg1i == -1 || arg2i == 1) {
7407
0
    ret = 1;
7408
0
      } else if (arg1i == 0 && arg2i == 0) {
7409
0
    ret = (arg1->floatval <= arg2->floatval);
7410
0
      } else {
7411
0
    ret = 0;
7412
0
      }
7413
0
  }
7414
0
  else if (!inf && strict) {
7415
0
      if ((arg1i == 1 && arg2i != 1) ||
7416
0
    (arg2i == -1 && arg1i != -1)) {
7417
0
    ret = 1;
7418
0
      } else if (arg1i == 0 && arg2i == 0) {
7419
0
    ret = (arg1->floatval > arg2->floatval);
7420
0
      } else {
7421
0
    ret = 0;
7422
0
      }
7423
0
  }
7424
0
  else if (!inf && !strict) {
7425
0
      if (arg1i == 1 || arg2i == -1) {
7426
0
    ret = 1;
7427
0
      } else if (arg1i == 0 && arg2i == 0) {
7428
0
    ret = (arg1->floatval >= arg2->floatval);
7429
0
      } else {
7430
0
    ret = 0;
7431
0
      }
7432
0
  }
7433
4
    }
7434
82.7k
error:
7435
82.7k
    xmlXPathReleaseObject(ctxt->context, arg1);
7436
82.7k
    xmlXPathReleaseObject(ctxt->context, arg2);
7437
82.7k
    return(ret);
7438
82.7k
}
7439
7440
/**
7441
 * xmlXPathValueFlipSign:
7442
 * @ctxt:  the XPath Parser context
7443
 *
7444
 * Implement the unary - operation on an XPath object
7445
 * The numeric operators convert their operands to numbers as if
7446
 * by calling the number function.
7447
 */
7448
void
7449
172k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7450
172k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7451
172k
    CAST_TO_NUMBER;
7452
172k
    CHECK_TYPE(XPATH_NUMBER);
7453
172k
    ctxt->value->floatval = -ctxt->value->floatval;
7454
172k
}
7455
7456
/**
7457
 * xmlXPathAddValues:
7458
 * @ctxt:  the XPath Parser context
7459
 *
7460
 * Implement the add operation on XPath objects:
7461
 * The numeric operators convert their operands to numbers as if
7462
 * by calling the number function.
7463
 */
7464
void
7465
46
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7466
46
    xmlXPathObjectPtr arg;
7467
46
    double val;
7468
7469
46
    arg = valuePop(ctxt);
7470
46
    if (arg == NULL)
7471
46
  XP_ERROR(XPATH_INVALID_OPERAND);
7472
46
    val = xmlXPathCastToNumber(arg);
7473
46
    xmlXPathReleaseObject(ctxt->context, arg);
7474
46
    CAST_TO_NUMBER;
7475
46
    CHECK_TYPE(XPATH_NUMBER);
7476
46
    ctxt->value->floatval += val;
7477
46
}
7478
7479
/**
7480
 * xmlXPathSubValues:
7481
 * @ctxt:  the XPath Parser context
7482
 *
7483
 * Implement the subtraction operation on XPath objects:
7484
 * The numeric operators convert their operands to numbers as if
7485
 * by calling the number function.
7486
 */
7487
void
7488
206
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7489
206
    xmlXPathObjectPtr arg;
7490
206
    double val;
7491
7492
206
    arg = valuePop(ctxt);
7493
206
    if (arg == NULL)
7494
206
  XP_ERROR(XPATH_INVALID_OPERAND);
7495
206
    val = xmlXPathCastToNumber(arg);
7496
206
    xmlXPathReleaseObject(ctxt->context, arg);
7497
206
    CAST_TO_NUMBER;
7498
206
    CHECK_TYPE(XPATH_NUMBER);
7499
206
    ctxt->value->floatval -= val;
7500
206
}
7501
7502
/**
7503
 * xmlXPathMultValues:
7504
 * @ctxt:  the XPath Parser context
7505
 *
7506
 * Implement the multiply operation on XPath objects:
7507
 * The numeric operators convert their operands to numbers as if
7508
 * by calling the number function.
7509
 */
7510
void
7511
25.9k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7512
25.9k
    xmlXPathObjectPtr arg;
7513
25.9k
    double val;
7514
7515
25.9k
    arg = valuePop(ctxt);
7516
25.9k
    if (arg == NULL)
7517
25.9k
  XP_ERROR(XPATH_INVALID_OPERAND);
7518
25.9k
    val = xmlXPathCastToNumber(arg);
7519
25.9k
    xmlXPathReleaseObject(ctxt->context, arg);
7520
25.9k
    CAST_TO_NUMBER;
7521
25.9k
    CHECK_TYPE(XPATH_NUMBER);
7522
25.9k
    ctxt->value->floatval *= val;
7523
25.9k
}
7524
7525
/**
7526
 * xmlXPathDivValues:
7527
 * @ctxt:  the XPath Parser context
7528
 *
7529
 * Implement the div operation on XPath objects @arg1 / @arg2:
7530
 * The numeric operators convert their operands to numbers as if
7531
 * by calling the number function.
7532
 */
7533
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7534
void
7535
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7536
0
    xmlXPathObjectPtr arg;
7537
0
    double val;
7538
7539
0
    arg = valuePop(ctxt);
7540
0
    if (arg == NULL)
7541
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7542
0
    val = xmlXPathCastToNumber(arg);
7543
0
    xmlXPathReleaseObject(ctxt->context, arg);
7544
0
    CAST_TO_NUMBER;
7545
0
    CHECK_TYPE(XPATH_NUMBER);
7546
0
    ctxt->value->floatval /= val;
7547
0
}
7548
7549
/**
7550
 * xmlXPathModValues:
7551
 * @ctxt:  the XPath Parser context
7552
 *
7553
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7554
 * The numeric operators convert their operands to numbers as if
7555
 * by calling the number function.
7556
 */
7557
void
7558
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7559
0
    xmlXPathObjectPtr arg;
7560
0
    double arg1, arg2;
7561
7562
0
    arg = valuePop(ctxt);
7563
0
    if (arg == NULL)
7564
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7565
0
    arg2 = xmlXPathCastToNumber(arg);
7566
0
    xmlXPathReleaseObject(ctxt->context, arg);
7567
0
    CAST_TO_NUMBER;
7568
0
    CHECK_TYPE(XPATH_NUMBER);
7569
0
    arg1 = ctxt->value->floatval;
7570
0
    if (arg2 == 0)
7571
0
  ctxt->value->floatval = xmlXPathNAN;
7572
0
    else {
7573
0
  ctxt->value->floatval = fmod(arg1, arg2);
7574
0
    }
7575
0
}
7576
7577
/************************************************************************
7578
 *                  *
7579
 *    The traversal functions         *
7580
 *                  *
7581
 ************************************************************************/
7582
7583
/*
7584
 * A traversal function enumerates nodes along an axis.
7585
 * Initially it must be called with NULL, and it indicates
7586
 * termination on the axis by returning NULL.
7587
 */
7588
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7589
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7590
7591
/*
7592
 * xmlXPathTraversalFunctionExt:
7593
 * A traversal function enumerates nodes along an axis.
7594
 * Initially it must be called with NULL, and it indicates
7595
 * termination on the axis by returning NULL.
7596
 * The context node of the traversal is specified via @contextNode.
7597
 */
7598
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7599
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7600
7601
/*
7602
 * xmlXPathNodeSetMergeFunction:
7603
 * Used for merging node sets in xmlXPathCollectAndTest().
7604
 */
7605
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7606
        (xmlNodeSetPtr, xmlNodeSetPtr);
7607
7608
7609
/**
7610
 * xmlXPathNextSelf:
7611
 * @ctxt:  the XPath Parser context
7612
 * @cur:  the current node in the traversal
7613
 *
7614
 * Traversal function for the "self" direction
7615
 * The self axis contains just the context node itself
7616
 *
7617
 * Returns the next element following that axis
7618
 */
7619
xmlNodePtr
7620
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7621
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7622
0
    if (cur == NULL)
7623
0
        return(ctxt->context->node);
7624
0
    return(NULL);
7625
0
}
7626
7627
/**
7628
 * xmlXPathNextChild:
7629
 * @ctxt:  the XPath Parser context
7630
 * @cur:  the current node in the traversal
7631
 *
7632
 * Traversal function for the "child" direction
7633
 * The child axis contains the children of the context node in document order.
7634
 *
7635
 * Returns the next element following that axis
7636
 */
7637
xmlNodePtr
7638
194k
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7639
194k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7640
194k
    if (cur == NULL) {
7641
97.0k
  if (ctxt->context->node == NULL) return(NULL);
7642
97.0k
  switch (ctxt->context->node->type) {
7643
61.7k
            case XML_ELEMENT_NODE:
7644
96.8k
            case XML_TEXT_NODE:
7645
96.8k
            case XML_CDATA_SECTION_NODE:
7646
96.8k
            case XML_ENTITY_REF_NODE:
7647
96.8k
            case XML_ENTITY_NODE:
7648
96.8k
            case XML_PI_NODE:
7649
96.8k
            case XML_COMMENT_NODE:
7650
96.8k
            case XML_NOTATION_NODE:
7651
96.8k
            case XML_DTD_NODE:
7652
96.8k
    return(ctxt->context->node->children);
7653
247
            case XML_DOCUMENT_NODE:
7654
247
            case XML_DOCUMENT_TYPE_NODE:
7655
247
            case XML_DOCUMENT_FRAG_NODE:
7656
247
            case XML_HTML_DOCUMENT_NODE:
7657
247
    return(((xmlDocPtr) ctxt->context->node)->children);
7658
0
      case XML_ELEMENT_DECL:
7659
0
      case XML_ATTRIBUTE_DECL:
7660
0
      case XML_ENTITY_DECL:
7661
0
            case XML_ATTRIBUTE_NODE:
7662
0
      case XML_NAMESPACE_DECL:
7663
0
      case XML_XINCLUDE_START:
7664
0
      case XML_XINCLUDE_END:
7665
0
    return(NULL);
7666
97.0k
  }
7667
0
  return(NULL);
7668
97.0k
    }
7669
97.5k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7670
97.5k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7671
0
  return(NULL);
7672
97.5k
    return(cur->next);
7673
97.5k
}
7674
7675
/**
7676
 * xmlXPathNextChildElement:
7677
 * @ctxt:  the XPath Parser context
7678
 * @cur:  the current node in the traversal
7679
 *
7680
 * Traversal function for the "child" direction and nodes of type element.
7681
 * The child axis contains the children of the context node in document order.
7682
 *
7683
 * Returns the next element following that axis
7684
 */
7685
static xmlNodePtr
7686
2.27M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687
2.27M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688
2.27M
    if (cur == NULL) {
7689
191k
  cur = ctxt->context->node;
7690
191k
  if (cur == NULL) return(NULL);
7691
  /*
7692
  * Get the first element child.
7693
  */
7694
191k
  switch (cur->type) {
7695
94.5k
            case XML_ELEMENT_NODE:
7696
94.5k
      case XML_DOCUMENT_FRAG_NODE:
7697
94.5k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698
94.5k
            case XML_ENTITY_NODE:
7699
94.5k
    cur = cur->children;
7700
94.5k
    if (cur != NULL) {
7701
13.4k
        if (cur->type == XML_ELEMENT_NODE)
7702
624
      return(cur);
7703
13.3k
        do {
7704
13.3k
      cur = cur->next;
7705
13.3k
        } while ((cur != NULL) &&
7706
13.3k
      (cur->type != XML_ELEMENT_NODE));
7707
12.8k
        return(cur);
7708
13.4k
    }
7709
81.0k
    return(NULL);
7710
58.8k
            case XML_DOCUMENT_NODE:
7711
58.8k
            case XML_HTML_DOCUMENT_NODE:
7712
58.8k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7713
38.4k
      default:
7714
38.4k
    return(NULL);
7715
191k
  }
7716
0
  return(NULL);
7717
191k
    }
7718
    /*
7719
    * Get the next sibling element node.
7720
    */
7721
2.08M
    switch (cur->type) {
7722
2.08M
  case XML_ELEMENT_NODE:
7723
2.08M
  case XML_TEXT_NODE:
7724
2.08M
  case XML_ENTITY_REF_NODE:
7725
2.08M
  case XML_ENTITY_NODE:
7726
2.08M
  case XML_CDATA_SECTION_NODE:
7727
2.08M
  case XML_PI_NODE:
7728
2.08M
  case XML_COMMENT_NODE:
7729
2.08M
  case XML_XINCLUDE_END:
7730
2.08M
      break;
7731
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7732
0
  default:
7733
0
      return(NULL);
7734
2.08M
    }
7735
2.08M
    if (cur->next != NULL) {
7736
2.01M
  if (cur->next->type == XML_ELEMENT_NODE)
7737
1.97M
      return(cur->next);
7738
42.9k
  cur = cur->next;
7739
43.2k
  do {
7740
43.2k
      cur = cur->next;
7741
43.2k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7742
42.9k
  return(cur);
7743
2.01M
    }
7744
69.2k
    return(NULL);
7745
2.08M
}
7746
7747
#if 0
7748
/**
7749
 * xmlXPathNextDescendantOrSelfElemParent:
7750
 * @ctxt:  the XPath Parser context
7751
 * @cur:  the current node in the traversal
7752
 *
7753
 * Traversal function for the "descendant-or-self" axis.
7754
 * Additionally it returns only nodes which can be parents of
7755
 * element nodes.
7756
 *
7757
 *
7758
 * Returns the next element following that axis
7759
 */
7760
static xmlNodePtr
7761
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7762
               xmlNodePtr contextNode)
7763
{
7764
    if (cur == NULL) {
7765
  if (contextNode == NULL)
7766
      return(NULL);
7767
  switch (contextNode->type) {
7768
      case XML_ELEMENT_NODE:
7769
      case XML_XINCLUDE_START:
7770
      case XML_DOCUMENT_FRAG_NODE:
7771
      case XML_DOCUMENT_NODE:
7772
      case XML_HTML_DOCUMENT_NODE:
7773
    return(contextNode);
7774
      default:
7775
    return(NULL);
7776
  }
7777
  return(NULL);
7778
    } else {
7779
  xmlNodePtr start = cur;
7780
7781
  while (cur != NULL) {
7782
      switch (cur->type) {
7783
    case XML_ELEMENT_NODE:
7784
    /* TODO: OK to have XInclude here? */
7785
    case XML_XINCLUDE_START:
7786
    case XML_DOCUMENT_FRAG_NODE:
7787
        if (cur != start)
7788
      return(cur);
7789
        if (cur->children != NULL) {
7790
      cur = cur->children;
7791
      continue;
7792
        }
7793
        break;
7794
    /* Not sure if we need those here. */
7795
    case XML_DOCUMENT_NODE:
7796
    case XML_HTML_DOCUMENT_NODE:
7797
        if (cur != start)
7798
      return(cur);
7799
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7800
    default:
7801
        break;
7802
      }
7803
7804
next_sibling:
7805
      if ((cur == NULL) || (cur == contextNode))
7806
    return(NULL);
7807
      if (cur->next != NULL) {
7808
    cur = cur->next;
7809
      } else {
7810
    cur = cur->parent;
7811
    goto next_sibling;
7812
      }
7813
  }
7814
    }
7815
    return(NULL);
7816
}
7817
#endif
7818
7819
/**
7820
 * xmlXPathNextDescendant:
7821
 * @ctxt:  the XPath Parser context
7822
 * @cur:  the current node in the traversal
7823
 *
7824
 * Traversal function for the "descendant" direction
7825
 * the descendant axis contains the descendants of the context node in document
7826
 * order; a descendant is a child or a child of a child and so on.
7827
 *
7828
 * Returns the next element following that axis
7829
 */
7830
xmlNodePtr
7831
2.45M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7832
2.45M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7833
2.45M
    if (cur == NULL) {
7834
13.3k
  if (ctxt->context->node == NULL)
7835
0
      return(NULL);
7836
13.3k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7837
13.3k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7838
0
      return(NULL);
7839
7840
13.3k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7841
4.43k
      return(ctxt->context->doc->children);
7842
8.96k
        return(ctxt->context->node->children);
7843
13.3k
    }
7844
7845
2.44M
    if (cur->type == XML_NAMESPACE_DECL)
7846
0
        return(NULL);
7847
2.44M
    if (cur->children != NULL) {
7848
  /*
7849
   * Do not descend on entities declarations
7850
   */
7851
184k
  if (cur->children->type != XML_ENTITY_DECL) {
7852
184k
      cur = cur->children;
7853
      /*
7854
       * Skip DTDs
7855
       */
7856
184k
      if (cur->type != XML_DTD_NODE)
7857
184k
    return(cur);
7858
184k
  }
7859
184k
    }
7860
7861
2.25M
    if (cur == ctxt->context->node) return(NULL);
7862
7863
2.25M
    while (cur->next != NULL) {
7864
2.23M
  cur = cur->next;
7865
2.23M
  if ((cur->type != XML_ENTITY_DECL) &&
7866
2.23M
      (cur->type != XML_DTD_NODE))
7867
2.23M
      return(cur);
7868
2.23M
    }
7869
7870
190k
    do {
7871
190k
        cur = cur->parent;
7872
190k
  if (cur == NULL) break;
7873
190k
  if (cur == ctxt->context->node) return(NULL);
7874
177k
  if (cur->next != NULL) {
7875
6.17k
      cur = cur->next;
7876
6.17k
      return(cur);
7877
6.17k
  }
7878
177k
    } while (cur != NULL);
7879
0
    return(cur);
7880
19.6k
}
7881
7882
/**
7883
 * xmlXPathNextDescendantOrSelf:
7884
 * @ctxt:  the XPath Parser context
7885
 * @cur:  the current node in the traversal
7886
 *
7887
 * Traversal function for the "descendant-or-self" direction
7888
 * the descendant-or-self axis contains the context node and the descendants
7889
 * of the context node in document order; thus the context node is the first
7890
 * node on the axis, and the first child of the context node is the second node
7891
 * on the axis
7892
 *
7893
 * Returns the next element following that axis
7894
 */
7895
xmlNodePtr
7896
437k
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7897
437k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7898
437k
    if (cur == NULL)
7899
81.4k
        return(ctxt->context->node);
7900
7901
356k
    if (ctxt->context->node == NULL)
7902
0
        return(NULL);
7903
356k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7904
356k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7905
17.5k
        return(NULL);
7906
7907
339k
    return(xmlXPathNextDescendant(ctxt, cur));
7908
356k
}
7909
7910
/**
7911
 * xmlXPathNextParent:
7912
 * @ctxt:  the XPath Parser context
7913
 * @cur:  the current node in the traversal
7914
 *
7915
 * Traversal function for the "parent" direction
7916
 * The parent axis contains the parent of the context node, if there is one.
7917
 *
7918
 * Returns the next element following that axis
7919
 */
7920
xmlNodePtr
7921
382
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922
382
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923
    /*
7924
     * the parent of an attribute or namespace node is the element
7925
     * to which the attribute or namespace node is attached
7926
     * Namespace handling !!!
7927
     */
7928
382
    if (cur == NULL) {
7929
191
  if (ctxt->context->node == NULL) return(NULL);
7930
191
  switch (ctxt->context->node->type) {
7931
6
            case XML_ELEMENT_NODE:
7932
12
            case XML_TEXT_NODE:
7933
12
            case XML_CDATA_SECTION_NODE:
7934
12
            case XML_ENTITY_REF_NODE:
7935
12
            case XML_ENTITY_NODE:
7936
12
            case XML_PI_NODE:
7937
12
            case XML_COMMENT_NODE:
7938
12
            case XML_NOTATION_NODE:
7939
12
            case XML_DTD_NODE:
7940
12
      case XML_ELEMENT_DECL:
7941
12
      case XML_ATTRIBUTE_DECL:
7942
12
      case XML_XINCLUDE_START:
7943
12
      case XML_XINCLUDE_END:
7944
12
      case XML_ENTITY_DECL:
7945
12
    if (ctxt->context->node->parent == NULL)
7946
0
        return((xmlNodePtr) ctxt->context->doc);
7947
12
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7948
12
        ((ctxt->context->node->parent->name[0] == ' ') ||
7949
6
         (xmlStrEqual(ctxt->context->node->parent->name,
7950
6
         BAD_CAST "fake node libxslt"))))
7951
0
        return(NULL);
7952
12
    return(ctxt->context->node->parent);
7953
179
            case XML_ATTRIBUTE_NODE: {
7954
179
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7955
7956
179
    return(att->parent);
7957
12
      }
7958
0
            case XML_DOCUMENT_NODE:
7959
0
            case XML_DOCUMENT_TYPE_NODE:
7960
0
            case XML_DOCUMENT_FRAG_NODE:
7961
0
            case XML_HTML_DOCUMENT_NODE:
7962
0
                return(NULL);
7963
0
      case XML_NAMESPACE_DECL: {
7964
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7965
7966
0
    if ((ns->next != NULL) &&
7967
0
        (ns->next->type != XML_NAMESPACE_DECL))
7968
0
        return((xmlNodePtr) ns->next);
7969
0
                return(NULL);
7970
0
      }
7971
191
  }
7972
191
    }
7973
191
    return(NULL);
7974
382
}
7975
7976
/**
7977
 * xmlXPathNextAncestor:
7978
 * @ctxt:  the XPath Parser context
7979
 * @cur:  the current node in the traversal
7980
 *
7981
 * Traversal function for the "ancestor" direction
7982
 * the ancestor axis contains the ancestors of the context node; the ancestors
7983
 * of the context node consist of the parent of context node and the parent's
7984
 * parent and so on; the nodes are ordered in reverse document order; thus the
7985
 * parent is the first node on the axis, and the parent's parent is the second
7986
 * node on the axis
7987
 *
7988
 * Returns the next element following that axis
7989
 */
7990
xmlNodePtr
7991
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7993
    /*
7994
     * the parent of an attribute or namespace node is the element
7995
     * to which the attribute or namespace node is attached
7996
     * !!!!!!!!!!!!!
7997
     */
7998
0
    if (cur == NULL) {
7999
0
  if (ctxt->context->node == NULL) return(NULL);
8000
0
  switch (ctxt->context->node->type) {
8001
0
            case XML_ELEMENT_NODE:
8002
0
            case XML_TEXT_NODE:
8003
0
            case XML_CDATA_SECTION_NODE:
8004
0
            case XML_ENTITY_REF_NODE:
8005
0
            case XML_ENTITY_NODE:
8006
0
            case XML_PI_NODE:
8007
0
            case XML_COMMENT_NODE:
8008
0
      case XML_DTD_NODE:
8009
0
      case XML_ELEMENT_DECL:
8010
0
      case XML_ATTRIBUTE_DECL:
8011
0
      case XML_ENTITY_DECL:
8012
0
            case XML_NOTATION_NODE:
8013
0
      case XML_XINCLUDE_START:
8014
0
      case XML_XINCLUDE_END:
8015
0
    if (ctxt->context->node->parent == NULL)
8016
0
        return((xmlNodePtr) ctxt->context->doc);
8017
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8019
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8020
0
         BAD_CAST "fake node libxslt"))))
8021
0
        return(NULL);
8022
0
    return(ctxt->context->node->parent);
8023
0
            case XML_ATTRIBUTE_NODE: {
8024
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8025
8026
0
    return(tmp->parent);
8027
0
      }
8028
0
            case XML_DOCUMENT_NODE:
8029
0
            case XML_DOCUMENT_TYPE_NODE:
8030
0
            case XML_DOCUMENT_FRAG_NODE:
8031
0
            case XML_HTML_DOCUMENT_NODE:
8032
0
                return(NULL);
8033
0
      case XML_NAMESPACE_DECL: {
8034
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8035
8036
0
    if ((ns->next != NULL) &&
8037
0
        (ns->next->type != XML_NAMESPACE_DECL))
8038
0
        return((xmlNodePtr) ns->next);
8039
    /* Bad, how did that namespace end up here ? */
8040
0
                return(NULL);
8041
0
      }
8042
0
  }
8043
0
  return(NULL);
8044
0
    }
8045
0
    if (cur == ctxt->context->doc->children)
8046
0
  return((xmlNodePtr) ctxt->context->doc);
8047
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8048
0
  return(NULL);
8049
0
    switch (cur->type) {
8050
0
  case XML_ELEMENT_NODE:
8051
0
  case XML_TEXT_NODE:
8052
0
  case XML_CDATA_SECTION_NODE:
8053
0
  case XML_ENTITY_REF_NODE:
8054
0
  case XML_ENTITY_NODE:
8055
0
  case XML_PI_NODE:
8056
0
  case XML_COMMENT_NODE:
8057
0
  case XML_NOTATION_NODE:
8058
0
  case XML_DTD_NODE:
8059
0
        case XML_ELEMENT_DECL:
8060
0
        case XML_ATTRIBUTE_DECL:
8061
0
        case XML_ENTITY_DECL:
8062
0
  case XML_XINCLUDE_START:
8063
0
  case XML_XINCLUDE_END:
8064
0
      if (cur->parent == NULL)
8065
0
    return(NULL);
8066
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8067
0
    ((cur->parent->name[0] == ' ') ||
8068
0
     (xmlStrEqual(cur->parent->name,
8069
0
            BAD_CAST "fake node libxslt"))))
8070
0
    return(NULL);
8071
0
      return(cur->parent);
8072
0
  case XML_ATTRIBUTE_NODE: {
8073
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8074
8075
0
      return(att->parent);
8076
0
  }
8077
0
  case XML_NAMESPACE_DECL: {
8078
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8079
8080
0
      if ((ns->next != NULL) &&
8081
0
          (ns->next->type != XML_NAMESPACE_DECL))
8082
0
          return((xmlNodePtr) ns->next);
8083
      /* Bad, how did that namespace end up here ? */
8084
0
            return(NULL);
8085
0
  }
8086
0
  case XML_DOCUMENT_NODE:
8087
0
  case XML_DOCUMENT_TYPE_NODE:
8088
0
  case XML_DOCUMENT_FRAG_NODE:
8089
0
  case XML_HTML_DOCUMENT_NODE:
8090
0
      return(NULL);
8091
0
    }
8092
0
    return(NULL);
8093
0
}
8094
8095
/**
8096
 * xmlXPathNextAncestorOrSelf:
8097
 * @ctxt:  the XPath Parser context
8098
 * @cur:  the current node in the traversal
8099
 *
8100
 * Traversal function for the "ancestor-or-self" direction
8101
 * he ancestor-or-self axis contains the context node and ancestors of
8102
 * the context node in reverse document order; thus the context node is
8103
 * the first node on the axis, and the context node's parent the second;
8104
 * parent here is defined the same as with the parent axis.
8105
 *
8106
 * Returns the next element following that axis
8107
 */
8108
xmlNodePtr
8109
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8110
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8111
0
    if (cur == NULL)
8112
0
        return(ctxt->context->node);
8113
0
    return(xmlXPathNextAncestor(ctxt, cur));
8114
0
}
8115
8116
/**
8117
 * xmlXPathNextFollowingSibling:
8118
 * @ctxt:  the XPath Parser context
8119
 * @cur:  the current node in the traversal
8120
 *
8121
 * Traversal function for the "following-sibling" direction
8122
 * The following-sibling axis contains the following siblings of the context
8123
 * node in document order.
8124
 *
8125
 * Returns the next element following that axis
8126
 */
8127
xmlNodePtr
8128
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8129
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8130
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8131
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8132
0
  return(NULL);
8133
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8134
0
        return(NULL);
8135
0
    if (cur == NULL)
8136
0
        return(ctxt->context->node->next);
8137
0
    return(cur->next);
8138
0
}
8139
8140
/**
8141
 * xmlXPathNextPrecedingSibling:
8142
 * @ctxt:  the XPath Parser context
8143
 * @cur:  the current node in the traversal
8144
 *
8145
 * Traversal function for the "preceding-sibling" direction
8146
 * The preceding-sibling axis contains the preceding siblings of the context
8147
 * node in reverse document order; the first preceding sibling is first on the
8148
 * axis; the sibling preceding that node is the second on the axis and so on.
8149
 *
8150
 * Returns the next element following that axis
8151
 */
8152
xmlNodePtr
8153
5.19k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154
5.19k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155
5.19k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156
5.19k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157
0
  return(NULL);
8158
5.19k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8159
0
        return(NULL);
8160
5.19k
    if (cur == NULL)
8161
260
        return(ctxt->context->node->prev);
8162
4.93k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8163
0
  cur = cur->prev;
8164
0
  if (cur == NULL)
8165
0
      return(ctxt->context->node->prev);
8166
0
    }
8167
4.93k
    return(cur->prev);
8168
4.93k
}
8169
8170
/**
8171
 * xmlXPathNextFollowing:
8172
 * @ctxt:  the XPath Parser context
8173
 * @cur:  the current node in the traversal
8174
 *
8175
 * Traversal function for the "following" direction
8176
 * The following axis contains all nodes in the same document as the context
8177
 * node that are after the context node in document order, excluding any
8178
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8179
 * are ordered in document order
8180
 *
8181
 * Returns the next element following that axis
8182
 */
8183
xmlNodePtr
8184
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8185
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8186
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8187
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8188
0
        return(cur->children);
8189
8190
0
    if (cur == NULL) {
8191
0
        cur = ctxt->context->node;
8192
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8193
0
            cur = cur->parent;
8194
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8195
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8196
8197
0
            if ((ns->next == NULL) ||
8198
0
                (ns->next->type == XML_NAMESPACE_DECL))
8199
0
                return (NULL);
8200
0
            cur = (xmlNodePtr) ns->next;
8201
0
        }
8202
0
    }
8203
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8204
0
    if (cur->next != NULL) return(cur->next) ;
8205
0
    do {
8206
0
        cur = cur->parent;
8207
0
        if (cur == NULL) break;
8208
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8209
0
        if (cur->next != NULL) return(cur->next);
8210
0
    } while (cur != NULL);
8211
0
    return(cur);
8212
0
}
8213
8214
/*
8215
 * xmlXPathIsAncestor:
8216
 * @ancestor:  the ancestor node
8217
 * @node:  the current node
8218
 *
8219
 * Check that @ancestor is a @node's ancestor
8220
 *
8221
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8222
 */
8223
static int
8224
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8225
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8226
0
    if (node->type == XML_NAMESPACE_DECL)
8227
0
        return(0);
8228
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8229
0
        return(0);
8230
    /* nodes need to be in the same document */
8231
0
    if (ancestor->doc != node->doc) return(0);
8232
    /* avoid searching if ancestor or node is the root node */
8233
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8234
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8235
0
    while (node->parent != NULL) {
8236
0
        if (node->parent == ancestor)
8237
0
            return(1);
8238
0
  node = node->parent;
8239
0
    }
8240
0
    return(0);
8241
0
}
8242
8243
/**
8244
 * xmlXPathNextPreceding:
8245
 * @ctxt:  the XPath Parser context
8246
 * @cur:  the current node in the traversal
8247
 *
8248
 * Traversal function for the "preceding" direction
8249
 * the preceding axis contains all nodes in the same document as the context
8250
 * node that are before the context node in document order, excluding any
8251
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8252
 * ordered in reverse document order
8253
 *
8254
 * Returns the next element following that axis
8255
 */
8256
xmlNodePtr
8257
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8258
0
{
8259
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8260
0
    if (cur == NULL) {
8261
0
        cur = ctxt->context->node;
8262
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8263
0
            cur = cur->parent;
8264
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8265
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8266
8267
0
            if ((ns->next == NULL) ||
8268
0
                (ns->next->type == XML_NAMESPACE_DECL))
8269
0
                return (NULL);
8270
0
            cur = (xmlNodePtr) ns->next;
8271
0
        }
8272
0
    }
8273
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8274
0
  return (NULL);
8275
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8276
0
  cur = cur->prev;
8277
0
    do {
8278
0
        if (cur->prev != NULL) {
8279
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8280
0
            return (cur);
8281
0
        }
8282
8283
0
        cur = cur->parent;
8284
0
        if (cur == NULL)
8285
0
            return (NULL);
8286
0
        if (cur == ctxt->context->doc->children)
8287
0
            return (NULL);
8288
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8289
0
    return (cur);
8290
0
}
8291
8292
/**
8293
 * xmlXPathNextPrecedingInternal:
8294
 * @ctxt:  the XPath Parser context
8295
 * @cur:  the current node in the traversal
8296
 *
8297
 * Traversal function for the "preceding" direction
8298
 * the preceding axis contains all nodes in the same document as the context
8299
 * node that are before the context node in document order, excluding any
8300
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8301
 * ordered in reverse document order
8302
 * This is a faster implementation but internal only since it requires a
8303
 * state kept in the parser context: ctxt->ancestor.
8304
 *
8305
 * Returns the next element following that axis
8306
 */
8307
static xmlNodePtr
8308
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8309
                              xmlNodePtr cur)
8310
30
{
8311
30
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8312
30
    if (cur == NULL) {
8313
18
        cur = ctxt->context->node;
8314
18
        if (cur == NULL)
8315
0
            return (NULL);
8316
18
        if (cur->type == XML_ATTRIBUTE_NODE) {
8317
0
            cur = cur->parent;
8318
18
        } else if (cur->type == XML_NAMESPACE_DECL) {
8319
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8320
8321
0
            if ((ns->next == NULL) ||
8322
0
                (ns->next->type == XML_NAMESPACE_DECL))
8323
0
                return (NULL);
8324
0
            cur = (xmlNodePtr) ns->next;
8325
0
        }
8326
18
        ctxt->ancestor = cur->parent;
8327
18
    }
8328
30
    if (cur->type == XML_NAMESPACE_DECL)
8329
0
        return(NULL);
8330
30
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8331
0
  cur = cur->prev;
8332
42
    while (cur->prev == NULL) {
8333
36
        cur = cur->parent;
8334
36
        if (cur == NULL)
8335
12
            return (NULL);
8336
24
        if (cur == ctxt->context->doc->children)
8337
6
            return (NULL);
8338
18
        if (cur != ctxt->ancestor)
8339
6
            return (cur);
8340
12
        ctxt->ancestor = cur->parent;
8341
12
    }
8342
6
    cur = cur->prev;
8343
12
    while (cur->last != NULL)
8344
6
        cur = cur->last;
8345
6
    return (cur);
8346
30
}
8347
8348
/**
8349
 * xmlXPathNextNamespace:
8350
 * @ctxt:  the XPath Parser context
8351
 * @cur:  the current attribute in the traversal
8352
 *
8353
 * Traversal function for the "namespace" direction
8354
 * the namespace axis contains the namespace nodes of the context node;
8355
 * the order of nodes on this axis is implementation-defined; the axis will
8356
 * be empty unless the context node is an element
8357
 *
8358
 * We keep the XML namespace node at the end of the list.
8359
 *
8360
 * Returns the next element following that axis
8361
 */
8362
xmlNodePtr
8363
141k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8364
141k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8365
141k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8366
130k
    if (cur == NULL) {
8367
20.8k
        if (ctxt->context->tmpNsList != NULL)
8368
0
      xmlFree(ctxt->context->tmpNsList);
8369
20.8k
  ctxt->context->tmpNsList =
8370
20.8k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8371
20.8k
  ctxt->context->tmpNsNr = 0;
8372
20.8k
  if (ctxt->context->tmpNsList != NULL) {
8373
109k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8374
88.6k
    ctxt->context->tmpNsNr++;
8375
88.6k
      }
8376
20.8k
  }
8377
20.8k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8378
20.8k
    }
8379
109k
    if (ctxt->context->tmpNsNr > 0) {
8380
88.6k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8381
88.6k
    } else {
8382
20.8k
  if (ctxt->context->tmpNsList != NULL)
8383
20.8k
      xmlFree(ctxt->context->tmpNsList);
8384
20.8k
  ctxt->context->tmpNsList = NULL;
8385
20.8k
  return(NULL);
8386
20.8k
    }
8387
109k
}
8388
8389
/**
8390
 * xmlXPathNextAttribute:
8391
 * @ctxt:  the XPath Parser context
8392
 * @cur:  the current attribute in the traversal
8393
 *
8394
 * Traversal function for the "attribute" direction
8395
 * TODO: support DTD inherited default attributes
8396
 *
8397
 * Returns the next element following that axis
8398
 */
8399
xmlNodePtr
8400
2.04k
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8401
2.04k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8402
2.04k
    if (ctxt->context->node == NULL)
8403
0
  return(NULL);
8404
2.04k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8405
789
  return(NULL);
8406
1.25k
    if (cur == NULL) {
8407
1.07k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8408
0
      return(NULL);
8409
1.07k
        return((xmlNodePtr)ctxt->context->node->properties);
8410
1.07k
    }
8411
179
    return((xmlNodePtr)cur->next);
8412
1.25k
}
8413
8414
/************************************************************************
8415
 *                  *
8416
 *    NodeTest Functions          *
8417
 *                  *
8418
 ************************************************************************/
8419
8420
#define IS_FUNCTION     200
8421
8422
8423
/************************************************************************
8424
 *                  *
8425
 *    Implicit tree core function library     *
8426
 *                  *
8427
 ************************************************************************/
8428
8429
/**
8430
 * xmlXPathRoot:
8431
 * @ctxt:  the XPath Parser context
8432
 *
8433
 * Initialize the context to the root of the document
8434
 */
8435
void
8436
70.6k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8437
70.6k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8438
0
  return;
8439
70.6k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8440
70.6k
  (xmlNodePtr) ctxt->context->doc));
8441
70.6k
}
8442
8443
/************************************************************************
8444
 *                  *
8445
 *    The explicit core function library      *
8446
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8447
 *                  *
8448
 ************************************************************************/
8449
8450
8451
/**
8452
 * xmlXPathLastFunction:
8453
 * @ctxt:  the XPath Parser context
8454
 * @nargs:  the number of arguments
8455
 *
8456
 * Implement the last() XPath function
8457
 *    number last()
8458
 * The last function returns the number of nodes in the context node list.
8459
 */
8460
void
8461
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8462
0
    CHECK_ARITY(0);
8463
0
    if (ctxt->context->contextSize >= 0) {
8464
0
  valuePush(ctxt,
8465
0
      xmlXPathCacheNewFloat(ctxt->context,
8466
0
    (double) ctxt->context->contextSize));
8467
#ifdef DEBUG_EXPR
8468
  xmlGenericError(xmlGenericErrorContext,
8469
    "last() : %d\n", ctxt->context->contextSize);
8470
#endif
8471
0
    } else {
8472
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8473
0
    }
8474
0
}
8475
8476
/**
8477
 * xmlXPathPositionFunction:
8478
 * @ctxt:  the XPath Parser context
8479
 * @nargs:  the number of arguments
8480
 *
8481
 * Implement the position() XPath function
8482
 *    number position()
8483
 * The position function returns the position of the context node in the
8484
 * context node list. The first position is 1, and so the last position
8485
 * will be equal to last().
8486
 */
8487
void
8488
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8489
0
    CHECK_ARITY(0);
8490
0
    if (ctxt->context->proximityPosition >= 0) {
8491
0
  valuePush(ctxt,
8492
0
        xmlXPathCacheNewFloat(ctxt->context,
8493
0
    (double) ctxt->context->proximityPosition));
8494
#ifdef DEBUG_EXPR
8495
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8496
    ctxt->context->proximityPosition);
8497
#endif
8498
0
    } else {
8499
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8500
0
    }
8501
0
}
8502
8503
/**
8504
 * xmlXPathCountFunction:
8505
 * @ctxt:  the XPath Parser context
8506
 * @nargs:  the number of arguments
8507
 *
8508
 * Implement the count() XPath function
8509
 *    number count(node-set)
8510
 */
8511
void
8512
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8513
0
    xmlXPathObjectPtr cur;
8514
8515
0
    CHECK_ARITY(1);
8516
0
    if ((ctxt->value == NULL) ||
8517
0
  ((ctxt->value->type != XPATH_NODESET) &&
8518
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8519
0
  XP_ERROR(XPATH_INVALID_TYPE);
8520
0
    cur = valuePop(ctxt);
8521
8522
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
8523
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8524
0
    else
8525
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8526
0
      (double) cur->nodesetval->nodeNr));
8527
0
    xmlXPathReleaseObject(ctxt->context, cur);
8528
0
}
8529
8530
/**
8531
 * xmlXPathGetElementsByIds:
8532
 * @doc:  the document
8533
 * @ids:  a whitespace separated list of IDs
8534
 *
8535
 * Selects elements by their unique ID.
8536
 *
8537
 * Returns a node-set of selected elements.
8538
 */
8539
static xmlNodeSetPtr
8540
1
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8541
1
    xmlNodeSetPtr ret;
8542
1
    const xmlChar *cur = ids;
8543
1
    xmlChar *ID;
8544
1
    xmlAttrPtr attr;
8545
1
    xmlNodePtr elem = NULL;
8546
8547
1
    if (ids == NULL) return(NULL);
8548
8549
1
    ret = xmlXPathNodeSetCreate(NULL);
8550
1
    if (ret == NULL)
8551
0
        return(ret);
8552
8553
1
    while (IS_BLANK_CH(*cur)) cur++;
8554
2
    while (*cur != 0) {
8555
40.7k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8556
40.7k
      cur++;
8557
8558
1
        ID = xmlStrndup(ids, cur - ids);
8559
1
  if (ID != NULL) {
8560
      /*
8561
       * We used to check the fact that the value passed
8562
       * was an NCName, but this generated much troubles for
8563
       * me and Aleksey Sanin, people blatantly violated that
8564
       * constraint, like Visa3D spec.
8565
       * if (xmlValidateNCName(ID, 1) == 0)
8566
       */
8567
1
      attr = xmlGetID(doc, ID);
8568
1
      if (attr != NULL) {
8569
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8570
0
        elem = attr->parent;
8571
0
    else if (attr->type == XML_ELEMENT_NODE)
8572
0
        elem = (xmlNodePtr) attr;
8573
0
    else
8574
0
        elem = NULL;
8575
                /* TODO: Check memory error. */
8576
0
    if (elem != NULL)
8577
0
        xmlXPathNodeSetAdd(ret, elem);
8578
0
      }
8579
1
      xmlFree(ID);
8580
1
  }
8581
8582
1
  while (IS_BLANK_CH(*cur)) cur++;
8583
1
  ids = cur;
8584
1
    }
8585
1
    return(ret);
8586
1
}
8587
8588
/**
8589
 * xmlXPathIdFunction:
8590
 * @ctxt:  the XPath Parser context
8591
 * @nargs:  the number of arguments
8592
 *
8593
 * Implement the id() XPath function
8594
 *    node-set id(object)
8595
 * The id function selects elements by their unique ID
8596
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8597
 * then the result is the union of the result of applying id to the
8598
 * string value of each of the nodes in the argument node-set. When the
8599
 * argument to id is of any other type, the argument is converted to a
8600
 * string as if by a call to the string function; the string is split
8601
 * into a whitespace-separated list of tokens (whitespace is any sequence
8602
 * of characters matching the production S); the result is a node-set
8603
 * containing the elements in the same document as the context node that
8604
 * have a unique ID equal to any of the tokens in the list.
8605
 */
8606
void
8607
1
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8608
1
    xmlChar *tokens;
8609
1
    xmlNodeSetPtr ret;
8610
1
    xmlXPathObjectPtr obj;
8611
8612
3
    CHECK_ARITY(1);
8613
3
    obj = valuePop(ctxt);
8614
3
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8615
1
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8616
0
  xmlNodeSetPtr ns;
8617
0
  int i;
8618
8619
        /* TODO: Check memory error. */
8620
0
  ret = xmlXPathNodeSetCreate(NULL);
8621
8622
0
  if (obj->nodesetval != NULL) {
8623
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8624
0
    tokens =
8625
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8626
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8627
                /* TODO: Check memory error. */
8628
0
    ret = xmlXPathNodeSetMerge(ret, ns);
8629
0
    xmlXPathFreeNodeSet(ns);
8630
0
    if (tokens != NULL)
8631
0
        xmlFree(tokens);
8632
0
      }
8633
0
  }
8634
0
  xmlXPathReleaseObject(ctxt->context, obj);
8635
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8636
0
  return;
8637
0
    }
8638
1
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8639
1
    if (obj == NULL) return;
8640
1
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8641
1
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8642
1
    xmlXPathReleaseObject(ctxt->context, obj);
8643
1
    return;
8644
1
}
8645
8646
/**
8647
 * xmlXPathLocalNameFunction:
8648
 * @ctxt:  the XPath Parser context
8649
 * @nargs:  the number of arguments
8650
 *
8651
 * Implement the local-name() XPath function
8652
 *    string local-name(node-set?)
8653
 * The local-name function returns a string containing the local part
8654
 * of the name of the node in the argument node-set that is first in
8655
 * document order. If the node-set is empty or the first node has no
8656
 * name, an empty string is returned. If the argument is omitted it
8657
 * defaults to the context node.
8658
 */
8659
void
8660
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8661
0
    xmlXPathObjectPtr cur;
8662
8663
0
    if (ctxt == NULL) return;
8664
8665
0
    if (nargs == 0) {
8666
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8667
0
      ctxt->context->node));
8668
0
  nargs = 1;
8669
0
    }
8670
8671
0
    CHECK_ARITY(1);
8672
0
    if ((ctxt->value == NULL) ||
8673
0
  ((ctxt->value->type != XPATH_NODESET) &&
8674
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8675
0
  XP_ERROR(XPATH_INVALID_TYPE);
8676
0
    cur = valuePop(ctxt);
8677
8678
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8679
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8680
0
    } else {
8681
0
  int i = 0; /* Should be first in document order !!!!! */
8682
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8683
0
  case XML_ELEMENT_NODE:
8684
0
  case XML_ATTRIBUTE_NODE:
8685
0
  case XML_PI_NODE:
8686
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8687
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8688
0
      else
8689
0
    valuePush(ctxt,
8690
0
          xmlXPathCacheNewString(ctxt->context,
8691
0
      cur->nodesetval->nodeTab[i]->name));
8692
0
      break;
8693
0
  case XML_NAMESPACE_DECL:
8694
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8695
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8696
0
      break;
8697
0
  default:
8698
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8699
0
  }
8700
0
    }
8701
0
    xmlXPathReleaseObject(ctxt->context, cur);
8702
0
}
8703
8704
/**
8705
 * xmlXPathNamespaceURIFunction:
8706
 * @ctxt:  the XPath Parser context
8707
 * @nargs:  the number of arguments
8708
 *
8709
 * Implement the namespace-uri() XPath function
8710
 *    string namespace-uri(node-set?)
8711
 * The namespace-uri function returns a string containing the
8712
 * namespace URI of the expanded name of the node in the argument
8713
 * node-set that is first in document order. If the node-set is empty,
8714
 * the first node has no name, or the expanded name has no namespace
8715
 * URI, an empty string is returned. If the argument is omitted it
8716
 * defaults to the context node.
8717
 */
8718
void
8719
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8720
0
    xmlXPathObjectPtr cur;
8721
8722
0
    if (ctxt == NULL) return;
8723
8724
0
    if (nargs == 0) {
8725
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8726
0
      ctxt->context->node));
8727
0
  nargs = 1;
8728
0
    }
8729
0
    CHECK_ARITY(1);
8730
0
    if ((ctxt->value == NULL) ||
8731
0
  ((ctxt->value->type != XPATH_NODESET) &&
8732
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8733
0
  XP_ERROR(XPATH_INVALID_TYPE);
8734
0
    cur = valuePop(ctxt);
8735
8736
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8737
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8738
0
    } else {
8739
0
  int i = 0; /* Should be first in document order !!!!! */
8740
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8741
0
  case XML_ELEMENT_NODE:
8742
0
  case XML_ATTRIBUTE_NODE:
8743
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8744
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8745
0
      else
8746
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8747
0
        cur->nodesetval->nodeTab[i]->ns->href));
8748
0
      break;
8749
0
  default:
8750
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8751
0
  }
8752
0
    }
8753
0
    xmlXPathReleaseObject(ctxt->context, cur);
8754
0
}
8755
8756
/**
8757
 * xmlXPathNameFunction:
8758
 * @ctxt:  the XPath Parser context
8759
 * @nargs:  the number of arguments
8760
 *
8761
 * Implement the name() XPath function
8762
 *    string name(node-set?)
8763
 * The name function returns a string containing a QName representing
8764
 * the name of the node in the argument node-set that is first in document
8765
 * order. The QName must represent the name with respect to the namespace
8766
 * declarations in effect on the node whose name is being represented.
8767
 * Typically, this will be the form in which the name occurred in the XML
8768
 * source. This need not be the case if there are namespace declarations
8769
 * in effect on the node that associate multiple prefixes with the same
8770
 * namespace. However, an implementation may include information about
8771
 * the original prefix in its representation of nodes; in this case, an
8772
 * implementation can ensure that the returned string is always the same
8773
 * as the QName used in the XML source. If the argument it omitted it
8774
 * defaults to the context node.
8775
 * Libxml keep the original prefix so the "real qualified name" used is
8776
 * returned.
8777
 */
8778
static void
8779
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8780
0
{
8781
0
    xmlXPathObjectPtr cur;
8782
8783
0
    if (nargs == 0) {
8784
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8785
0
      ctxt->context->node));
8786
0
        nargs = 1;
8787
0
    }
8788
8789
0
    CHECK_ARITY(1);
8790
0
    if ((ctxt->value == NULL) ||
8791
0
        ((ctxt->value->type != XPATH_NODESET) &&
8792
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
8793
0
        XP_ERROR(XPATH_INVALID_TYPE);
8794
0
    cur = valuePop(ctxt);
8795
8796
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8797
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8798
0
    } else {
8799
0
        int i = 0;              /* Should be first in document order !!!!! */
8800
8801
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8802
0
            case XML_ELEMENT_NODE:
8803
0
            case XML_ATTRIBUTE_NODE:
8804
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8805
0
        valuePush(ctxt,
8806
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8807
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8808
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8809
0
        valuePush(ctxt,
8810
0
            xmlXPathCacheNewString(ctxt->context,
8811
0
          cur->nodesetval->nodeTab[i]->name));
8812
0
    } else {
8813
0
        xmlChar *fullname;
8814
8815
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8816
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8817
0
             NULL, 0);
8818
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8819
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8820
0
        if (fullname == NULL)
8821
0
                        xmlXPathPErrMemory(ctxt, NULL);
8822
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8823
0
      ctxt->context, fullname));
8824
0
                }
8825
0
                break;
8826
0
            default:
8827
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8828
0
        cur->nodesetval->nodeTab[i]));
8829
0
                xmlXPathLocalNameFunction(ctxt, 1);
8830
0
        }
8831
0
    }
8832
0
    xmlXPathReleaseObject(ctxt->context, cur);
8833
0
}
8834
8835
8836
/**
8837
 * xmlXPathStringFunction:
8838
 * @ctxt:  the XPath Parser context
8839
 * @nargs:  the number of arguments
8840
 *
8841
 * Implement the string() XPath function
8842
 *    string string(object?)
8843
 * The string function converts an object to a string as follows:
8844
 *    - A node-set is converted to a string by returning the value of
8845
 *      the node in the node-set that is first in document order.
8846
 *      If the node-set is empty, an empty string is returned.
8847
 *    - A number is converted to a string as follows
8848
 *      + NaN is converted to the string NaN
8849
 *      + positive zero is converted to the string 0
8850
 *      + negative zero is converted to the string 0
8851
 *      + positive infinity is converted to the string Infinity
8852
 *      + negative infinity is converted to the string -Infinity
8853
 *      + if the number is an integer, the number is represented in
8854
 *        decimal form as a Number with no decimal point and no leading
8855
 *        zeros, preceded by a minus sign (-) if the number is negative
8856
 *      + otherwise, the number is represented in decimal form as a
8857
 *        Number including a decimal point with at least one digit
8858
 *        before the decimal point and at least one digit after the
8859
 *        decimal point, preceded by a minus sign (-) if the number
8860
 *        is negative; there must be no leading zeros before the decimal
8861
 *        point apart possibly from the one required digit immediately
8862
 *        before the decimal point; beyond the one required digit
8863
 *        after the decimal point there must be as many, but only as
8864
 *        many, more digits as are needed to uniquely distinguish the
8865
 *        number from all other IEEE 754 numeric values.
8866
 *    - The boolean false value is converted to the string false.
8867
 *      The boolean true value is converted to the string true.
8868
 *
8869
 * If the argument is omitted, it defaults to a node-set with the
8870
 * context node as its only member.
8871
 */
8872
void
8873
169k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8874
169k
    xmlXPathObjectPtr cur;
8875
8876
169k
    if (ctxt == NULL) return;
8877
169k
    if (nargs == 0) {
8878
0
    valuePush(ctxt,
8879
0
  xmlXPathCacheWrapString(ctxt->context,
8880
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8881
0
  return;
8882
0
    }
8883
8884
677k
    CHECK_ARITY(1);
8885
677k
    cur = valuePop(ctxt);
8886
677k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8887
169k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8888
169k
}
8889
8890
/**
8891
 * xmlXPathStringLengthFunction:
8892
 * @ctxt:  the XPath Parser context
8893
 * @nargs:  the number of arguments
8894
 *
8895
 * Implement the string-length() XPath function
8896
 *    number string-length(string?)
8897
 * The string-length returns the number of characters in the string
8898
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8899
 * the context node converted to a string, in other words the value
8900
 * of the context node.
8901
 */
8902
void
8903
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8904
0
    xmlXPathObjectPtr cur;
8905
8906
0
    if (nargs == 0) {
8907
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8908
0
      return;
8909
0
  if (ctxt->context->node == NULL) {
8910
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8911
0
  } else {
8912
0
      xmlChar *content;
8913
8914
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8915
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8916
0
    xmlUTF8Strlen(content)));
8917
0
      xmlFree(content);
8918
0
  }
8919
0
  return;
8920
0
    }
8921
0
    CHECK_ARITY(1);
8922
0
    CAST_TO_STRING;
8923
0
    CHECK_TYPE(XPATH_STRING);
8924
0
    cur = valuePop(ctxt);
8925
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8926
0
  xmlUTF8Strlen(cur->stringval)));
8927
0
    xmlXPathReleaseObject(ctxt->context, cur);
8928
0
}
8929
8930
/**
8931
 * xmlXPathConcatFunction:
8932
 * @ctxt:  the XPath Parser context
8933
 * @nargs:  the number of arguments
8934
 *
8935
 * Implement the concat() XPath function
8936
 *    string concat(string, string, string*)
8937
 * The concat function returns the concatenation of its arguments.
8938
 */
8939
void
8940
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8941
0
    xmlXPathObjectPtr cur, newobj;
8942
0
    xmlChar *tmp;
8943
8944
0
    if (ctxt == NULL) return;
8945
0
    if (nargs < 2) {
8946
0
  CHECK_ARITY(2);
8947
0
    }
8948
8949
0
    CAST_TO_STRING;
8950
0
    cur = valuePop(ctxt);
8951
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8952
0
  xmlXPathReleaseObject(ctxt->context, cur);
8953
0
  return;
8954
0
    }
8955
0
    nargs--;
8956
8957
0
    while (nargs > 0) {
8958
0
  CAST_TO_STRING;
8959
0
  newobj = valuePop(ctxt);
8960
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8961
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8962
0
      xmlXPathReleaseObject(ctxt->context, cur);
8963
0
      XP_ERROR(XPATH_INVALID_TYPE);
8964
0
  }
8965
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8966
0
  newobj->stringval = cur->stringval;
8967
0
  cur->stringval = tmp;
8968
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8969
0
  nargs--;
8970
0
    }
8971
0
    valuePush(ctxt, cur);
8972
0
}
8973
8974
/**
8975
 * xmlXPathContainsFunction:
8976
 * @ctxt:  the XPath Parser context
8977
 * @nargs:  the number of arguments
8978
 *
8979
 * Implement the contains() XPath function
8980
 *    boolean contains(string, string)
8981
 * The contains function returns true if the first argument string
8982
 * contains the second argument string, and otherwise returns false.
8983
 */
8984
void
8985
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8986
0
    xmlXPathObjectPtr hay, needle;
8987
8988
0
    CHECK_ARITY(2);
8989
0
    CAST_TO_STRING;
8990
0
    CHECK_TYPE(XPATH_STRING);
8991
0
    needle = valuePop(ctxt);
8992
0
    CAST_TO_STRING;
8993
0
    hay = valuePop(ctxt);
8994
8995
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8996
0
  xmlXPathReleaseObject(ctxt->context, hay);
8997
0
  xmlXPathReleaseObject(ctxt->context, needle);
8998
0
  XP_ERROR(XPATH_INVALID_TYPE);
8999
0
    }
9000
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9001
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9002
0
    else
9003
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9004
0
    xmlXPathReleaseObject(ctxt->context, hay);
9005
0
    xmlXPathReleaseObject(ctxt->context, needle);
9006
0
}
9007
9008
/**
9009
 * xmlXPathStartsWithFunction:
9010
 * @ctxt:  the XPath Parser context
9011
 * @nargs:  the number of arguments
9012
 *
9013
 * Implement the starts-with() XPath function
9014
 *    boolean starts-with(string, string)
9015
 * The starts-with function returns true if the first argument string
9016
 * starts with the second argument string, and otherwise returns false.
9017
 */
9018
void
9019
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
0
    xmlXPathObjectPtr hay, needle;
9021
0
    int n;
9022
9023
0
    CHECK_ARITY(2);
9024
0
    CAST_TO_STRING;
9025
0
    CHECK_TYPE(XPATH_STRING);
9026
0
    needle = valuePop(ctxt);
9027
0
    CAST_TO_STRING;
9028
0
    hay = valuePop(ctxt);
9029
9030
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9031
0
  xmlXPathReleaseObject(ctxt->context, hay);
9032
0
  xmlXPathReleaseObject(ctxt->context, needle);
9033
0
  XP_ERROR(XPATH_INVALID_TYPE);
9034
0
    }
9035
0
    n = xmlStrlen(needle->stringval);
9036
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9037
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
0
    else
9039
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9040
0
    xmlXPathReleaseObject(ctxt->context, hay);
9041
0
    xmlXPathReleaseObject(ctxt->context, needle);
9042
0
}
9043
9044
/**
9045
 * xmlXPathSubstringFunction:
9046
 * @ctxt:  the XPath Parser context
9047
 * @nargs:  the number of arguments
9048
 *
9049
 * Implement the substring() XPath function
9050
 *    string substring(string, number, number?)
9051
 * The substring function returns the substring of the first argument
9052
 * starting at the position specified in the second argument with
9053
 * length specified in the third argument. For example,
9054
 * substring("12345",2,3) returns "234". If the third argument is not
9055
 * specified, it returns the substring starting at the position specified
9056
 * in the second argument and continuing to the end of the string. For
9057
 * example, substring("12345",2) returns "2345".  More precisely, each
9058
 * character in the string (see [3.6 Strings]) is considered to have a
9059
 * numeric position: the position of the first character is 1, the position
9060
 * of the second character is 2 and so on. The returned substring contains
9061
 * those characters for which the position of the character is greater than
9062
 * or equal to the second argument and, if the third argument is specified,
9063
 * less than the sum of the second and third arguments; the comparisons
9064
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9065
 *  - substring("12345", 1.5, 2.6) returns "234"
9066
 *  - substring("12345", 0, 3) returns "12"
9067
 *  - substring("12345", 0 div 0, 3) returns ""
9068
 *  - substring("12345", 1, 0 div 0) returns ""
9069
 *  - substring("12345", -42, 1 div 0) returns "12345"
9070
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9071
 */
9072
void
9073
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9074
0
    xmlXPathObjectPtr str, start, len;
9075
0
    double le=0, in;
9076
0
    int i = 1, j = INT_MAX;
9077
9078
0
    if (nargs < 2) {
9079
0
  CHECK_ARITY(2);
9080
0
    }
9081
0
    if (nargs > 3) {
9082
0
  CHECK_ARITY(3);
9083
0
    }
9084
    /*
9085
     * take care of possible last (position) argument
9086
    */
9087
0
    if (nargs == 3) {
9088
0
  CAST_TO_NUMBER;
9089
0
  CHECK_TYPE(XPATH_NUMBER);
9090
0
  len = valuePop(ctxt);
9091
0
  le = len->floatval;
9092
0
  xmlXPathReleaseObject(ctxt->context, len);
9093
0
    }
9094
9095
0
    CAST_TO_NUMBER;
9096
0
    CHECK_TYPE(XPATH_NUMBER);
9097
0
    start = valuePop(ctxt);
9098
0
    in = start->floatval;
9099
0
    xmlXPathReleaseObject(ctxt->context, start);
9100
0
    CAST_TO_STRING;
9101
0
    CHECK_TYPE(XPATH_STRING);
9102
0
    str = valuePop(ctxt);
9103
9104
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9105
0
        i = INT_MAX;
9106
0
    } else if (in >= 1.0) {
9107
0
        i = (int)in;
9108
0
        if (in - floor(in) >= 0.5)
9109
0
            i += 1;
9110
0
    }
9111
9112
0
    if (nargs == 3) {
9113
0
        double rin, rle, end;
9114
9115
0
        rin = floor(in);
9116
0
        if (in - rin >= 0.5)
9117
0
            rin += 1.0;
9118
9119
0
        rle = floor(le);
9120
0
        if (le - rle >= 0.5)
9121
0
            rle += 1.0;
9122
9123
0
        end = rin + rle;
9124
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9125
0
            j = 1;
9126
0
        } else if (end < INT_MAX) {
9127
0
            j = (int)end;
9128
0
        }
9129
0
    }
9130
9131
0
    if (i < j) {
9132
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9133
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9134
0
  xmlFree(ret);
9135
0
    } else {
9136
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9137
0
    }
9138
9139
0
    xmlXPathReleaseObject(ctxt->context, str);
9140
0
}
9141
9142
/**
9143
 * xmlXPathSubstringBeforeFunction:
9144
 * @ctxt:  the XPath Parser context
9145
 * @nargs:  the number of arguments
9146
 *
9147
 * Implement the substring-before() XPath function
9148
 *    string substring-before(string, string)
9149
 * The substring-before function returns the substring of the first
9150
 * argument string that precedes the first occurrence of the second
9151
 * argument string in the first argument string, or the empty string
9152
 * if the first argument string does not contain the second argument
9153
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9154
 */
9155
void
9156
9
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9157
9
  xmlXPathObjectPtr str;
9158
9
  xmlXPathObjectPtr find;
9159
9
  xmlBufPtr target;
9160
9
  const xmlChar *point;
9161
9
  int offset;
9162
9163
27
  CHECK_ARITY(2);
9164
27
  CAST_TO_STRING;
9165
27
  find = valuePop(ctxt);
9166
27
  CAST_TO_STRING;
9167
27
  str = valuePop(ctxt);
9168
9169
27
  target = xmlBufCreate();
9170
27
  if (target) {
9171
9
    point = xmlStrstr(str->stringval, find->stringval);
9172
9
    if (point) {
9173
9
      offset = point - str->stringval;
9174
9
      xmlBufAdd(target, str->stringval, offset);
9175
9
    }
9176
9
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9177
9
  xmlBufContent(target)));
9178
9
    xmlBufFree(target);
9179
9
  }
9180
27
  xmlXPathReleaseObject(ctxt->context, str);
9181
27
  xmlXPathReleaseObject(ctxt->context, find);
9182
27
}
9183
9184
/**
9185
 * xmlXPathSubstringAfterFunction:
9186
 * @ctxt:  the XPath Parser context
9187
 * @nargs:  the number of arguments
9188
 *
9189
 * Implement the substring-after() XPath function
9190
 *    string substring-after(string, string)
9191
 * The substring-after function returns the substring of the first
9192
 * argument string that follows the first occurrence of the second
9193
 * argument string in the first argument string, or the empty stringi
9194
 * if the first argument string does not contain the second argument
9195
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9196
 * and substring-after("1999/04/01","19") returns 99/04/01.
9197
 */
9198
void
9199
82.7k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9200
82.7k
  xmlXPathObjectPtr str;
9201
82.7k
  xmlXPathObjectPtr find;
9202
82.7k
  xmlBufPtr target;
9203
82.7k
  const xmlChar *point;
9204
82.7k
  int offset;
9205
9206
248k
  CHECK_ARITY(2);
9207
248k
  CAST_TO_STRING;
9208
248k
  find = valuePop(ctxt);
9209
248k
  CAST_TO_STRING;
9210
248k
  str = valuePop(ctxt);
9211
9212
248k
  target = xmlBufCreate();
9213
248k
  if (target) {
9214
82.7k
    point = xmlStrstr(str->stringval, find->stringval);
9215
82.7k
    if (point) {
9216
0
      offset = point - str->stringval + xmlStrlen(find->stringval);
9217
0
      xmlBufAdd(target, &str->stringval[offset],
9218
0
       xmlStrlen(str->stringval) - offset);
9219
0
    }
9220
82.7k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9221
82.7k
  xmlBufContent(target)));
9222
82.7k
    xmlBufFree(target);
9223
82.7k
  }
9224
248k
  xmlXPathReleaseObject(ctxt->context, str);
9225
248k
  xmlXPathReleaseObject(ctxt->context, find);
9226
248k
}
9227
9228
/**
9229
 * xmlXPathNormalizeFunction:
9230
 * @ctxt:  the XPath Parser context
9231
 * @nargs:  the number of arguments
9232
 *
9233
 * Implement the normalize-space() XPath function
9234
 *    string normalize-space(string?)
9235
 * The normalize-space function returns the argument string with white
9236
 * space normalized by stripping leading and trailing whitespace
9237
 * and replacing sequences of whitespace characters by a single
9238
 * space. Whitespace characters are the same allowed by the S production
9239
 * in XML. If the argument is omitted, it defaults to the context
9240
 * node converted to a string, in other words the value of the context node.
9241
 */
9242
void
9243
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9244
0
    xmlChar *source, *target;
9245
0
    int blank;
9246
9247
0
    if (ctxt == NULL) return;
9248
0
    if (nargs == 0) {
9249
        /* Use current context node */
9250
0
        valuePush(ctxt,
9251
0
            xmlXPathCacheWrapString(ctxt->context,
9252
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9253
0
        nargs = 1;
9254
0
    }
9255
9256
0
    CHECK_ARITY(1);
9257
0
    CAST_TO_STRING;
9258
0
    CHECK_TYPE(XPATH_STRING);
9259
0
    source = ctxt->value->stringval;
9260
0
    if (source == NULL)
9261
0
        return;
9262
0
    target = source;
9263
9264
    /* Skip leading whitespaces */
9265
0
    while (IS_BLANK_CH(*source))
9266
0
        source++;
9267
9268
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9269
0
    blank = 0;
9270
0
    while (*source) {
9271
0
        if (IS_BLANK_CH(*source)) {
9272
0
      blank = 1;
9273
0
        } else {
9274
0
            if (blank) {
9275
0
                *target++ = 0x20;
9276
0
                blank = 0;
9277
0
            }
9278
0
            *target++ = *source;
9279
0
        }
9280
0
        source++;
9281
0
    }
9282
0
    *target = 0;
9283
0
}
9284
9285
/**
9286
 * xmlXPathTranslateFunction:
9287
 * @ctxt:  the XPath Parser context
9288
 * @nargs:  the number of arguments
9289
 *
9290
 * Implement the translate() XPath function
9291
 *    string translate(string, string, string)
9292
 * The translate function returns the first argument string with
9293
 * occurrences of characters in the second argument string replaced
9294
 * by the character at the corresponding position in the third argument
9295
 * string. For example, translate("bar","abc","ABC") returns the string
9296
 * BAr. If there is a character in the second argument string with no
9297
 * character at a corresponding position in the third argument string
9298
 * (because the second argument string is longer than the third argument
9299
 * string), then occurrences of that character in the first argument
9300
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9301
 * returns "AAA". If a character occurs more than once in second
9302
 * argument string, then the first occurrence determines the replacement
9303
 * character. If the third argument string is longer than the second
9304
 * argument string, then excess characters are ignored.
9305
 */
9306
void
9307
13
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9308
13
    xmlXPathObjectPtr str;
9309
13
    xmlXPathObjectPtr from;
9310
13
    xmlXPathObjectPtr to;
9311
13
    xmlBufPtr target;
9312
13
    int offset, max;
9313
13
    int ch;
9314
13
    const xmlChar *point;
9315
13
    xmlChar *cptr;
9316
9317
39
    CHECK_ARITY(3);
9318
9319
39
    CAST_TO_STRING;
9320
39
    to = valuePop(ctxt);
9321
39
    CAST_TO_STRING;
9322
39
    from = valuePop(ctxt);
9323
39
    CAST_TO_STRING;
9324
39
    str = valuePop(ctxt);
9325
9326
39
    target = xmlBufCreate();
9327
39
    if (target) {
9328
13
  max = xmlUTF8Strlen(to->stringval);
9329
230k
  for (cptr = str->stringval; (ch=*cptr); ) {
9330
230k
      offset = xmlUTF8Strloc(from->stringval, cptr);
9331
230k
      if (offset >= 0) {
9332
135k
    if (offset < max) {
9333
7.81k
        point = xmlUTF8Strpos(to->stringval, offset);
9334
7.81k
        if (point)
9335
7.81k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9336
7.81k
    }
9337
135k
      } else
9338
95.0k
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9339
9340
      /* Step to next character in input */
9341
230k
      cptr++;
9342
230k
      if ( ch & 0x80 ) {
9343
    /* if not simple ascii, verify proper format */
9344
95.0k
    if ( (ch & 0xc0) != 0xc0 ) {
9345
5
        xmlGenericError(xmlGenericErrorContext,
9346
5
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9347
                    /* not asserting an XPath error is probably better */
9348
5
        break;
9349
5
    }
9350
    /* then skip over remaining bytes for this char */
9351
285k
    while ( (ch <<= 1) & 0x80 )
9352
190k
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9353
4
      xmlGenericError(xmlGenericErrorContext,
9354
4
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9355
                        /* not asserting an XPath error is probably better */
9356
4
      break;
9357
4
        }
9358
95.0k
    if (ch & 0x80) /* must have had error encountered */
9359
4
        break;
9360
95.0k
      }
9361
230k
  }
9362
13
    }
9363
39
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9364
39
  xmlBufContent(target)));
9365
39
    xmlBufFree(target);
9366
39
    xmlXPathReleaseObject(ctxt->context, str);
9367
39
    xmlXPathReleaseObject(ctxt->context, from);
9368
39
    xmlXPathReleaseObject(ctxt->context, to);
9369
39
}
9370
9371
/**
9372
 * xmlXPathBooleanFunction:
9373
 * @ctxt:  the XPath Parser context
9374
 * @nargs:  the number of arguments
9375
 *
9376
 * Implement the boolean() XPath function
9377
 *    boolean boolean(object)
9378
 * The boolean function converts its argument to a boolean as follows:
9379
 *    - a number is true if and only if it is neither positive or
9380
 *      negative zero nor NaN
9381
 *    - a node-set is true if and only if it is non-empty
9382
 *    - a string is true if and only if its length is non-zero
9383
 */
9384
void
9385
165k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9386
165k
    xmlXPathObjectPtr cur;
9387
9388
496k
    CHECK_ARITY(1);
9389
496k
    cur = valuePop(ctxt);
9390
496k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9391
165k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9392
165k
    valuePush(ctxt, cur);
9393
165k
}
9394
9395
/**
9396
 * xmlXPathNotFunction:
9397
 * @ctxt:  the XPath Parser context
9398
 * @nargs:  the number of arguments
9399
 *
9400
 * Implement the not() XPath function
9401
 *    boolean not(boolean)
9402
 * The not function returns true if its argument is false,
9403
 * and false otherwise.
9404
 */
9405
void
9406
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9407
0
    CHECK_ARITY(1);
9408
0
    CAST_TO_BOOLEAN;
9409
0
    CHECK_TYPE(XPATH_BOOLEAN);
9410
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9411
0
}
9412
9413
/**
9414
 * xmlXPathTrueFunction:
9415
 * @ctxt:  the XPath Parser context
9416
 * @nargs:  the number of arguments
9417
 *
9418
 * Implement the true() XPath function
9419
 *    boolean true()
9420
 */
9421
void
9422
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9423
0
    CHECK_ARITY(0);
9424
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9425
0
}
9426
9427
/**
9428
 * xmlXPathFalseFunction:
9429
 * @ctxt:  the XPath Parser context
9430
 * @nargs:  the number of arguments
9431
 *
9432
 * Implement the false() XPath function
9433
 *    boolean false()
9434
 */
9435
void
9436
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9437
0
    CHECK_ARITY(0);
9438
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9439
0
}
9440
9441
/**
9442
 * xmlXPathLangFunction:
9443
 * @ctxt:  the XPath Parser context
9444
 * @nargs:  the number of arguments
9445
 *
9446
 * Implement the lang() XPath function
9447
 *    boolean lang(string)
9448
 * The lang function returns true or false depending on whether the
9449
 * language of the context node as specified by xml:lang attributes
9450
 * is the same as or is a sublanguage of the language specified by
9451
 * the argument string. The language of the context node is determined
9452
 * by the value of the xml:lang attribute on the context node, or, if
9453
 * the context node has no xml:lang attribute, by the value of the
9454
 * xml:lang attribute on the nearest ancestor of the context node that
9455
 * has an xml:lang attribute. If there is no such attribute, then lang
9456
 * returns false. If there is such an attribute, then lang returns
9457
 * true if the attribute value is equal to the argument ignoring case,
9458
 * or if there is some suffix starting with - such that the attribute
9459
 * value is equal to the argument ignoring that suffix of the attribute
9460
 * value and ignoring case.
9461
 */
9462
void
9463
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9464
0
    xmlXPathObjectPtr val = NULL;
9465
0
    const xmlChar *theLang = NULL;
9466
0
    const xmlChar *lang;
9467
0
    int ret = 0;
9468
0
    int i;
9469
9470
0
    CHECK_ARITY(1);
9471
0
    CAST_TO_STRING;
9472
0
    CHECK_TYPE(XPATH_STRING);
9473
0
    val = valuePop(ctxt);
9474
0
    lang = val->stringval;
9475
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9476
0
    if ((theLang != NULL) && (lang != NULL)) {
9477
0
        for (i = 0;lang[i] != 0;i++)
9478
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9479
0
          goto not_equal;
9480
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9481
0
      ret = 1;
9482
0
    }
9483
0
not_equal:
9484
0
    if (theLang != NULL)
9485
0
  xmlFree((void *)theLang);
9486
9487
0
    xmlXPathReleaseObject(ctxt->context, val);
9488
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9489
0
}
9490
9491
/**
9492
 * xmlXPathNumberFunction:
9493
 * @ctxt:  the XPath Parser context
9494
 * @nargs:  the number of arguments
9495
 *
9496
 * Implement the number() XPath function
9497
 *    number number(object?)
9498
 */
9499
void
9500
197k
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9501
197k
    xmlXPathObjectPtr cur;
9502
197k
    double res;
9503
9504
197k
    if (ctxt == NULL) return;
9505
197k
    if (nargs == 0) {
9506
0
  if (ctxt->context->node == NULL) {
9507
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9508
0
  } else {
9509
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9510
9511
0
      res = xmlXPathStringEvalNumber(content);
9512
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9513
0
      xmlFree(content);
9514
0
  }
9515
0
  return;
9516
0
    }
9517
9518
791k
    CHECK_ARITY(1);
9519
791k
    cur = valuePop(ctxt);
9520
791k
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9521
791k
}
9522
9523
/**
9524
 * xmlXPathSumFunction:
9525
 * @ctxt:  the XPath Parser context
9526
 * @nargs:  the number of arguments
9527
 *
9528
 * Implement the sum() XPath function
9529
 *    number sum(node-set)
9530
 * The sum function returns the sum of the values of the nodes in
9531
 * the argument node-set.
9532
 */
9533
void
9534
9.85k
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
9.85k
    xmlXPathObjectPtr cur;
9536
9.85k
    int i;
9537
9.85k
    double res = 0.0;
9538
9539
29.5k
    CHECK_ARITY(1);
9540
29.5k
    if ((ctxt->value == NULL) ||
9541
9.85k
  ((ctxt->value->type != XPATH_NODESET) &&
9542
9.85k
   (ctxt->value->type != XPATH_XSLT_TREE)))
9543
9.85k
  XP_ERROR(XPATH_INVALID_TYPE);
9544
9.85k
    cur = valuePop(ctxt);
9545
9546
9.85k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9547
14.3k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9548
9.65k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9549
9.65k
  }
9550
4.66k
    }
9551
9.85k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9552
9.85k
    xmlXPathReleaseObject(ctxt->context, cur);
9553
9.85k
}
9554
9555
/**
9556
 * xmlXPathFloorFunction:
9557
 * @ctxt:  the XPath Parser context
9558
 * @nargs:  the number of arguments
9559
 *
9560
 * Implement the floor() XPath function
9561
 *    number floor(number)
9562
 * The floor function returns the largest (closest to positive infinity)
9563
 * number that is not greater than the argument and that is an integer.
9564
 */
9565
void
9566
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9567
0
    CHECK_ARITY(1);
9568
0
    CAST_TO_NUMBER;
9569
0
    CHECK_TYPE(XPATH_NUMBER);
9570
9571
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9572
0
}
9573
9574
/**
9575
 * xmlXPathCeilingFunction:
9576
 * @ctxt:  the XPath Parser context
9577
 * @nargs:  the number of arguments
9578
 *
9579
 * Implement the ceiling() XPath function
9580
 *    number ceiling(number)
9581
 * The ceiling function returns the smallest (closest to negative infinity)
9582
 * number that is not less than the argument and that is an integer.
9583
 */
9584
void
9585
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9586
0
    CHECK_ARITY(1);
9587
0
    CAST_TO_NUMBER;
9588
0
    CHECK_TYPE(XPATH_NUMBER);
9589
9590
#ifdef _AIX
9591
    /* Work around buggy ceil() function on AIX */
9592
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9593
#else
9594
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9595
0
#endif
9596
0
}
9597
9598
/**
9599
 * xmlXPathRoundFunction:
9600
 * @ctxt:  the XPath Parser context
9601
 * @nargs:  the number of arguments
9602
 *
9603
 * Implement the round() XPath function
9604
 *    number round(number)
9605
 * The round function returns the number that is closest to the
9606
 * argument and that is an integer. If there are two such numbers,
9607
 * then the one that is closest to positive infinity is returned.
9608
 */
9609
void
9610
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9611
0
    double f;
9612
9613
0
    CHECK_ARITY(1);
9614
0
    CAST_TO_NUMBER;
9615
0
    CHECK_TYPE(XPATH_NUMBER);
9616
9617
0
    f = ctxt->value->floatval;
9618
9619
0
    if ((f >= -0.5) && (f < 0.5)) {
9620
        /* Handles negative zero. */
9621
0
        ctxt->value->floatval *= 0.0;
9622
0
    }
9623
0
    else {
9624
0
        double rounded = floor(f);
9625
0
        if (f - rounded >= 0.5)
9626
0
            rounded += 1.0;
9627
0
        ctxt->value->floatval = rounded;
9628
0
    }
9629
0
}
9630
9631
/************************************************************************
9632
 *                  *
9633
 *      The Parser          *
9634
 *                  *
9635
 ************************************************************************/
9636
9637
/*
9638
 * a few forward declarations since we use a recursive call based
9639
 * implementation.
9640
 */
9641
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9642
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9643
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9644
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9645
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9646
                                    int qualified);
9647
9648
/**
9649
 * xmlXPathCurrentChar:
9650
 * @ctxt:  the XPath parser context
9651
 * @cur:  pointer to the beginning of the char
9652
 * @len:  pointer to the length of the char read
9653
 *
9654
 * The current char value, if using UTF-8 this may actually span multiple
9655
 * bytes in the input buffer.
9656
 *
9657
 * Returns the current char value and its length
9658
 */
9659
9660
static int
9661
2.15M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9662
2.15M
    unsigned char c;
9663
2.15M
    unsigned int val;
9664
2.15M
    const xmlChar *cur;
9665
9666
2.15M
    if (ctxt == NULL)
9667
0
  return(0);
9668
2.15M
    cur = ctxt->cur;
9669
9670
    /*
9671
     * We are supposed to handle UTF8, check it's valid
9672
     * From rfc2044: encoding of the Unicode values on UTF-8:
9673
     *
9674
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9675
     * 0000 0000-0000 007F   0xxxxxxx
9676
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9677
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9678
     *
9679
     * Check for the 0x110000 limit too
9680
     */
9681
2.15M
    c = *cur;
9682
2.15M
    if (c & 0x80) {
9683
84.5k
  if ((cur[1] & 0xc0) != 0x80)
9684
409
      goto encoding_error;
9685
84.1k
  if ((c & 0xe0) == 0xe0) {
9686
9687
4
      if ((cur[2] & 0xc0) != 0x80)
9688
0
    goto encoding_error;
9689
4
      if ((c & 0xf0) == 0xf0) {
9690
4
    if (((c & 0xf8) != 0xf0) ||
9691
4
        ((cur[3] & 0xc0) != 0x80))
9692
0
        goto encoding_error;
9693
    /* 4-byte code */
9694
4
    *len = 4;
9695
4
    val = (cur[0] & 0x7) << 18;
9696
4
    val |= (cur[1] & 0x3f) << 12;
9697
4
    val |= (cur[2] & 0x3f) << 6;
9698
4
    val |= cur[3] & 0x3f;
9699
4
      } else {
9700
        /* 3-byte code */
9701
0
    *len = 3;
9702
0
    val = (cur[0] & 0xf) << 12;
9703
0
    val |= (cur[1] & 0x3f) << 6;
9704
0
    val |= cur[2] & 0x3f;
9705
0
      }
9706
84.1k
  } else {
9707
    /* 2-byte code */
9708
84.1k
      *len = 2;
9709
84.1k
      val = (cur[0] & 0x1f) << 6;
9710
84.1k
      val |= cur[1] & 0x3f;
9711
84.1k
  }
9712
84.1k
  if (!IS_CHAR(val)) {
9713
4
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9714
0
  }
9715
84.1k
  return(val);
9716
2.06M
    } else {
9717
  /* 1-byte code */
9718
2.06M
  *len = 1;
9719
2.06M
  return(*cur);
9720
2.06M
    }
9721
409
encoding_error:
9722
    /*
9723
     * If we detect an UTF8 error that probably means that the
9724
     * input encoding didn't get properly advertised in the
9725
     * declaration header. Report the error and switch the encoding
9726
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9727
     * encoding !)
9728
     */
9729
409
    *len = 0;
9730
409
    XP_ERROR0(XPATH_ENCODING_ERROR);
9731
0
}
9732
9733
/**
9734
 * xmlXPathParseNCName:
9735
 * @ctxt:  the XPath Parser context
9736
 *
9737
 * parse an XML namespace non qualified name.
9738
 *
9739
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9740
 *
9741
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9742
 *                       CombiningChar | Extender
9743
 *
9744
 * Returns the namespace name or NULL
9745
 */
9746
9747
xmlChar *
9748
623k
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9749
623k
    const xmlChar *in;
9750
623k
    xmlChar *ret;
9751
623k
    int count = 0;
9752
9753
623k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9754
    /*
9755
     * Accelerator for simple ASCII names
9756
     */
9757
623k
    in = ctxt->cur;
9758
623k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9759
623k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9760
623k
  (*in == '_')) {
9761
504k
  in++;
9762
595k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9763
595k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9764
595k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9765
595k
         (*in == '_') || (*in == '.') ||
9766
595k
         (*in == '-'))
9767
90.6k
      in++;
9768
504k
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9769
504k
            (*in == '[') || (*in == ']') || (*in == ':') ||
9770
504k
            (*in == '@') || (*in == '*')) {
9771
63.6k
      count = in - ctxt->cur;
9772
63.6k
      if (count == 0)
9773
0
    return(NULL);
9774
63.6k
      ret = xmlStrndup(ctxt->cur, count);
9775
63.6k
      ctxt->cur = in;
9776
63.6k
      return(ret);
9777
63.6k
  }
9778
504k
    }
9779
559k
    return(xmlXPathParseNameComplex(ctxt, 0));
9780
623k
}
9781
9782
9783
/**
9784
 * xmlXPathParseQName:
9785
 * @ctxt:  the XPath Parser context
9786
 * @prefix:  a xmlChar **
9787
 *
9788
 * parse an XML qualified name
9789
 *
9790
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9791
 *
9792
 * [NS 6] Prefix ::= NCName
9793
 *
9794
 * [NS 7] LocalPart ::= NCName
9795
 *
9796
 * Returns the function returns the local part, and prefix is updated
9797
 *   to get the Prefix if any.
9798
 */
9799
9800
static xmlChar *
9801
19.5k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9802
19.5k
    xmlChar *ret = NULL;
9803
9804
19.5k
    *prefix = NULL;
9805
19.5k
    ret = xmlXPathParseNCName(ctxt);
9806
19.5k
    if (ret && CUR == ':') {
9807
19.4k
        *prefix = ret;
9808
19.4k
  NEXT;
9809
19.4k
  ret = xmlXPathParseNCName(ctxt);
9810
19.4k
    }
9811
19.5k
    return(ret);
9812
19.5k
}
9813
9814
/**
9815
 * xmlXPathParseName:
9816
 * @ctxt:  the XPath Parser context
9817
 *
9818
 * parse an XML name
9819
 *
9820
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9821
 *                  CombiningChar | Extender
9822
 *
9823
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9824
 *
9825
 * Returns the namespace name or NULL
9826
 */
9827
9828
xmlChar *
9829
1
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9830
1
    const xmlChar *in;
9831
1
    xmlChar *ret;
9832
1
    size_t count = 0;
9833
9834
1
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9835
    /*
9836
     * Accelerator for simple ASCII names
9837
     */
9838
1
    in = ctxt->cur;
9839
1
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9840
1
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9841
1
  (*in == '_') || (*in == ':')) {
9842
1
  in++;
9843
40.7k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9844
40.7k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9845
40.7k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9846
40.7k
         (*in == '_') || (*in == '-') ||
9847
40.7k
         (*in == ':') || (*in == '.'))
9848
40.7k
      in++;
9849
1
  if ((*in > 0) && (*in < 0x80)) {
9850
1
      count = in - ctxt->cur;
9851
1
            if (count > XML_MAX_NAME_LENGTH) {
9852
0
                ctxt->cur = in;
9853
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9854
0
            }
9855
1
      ret = xmlStrndup(ctxt->cur, count);
9856
1
      ctxt->cur = in;
9857
1
      return(ret);
9858
1
  }
9859
1
    }
9860
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9861
1
}
9862
9863
static xmlChar *
9864
559k
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9865
559k
    xmlChar buf[XML_MAX_NAMELEN + 5];
9866
559k
    int len = 0, l;
9867
559k
    int c;
9868
9869
    /*
9870
     * Handler for more complex cases
9871
     */
9872
559k
    c = CUR_CHAR(l);
9873
559k
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9874
559k
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9875
559k
        (c == '*') || /* accelerators */
9876
559k
  (!IS_LETTER(c) && (c != '_') &&
9877
467k
         ((!qualified) || (c != ':')))) {
9878
92.3k
  return(NULL);
9879
92.3k
    }
9880
9881
1.00M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9882
1.00M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9883
1.00M
            (c == '.') || (c == '-') ||
9884
1.00M
      (c == '_') || ((qualified) && (c == ':')) ||
9885
1.00M
      (IS_COMBINING(c)) ||
9886
1.00M
      (IS_EXTENDER(c)))) {
9887
540k
  COPY_BUF(l,buf,len,c);
9888
540k
  NEXTL(l);
9889
540k
  c = CUR_CHAR(l);
9890
540k
  if (len >= XML_MAX_NAMELEN) {
9891
      /*
9892
       * Okay someone managed to make a huge name, so he's ready to pay
9893
       * for the processing speed.
9894
       */
9895
2
      xmlChar *buffer;
9896
2
      int max = len * 2;
9897
9898
2
            if (len > XML_MAX_NAME_LENGTH) {
9899
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9900
0
            }
9901
2
      buffer = (xmlChar *) xmlMallocAtomic(max);
9902
2
      if (buffer == NULL) {
9903
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9904
0
      }
9905
2
      memcpy(buffer, buf, len);
9906
2.22k
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9907
2.22k
       (c == '.') || (c == '-') ||
9908
2.22k
       (c == '_') || ((qualified) && (c == ':')) ||
9909
2.22k
       (IS_COMBINING(c)) ||
9910
2.22k
       (IS_EXTENDER(c))) {
9911
2.21k
    if (len + 10 > max) {
9912
6
                    xmlChar *tmp;
9913
6
                    if (max > XML_MAX_NAME_LENGTH) {
9914
0
                        xmlFree(buffer);
9915
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9916
0
                    }
9917
6
        max *= 2;
9918
6
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9919
6
        if (tmp == NULL) {
9920
0
                        xmlFree(buffer);
9921
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9922
0
        }
9923
6
                    buffer = tmp;
9924
6
    }
9925
2.21k
    COPY_BUF(l,buffer,len,c);
9926
2.21k
    NEXTL(l);
9927
2.21k
    c = CUR_CHAR(l);
9928
2.21k
      }
9929
2
      buffer[len] = 0;
9930
2
      return(buffer);
9931
2
  }
9932
540k
    }
9933
467k
    if (len == 0)
9934
0
  return(NULL);
9935
467k
    return(xmlStrndup(buf, len));
9936
467k
}
9937
9938
6
#define MAX_FRAC 20
9939
9940
/**
9941
 * xmlXPathStringEvalNumber:
9942
 * @str:  A string to scan
9943
 *
9944
 *  [30a]  Float  ::= Number ('e' Digits?)?
9945
 *
9946
 *  [30]   Number ::=   Digits ('.' Digits?)?
9947
 *                    | '.' Digits
9948
 *  [31]   Digits ::=   [0-9]+
9949
 *
9950
 * Compile a Number in the string
9951
 * In complement of the Number expression, this function also handles
9952
 * negative values : '-' Number.
9953
 *
9954
 * Returns the double value.
9955
 */
9956
double
9957
222k
xmlXPathStringEvalNumber(const xmlChar *str) {
9958
222k
    const xmlChar *cur = str;
9959
222k
    double ret;
9960
222k
    int ok = 0;
9961
222k
    int isneg = 0;
9962
222k
    int exponent = 0;
9963
222k
    int is_exponent_negative = 0;
9964
222k
#ifdef __GNUC__
9965
222k
    unsigned long tmp = 0;
9966
222k
    double temp;
9967
222k
#endif
9968
222k
    if (cur == NULL) return(0);
9969
222k
    while (IS_BLANK_CH(*cur)) cur++;
9970
222k
    if (*cur == '-') {
9971
204
  isneg = 1;
9972
204
  cur++;
9973
204
    }
9974
222k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9975
221k
        return(xmlXPathNAN);
9976
221k
    }
9977
9978
220
#ifdef __GNUC__
9979
    /*
9980
     * tmp/temp is a workaround against a gcc compiler bug
9981
     * http://veillard.com/gcc.bug
9982
     */
9983
220
    ret = 0;
9984
428
    while ((*cur >= '0') && (*cur <= '9')) {
9985
208
  ret = ret * 10;
9986
208
  tmp = (*cur - '0');
9987
208
  ok = 1;
9988
208
  cur++;
9989
208
  temp = (double) tmp;
9990
208
  ret = ret + temp;
9991
208
    }
9992
#else
9993
    ret = 0;
9994
    while ((*cur >= '0') && (*cur <= '9')) {
9995
  ret = ret * 10 + (*cur - '0');
9996
  ok = 1;
9997
  cur++;
9998
    }
9999
#endif
10000
10001
220
    if (*cur == '.') {
10002
12
  int v, frac = 0, max;
10003
12
  double fraction = 0;
10004
10005
12
        cur++;
10006
12
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10007
12
      return(xmlXPathNAN);
10008
12
  }
10009
0
        while (*cur == '0') {
10010
0
      frac = frac + 1;
10011
0
      cur++;
10012
0
        }
10013
0
        max = frac + MAX_FRAC;
10014
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10015
0
      v = (*cur - '0');
10016
0
      fraction = fraction * 10 + v;
10017
0
      frac = frac + 1;
10018
0
      cur++;
10019
0
  }
10020
0
  fraction /= pow(10.0, frac);
10021
0
  ret = ret + fraction;
10022
0
  while ((*cur >= '0') && (*cur <= '9'))
10023
0
      cur++;
10024
0
    }
10025
208
    if ((*cur == 'e') || (*cur == 'E')) {
10026
0
      cur++;
10027
0
      if (*cur == '-') {
10028
0
  is_exponent_negative = 1;
10029
0
  cur++;
10030
0
      } else if (*cur == '+') {
10031
0
        cur++;
10032
0
      }
10033
0
      while ((*cur >= '0') && (*cur <= '9')) {
10034
0
        if (exponent < 1000000)
10035
0
    exponent = exponent * 10 + (*cur - '0');
10036
0
  cur++;
10037
0
      }
10038
0
    }
10039
208
    while (IS_BLANK_CH(*cur)) cur++;
10040
208
    if (*cur != 0) return(xmlXPathNAN);
10041
208
    if (isneg) ret = -ret;
10042
208
    if (is_exponent_negative) exponent = -exponent;
10043
208
    ret *= pow(10.0, (double)exponent);
10044
208
    return(ret);
10045
208
}
10046
10047
/**
10048
 * xmlXPathCompNumber:
10049
 * @ctxt:  the XPath Parser context
10050
 *
10051
 *  [30]   Number ::=   Digits ('.' Digits?)?
10052
 *                    | '.' Digits
10053
 *  [31]   Digits ::=   [0-9]+
10054
 *
10055
 * Compile a Number, then push it on the stack
10056
 *
10057
 */
10058
static void
10059
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10060
745
{
10061
745
    double ret = 0.0;
10062
745
    int ok = 0;
10063
745
    int exponent = 0;
10064
745
    int is_exponent_negative = 0;
10065
745
    xmlXPathObjectPtr num;
10066
745
#ifdef __GNUC__
10067
745
    unsigned long tmp = 0;
10068
745
    double temp;
10069
745
#endif
10070
10071
745
    CHECK_ERROR;
10072
733
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10073
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10074
0
    }
10075
733
#ifdef __GNUC__
10076
    /*
10077
     * tmp/temp is a workaround against a gcc compiler bug
10078
     * http://veillard.com/gcc.bug
10079
     */
10080
733
    ret = 0;
10081
1.51k
    while ((CUR >= '0') && (CUR <= '9')) {
10082
777
  ret = ret * 10;
10083
777
  tmp = (CUR - '0');
10084
777
        ok = 1;
10085
777
        NEXT;
10086
777
  temp = (double) tmp;
10087
777
  ret = ret + temp;
10088
777
    }
10089
#else
10090
    ret = 0;
10091
    while ((CUR >= '0') && (CUR <= '9')) {
10092
  ret = ret * 10 + (CUR - '0');
10093
  ok = 1;
10094
  NEXT;
10095
    }
10096
#endif
10097
733
    if (CUR == '.') {
10098
6
  int v, frac = 0, max;
10099
6
  double fraction = 0;
10100
10101
6
        NEXT;
10102
6
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10103
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10104
0
        }
10105
10
        while (CUR == '0') {
10106
4
            frac = frac + 1;
10107
4
            NEXT;
10108
4
        }
10109
6
        max = frac + MAX_FRAC;
10110
8
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10111
2
      v = (CUR - '0');
10112
2
      fraction = fraction * 10 + v;
10113
2
      frac = frac + 1;
10114
2
            NEXT;
10115
2
        }
10116
6
        fraction /= pow(10.0, frac);
10117
6
        ret = ret + fraction;
10118
6
        while ((CUR >= '0') && (CUR <= '9'))
10119
0
            NEXT;
10120
6
    }
10121
733
    if ((CUR == 'e') || (CUR == 'E')) {
10122
9
        NEXT;
10123
9
        if (CUR == '-') {
10124
0
            is_exponent_negative = 1;
10125
0
            NEXT;
10126
9
        } else if (CUR == '+') {
10127
0
      NEXT;
10128
0
  }
10129
10
        while ((CUR >= '0') && (CUR <= '9')) {
10130
1
            if (exponent < 1000000)
10131
1
                exponent = exponent * 10 + (CUR - '0');
10132
1
            NEXT;
10133
1
        }
10134
9
        if (is_exponent_negative)
10135
0
            exponent = -exponent;
10136
9
        ret *= pow(10.0, (double) exponent);
10137
9
    }
10138
733
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10139
733
    if (num == NULL) {
10140
0
  ctxt->error = XPATH_MEMORY_ERROR;
10141
733
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10142
733
                              NULL) == -1) {
10143
0
        xmlXPathReleaseObject(ctxt->context, num);
10144
0
    }
10145
733
}
10146
10147
/**
10148
 * xmlXPathParseLiteral:
10149
 * @ctxt:  the XPath Parser context
10150
 *
10151
 * Parse a Literal
10152
 *
10153
 *  [29]   Literal ::=   '"' [^"]* '"'
10154
 *                    | "'" [^']* "'"
10155
 *
10156
 * Returns the value found or NULL in case of error
10157
 */
10158
static xmlChar *
10159
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10160
0
    const xmlChar *q;
10161
0
    xmlChar *ret = NULL;
10162
10163
0
    if (CUR == '"') {
10164
0
        NEXT;
10165
0
  q = CUR_PTR;
10166
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10167
0
      NEXT;
10168
0
  if (!IS_CHAR_CH(CUR)) {
10169
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10170
0
  } else {
10171
0
      ret = xmlStrndup(q, CUR_PTR - q);
10172
0
      NEXT;
10173
0
        }
10174
0
    } else if (CUR == '\'') {
10175
0
        NEXT;
10176
0
  q = CUR_PTR;
10177
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10178
0
      NEXT;
10179
0
  if (!IS_CHAR_CH(CUR)) {
10180
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10181
0
  } else {
10182
0
      ret = xmlStrndup(q, CUR_PTR - q);
10183
0
      NEXT;
10184
0
        }
10185
0
    } else {
10186
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10187
0
    }
10188
0
    return(ret);
10189
0
}
10190
10191
/**
10192
 * xmlXPathCompLiteral:
10193
 * @ctxt:  the XPath Parser context
10194
 *
10195
 * Parse a Literal and push it on the stack.
10196
 *
10197
 *  [29]   Literal ::=   '"' [^"]* '"'
10198
 *                    | "'" [^']* "'"
10199
 *
10200
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10201
 */
10202
static void
10203
129
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10204
129
    const xmlChar *q;
10205
129
    xmlChar *ret = NULL;
10206
129
    xmlXPathObjectPtr lit;
10207
10208
129
    if (CUR == '"') {
10209
33
        NEXT;
10210
33
  q = CUR_PTR;
10211
59.6k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10212
59.6k
      NEXT;
10213
33
  if (!IS_CHAR_CH(CUR)) {
10214
18
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10215
15
  } else {
10216
15
      ret = xmlStrndup(q, CUR_PTR - q);
10217
15
      NEXT;
10218
15
        }
10219
96
    } else if (CUR == '\'') {
10220
96
        NEXT;
10221
96
  q = CUR_PTR;
10222
3.53M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10223
3.53M
      NEXT;
10224
96
  if (!IS_CHAR_CH(CUR)) {
10225
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10226
96
  } else {
10227
96
      ret = xmlStrndup(q, CUR_PTR - q);
10228
96
      NEXT;
10229
96
        }
10230
96
    } else {
10231
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10232
0
    }
10233
111
    if (ret == NULL) {
10234
0
        xmlXPathPErrMemory(ctxt, NULL);
10235
0
        return;
10236
0
    }
10237
111
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10238
111
    if (lit == NULL) {
10239
0
  ctxt->error = XPATH_MEMORY_ERROR;
10240
111
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10241
111
                              NULL) == -1) {
10242
0
        xmlXPathReleaseObject(ctxt->context, lit);
10243
0
    }
10244
111
    xmlFree(ret);
10245
111
}
10246
10247
/**
10248
 * xmlXPathCompVariableReference:
10249
 * @ctxt:  the XPath Parser context
10250
 *
10251
 * Parse a VariableReference, evaluate it and push it on the stack.
10252
 *
10253
 * The variable bindings consist of a mapping from variable names
10254
 * to variable values. The value of a variable is an object, which can be
10255
 * of any of the types that are possible for the value of an expression,
10256
 * and may also be of additional types not specified here.
10257
 *
10258
 * Early evaluation is possible since:
10259
 * The variable bindings [...] used to evaluate a subexpression are
10260
 * always the same as those used to evaluate the containing expression.
10261
 *
10262
 *  [36]   VariableReference ::=   '$' QName
10263
 */
10264
static void
10265
4
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10266
4
    xmlChar *name;
10267
4
    xmlChar *prefix;
10268
10269
4
    SKIP_BLANKS;
10270
4
    if (CUR != '$') {
10271
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10272
0
    }
10273
4
    NEXT;
10274
4
    name = xmlXPathParseQName(ctxt, &prefix);
10275
4
    if (name == NULL) {
10276
0
        xmlFree(prefix);
10277
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10278
0
    }
10279
4
    ctxt->comp->last = -1;
10280
4
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10281
0
        xmlFree(prefix);
10282
0
        xmlFree(name);
10283
0
    }
10284
4
    SKIP_BLANKS;
10285
4
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10286
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10287
0
    }
10288
4
}
10289
10290
/**
10291
 * xmlXPathIsNodeType:
10292
 * @name:  a name string
10293
 *
10294
 * Is the name given a NodeType one.
10295
 *
10296
 *  [38]   NodeType ::=   'comment'
10297
 *                    | 'text'
10298
 *                    | 'processing-instruction'
10299
 *                    | 'node'
10300
 *
10301
 * Returns 1 if true 0 otherwise
10302
 */
10303
int
10304
19.4k
xmlXPathIsNodeType(const xmlChar *name) {
10305
19.4k
    if (name == NULL)
10306
0
  return(0);
10307
10308
19.4k
    if (xmlStrEqual(name, BAD_CAST "node"))
10309
0
  return(1);
10310
19.4k
    if (xmlStrEqual(name, BAD_CAST "text"))
10311
0
  return(1);
10312
19.4k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10313
0
  return(1);
10314
19.4k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10315
0
  return(1);
10316
19.4k
    return(0);
10317
19.4k
}
10318
10319
/**
10320
 * xmlXPathCompFunctionCall:
10321
 * @ctxt:  the XPath Parser context
10322
 *
10323
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10324
 *  [17]   Argument ::=   Expr
10325
 *
10326
 * Compile a function call, the evaluation of all arguments are
10327
 * pushed on the stack
10328
 */
10329
static void
10330
19.4k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10331
19.4k
    xmlChar *name;
10332
19.4k
    xmlChar *prefix;
10333
19.4k
    int nbargs = 0;
10334
19.4k
    int sort = 1;
10335
10336
19.4k
    name = xmlXPathParseQName(ctxt, &prefix);
10337
19.4k
    if (name == NULL) {
10338
0
  xmlFree(prefix);
10339
0
  XP_ERROR(XPATH_EXPR_ERROR);
10340
0
    }
10341
19.4k
    SKIP_BLANKS;
10342
#ifdef DEBUG_EXPR
10343
    if (prefix == NULL)
10344
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10345
      name);
10346
    else
10347
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10348
      prefix, name);
10349
#endif
10350
10351
19.4k
    if (CUR != '(') {
10352
0
  xmlFree(name);
10353
0
  xmlFree(prefix);
10354
0
  XP_ERROR(XPATH_EXPR_ERROR);
10355
0
    }
10356
19.4k
    NEXT;
10357
19.4k
    SKIP_BLANKS;
10358
10359
    /*
10360
    * Optimization for count(): we don't need the node-set to be sorted.
10361
    */
10362
19.4k
    if ((prefix == NULL) && (name[0] == 'c') &&
10363
19.4k
  xmlStrEqual(name, BAD_CAST "count"))
10364
0
    {
10365
0
  sort = 0;
10366
0
    }
10367
19.4k
    ctxt->comp->last = -1;
10368
19.4k
    if (CUR != ')') {
10369
26.0k
  while (CUR != 0) {
10370
26.0k
      int op1 = ctxt->comp->last;
10371
26.0k
      ctxt->comp->last = -1;
10372
26.0k
      xmlXPathCompileExpr(ctxt, sort);
10373
26.0k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10374
12.8k
    xmlFree(name);
10375
12.8k
    xmlFree(prefix);
10376
12.8k
    return;
10377
12.8k
      }
10378
13.2k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10379
13.2k
      nbargs++;
10380
13.2k
      if (CUR == ')') break;
10381
6.61k
      if (CUR != ',') {
10382
25
    xmlFree(name);
10383
25
    xmlFree(prefix);
10384
25
    XP_ERROR(XPATH_EXPR_ERROR);
10385
0
      }
10386
6.58k
      NEXT;
10387
6.58k
      SKIP_BLANKS;
10388
6.58k
  }
10389
19.4k
    }
10390
6.63k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10391
0
        xmlFree(prefix);
10392
0
        xmlFree(name);
10393
0
    }
10394
6.63k
    NEXT;
10395
6.63k
    SKIP_BLANKS;
10396
6.63k
}
10397
10398
/**
10399
 * xmlXPathCompPrimaryExpr:
10400
 * @ctxt:  the XPath Parser context
10401
 *
10402
 *  [15]   PrimaryExpr ::=   VariableReference
10403
 *                | '(' Expr ')'
10404
 *                | Literal
10405
 *                | Number
10406
 *                | FunctionCall
10407
 *
10408
 * Compile a primary expression.
10409
 */
10410
static void
10411
39.7k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10412
39.7k
    SKIP_BLANKS;
10413
39.7k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10414
39.7k
    else if (CUR == '(') {
10415
19.3k
  NEXT;
10416
19.3k
  SKIP_BLANKS;
10417
19.3k
  xmlXPathCompileExpr(ctxt, 1);
10418
19.3k
  CHECK_ERROR;
10419
19.3k
  if (CUR != ')') {
10420
2
      XP_ERROR(XPATH_EXPR_ERROR);
10421
0
  }
10422
19.3k
  NEXT;
10423
19.3k
  SKIP_BLANKS;
10424
20.3k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425
745
  xmlXPathCompNumber(ctxt);
10426
19.6k
    } else if ((CUR == '\'') || (CUR == '"')) {
10427
129
  xmlXPathCompLiteral(ctxt);
10428
19.4k
    } else {
10429
19.4k
  xmlXPathCompFunctionCall(ctxt);
10430
19.4k
    }
10431
39.7k
    SKIP_BLANKS;
10432
39.7k
}
10433
10434
/**
10435
 * xmlXPathCompFilterExpr:
10436
 * @ctxt:  the XPath Parser context
10437
 *
10438
 *  [20]   FilterExpr ::=   PrimaryExpr
10439
 *               | FilterExpr Predicate
10440
 *
10441
 * Compile a filter expression.
10442
 * Square brackets are used to filter expressions in the same way that
10443
 * they are used in location paths. It is an error if the expression to
10444
 * be filtered does not evaluate to a node-set. The context node list
10445
 * used for evaluating the expression in square brackets is the node-set
10446
 * to be filtered listed in document order.
10447
 */
10448
10449
static void
10450
39.7k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10451
39.7k
    xmlXPathCompPrimaryExpr(ctxt);
10452
39.7k
    CHECK_ERROR;
10453
26.8k
    SKIP_BLANKS;
10454
10455
46.2k
    while (CUR == '[') {
10456
19.3k
  xmlXPathCompPredicate(ctxt, 1);
10457
19.3k
  SKIP_BLANKS;
10458
19.3k
    }
10459
10460
10461
26.8k
}
10462
10463
/**
10464
 * xmlXPathScanName:
10465
 * @ctxt:  the XPath Parser context
10466
 *
10467
 * Trickery: parse an XML name but without consuming the input flow
10468
 * Needed to avoid insanity in the parser state.
10469
 *
10470
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10471
 *                  CombiningChar | Extender
10472
 *
10473
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10474
 *
10475
 * [6] Names ::= Name (S Name)*
10476
 *
10477
 * Returns the Name parsed or NULL
10478
 */
10479
10480
static xmlChar *
10481
454k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10482
454k
    int l;
10483
454k
    int c;
10484
454k
    const xmlChar *cur;
10485
454k
    xmlChar *ret;
10486
10487
454k
    cur = ctxt->cur;
10488
10489
454k
    c = CUR_CHAR(l);
10490
454k
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10491
454k
  (!IS_LETTER(c) && (c != '_') &&
10492
454k
         (c != ':'))) {
10493
1.00k
  return(NULL);
10494
1.00k
    }
10495
10496
1.04M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10497
1.04M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10498
1.04M
            (c == '.') || (c == '-') ||
10499
1.04M
      (c == '_') || (c == ':') ||
10500
1.04M
      (IS_COMBINING(c)) ||
10501
1.04M
      (IS_EXTENDER(c)))) {
10502
595k
  NEXTL(l);
10503
595k
  c = CUR_CHAR(l);
10504
595k
    }
10505
453k
    ret = xmlStrndup(cur, ctxt->cur - cur);
10506
453k
    ctxt->cur = cur;
10507
453k
    return(ret);
10508
454k
}
10509
10510
/**
10511
 * xmlXPathCompPathExpr:
10512
 * @ctxt:  the XPath Parser context
10513
 *
10514
 *  [19]   PathExpr ::=   LocationPath
10515
 *               | FilterExpr
10516
 *               | FilterExpr '/' RelativeLocationPath
10517
 *               | FilterExpr '//' RelativeLocationPath
10518
 *
10519
 * Compile a path expression.
10520
 * The / operator and // operators combine an arbitrary expression
10521
 * and a relative location path. It is an error if the expression
10522
 * does not evaluate to a node-set.
10523
 * The / operator does composition in the same way as when / is
10524
 * used in a location path. As in location paths, // is short for
10525
 * /descendant-or-self::node()/.
10526
 */
10527
10528
static void
10529
573k
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10530
573k
    int lc = 1;           /* Should we branch to LocationPath ?         */
10531
573k
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10532
10533
573k
    SKIP_BLANKS;
10534
573k
    if ((CUR == '$') || (CUR == '(') ||
10535
573k
  (IS_ASCII_DIGIT(CUR)) ||
10536
573k
        (CUR == '\'') || (CUR == '"') ||
10537
573k
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10538
20.2k
  lc = 0;
10539
553k
    } else if (CUR == '*') {
10540
  /* relative or absolute location path */
10541
58.0k
  lc = 1;
10542
495k
    } else if (CUR == '/') {
10543
  /* relative or absolute location path */
10544
33.6k
  lc = 1;
10545
461k
    } else if (CUR == '@') {
10546
  /* relative abbreviated attribute location path */
10547
27
  lc = 1;
10548
461k
    } else if (CUR == '.') {
10549
  /* relative abbreviated attribute location path */
10550
6.62k
  lc = 1;
10551
454k
    } else {
10552
  /*
10553
   * Problem is finding if we have a name here whether it's:
10554
   *   - a nodetype
10555
   *   - a function call in which case it's followed by '('
10556
   *   - an axis in which case it's followed by ':'
10557
   *   - a element name
10558
   * We do an a priori analysis here rather than having to
10559
   * maintain parsed token content through the recursive function
10560
   * calls. This looks uglier but makes the code easier to
10561
   * read/write/debug.
10562
   */
10563
454k
  SKIP_BLANKS;
10564
454k
  name = xmlXPathScanName(ctxt);
10565
454k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10566
#ifdef DEBUG_STEP
10567
      xmlGenericError(xmlGenericErrorContext,
10568
        "PathExpr: Axis\n");
10569
#endif
10570
6
      lc = 1;
10571
6
      xmlFree(name);
10572
454k
  } else if (name != NULL) {
10573
453k
      int len =xmlStrlen(name);
10574
10575
10576
453k
      while (NXT(len) != 0) {
10577
453k
    if (NXT(len) == '/') {
10578
        /* element name */
10579
#ifdef DEBUG_STEP
10580
        xmlGenericError(xmlGenericErrorContext,
10581
          "PathExpr: AbbrRelLocation\n");
10582
#endif
10583
105
        lc = 1;
10584
105
        break;
10585
453k
    } else if (IS_BLANK_CH(NXT(len))) {
10586
        /* ignore blanks */
10587
105
        ;
10588
453k
    } else if (NXT(len) == ':') {
10589
#ifdef DEBUG_STEP
10590
        xmlGenericError(xmlGenericErrorContext,
10591
          "PathExpr: AbbrRelLocation\n");
10592
#endif
10593
6
        lc = 1;
10594
6
        break;
10595
453k
    } else if ((NXT(len) == '(')) {
10596
        /* Node Type or Function */
10597
19.4k
        if (xmlXPathIsNodeType(name)) {
10598
#ifdef DEBUG_STEP
10599
            xmlGenericError(xmlGenericErrorContext,
10600
        "PathExpr: Type search\n");
10601
#endif
10602
0
      lc = 1;
10603
#ifdef LIBXML_XPTR_LOCS_ENABLED
10604
                    } else if (ctxt->xptr &&
10605
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10606
                        lc = 1;
10607
#endif
10608
19.4k
        } else {
10609
#ifdef DEBUG_STEP
10610
            xmlGenericError(xmlGenericErrorContext,
10611
        "PathExpr: function call\n");
10612
#endif
10613
19.4k
      lc = 0;
10614
19.4k
        }
10615
19.4k
                    break;
10616
434k
    } else if ((NXT(len) == '[')) {
10617
        /* element name */
10618
#ifdef DEBUG_STEP
10619
        xmlGenericError(xmlGenericErrorContext,
10620
          "PathExpr: AbbrRelLocation\n");
10621
#endif
10622
16
        lc = 1;
10623
16
        break;
10624
434k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10625
434k
         (NXT(len) == '=')) {
10626
632
        lc = 1;
10627
632
        break;
10628
433k
    } else {
10629
433k
        lc = 1;
10630
433k
        break;
10631
433k
    }
10632
105
    len++;
10633
105
      }
10634
453k
      if (NXT(len) == 0) {
10635
#ifdef DEBUG_STEP
10636
    xmlGenericError(xmlGenericErrorContext,
10637
      "PathExpr: AbbrRelLocation\n");
10638
#endif
10639
    /* element name */
10640
76
    lc = 1;
10641
76
      }
10642
453k
      xmlFree(name);
10643
453k
  } else {
10644
      /* make sure all cases are covered explicitly */
10645
1.00k
      XP_ERROR(XPATH_EXPR_ERROR);
10646
0
  }
10647
454k
    }
10648
10649
572k
    if (lc) {
10650
532k
  if (CUR == '/') {
10651
33.6k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10652
499k
  } else {
10653
499k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10654
499k
  }
10655
532k
  xmlXPathCompLocationPath(ctxt);
10656
532k
    } else {
10657
39.7k
  xmlXPathCompFilterExpr(ctxt);
10658
39.7k
  CHECK_ERROR;
10659
14.0k
  if ((CUR == '/') && (NXT(1) == '/')) {
10660
13
      SKIP(2);
10661
13
      SKIP_BLANKS;
10662
10663
13
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10664
13
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10665
10666
13
      xmlXPathCompRelativeLocationPath(ctxt);
10667
14.0k
  } else if (CUR == '/') {
10668
6.54k
      xmlXPathCompRelativeLocationPath(ctxt);
10669
6.54k
  }
10670
14.0k
    }
10671
546k
    SKIP_BLANKS;
10672
546k
}
10673
10674
/**
10675
 * xmlXPathCompUnionExpr:
10676
 * @ctxt:  the XPath Parser context
10677
 *
10678
 *  [18]   UnionExpr ::=   PathExpr
10679
 *               | UnionExpr '|' PathExpr
10680
 *
10681
 * Compile an union expression.
10682
 */
10683
10684
static void
10685
151k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10686
151k
    xmlXPathCompPathExpr(ctxt);
10687
151k
    CHECK_ERROR;
10688
124k
    SKIP_BLANKS;
10689
546k
    while (CUR == '|') {
10690
421k
  int op1 = ctxt->comp->last;
10691
421k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10692
10693
421k
  NEXT;
10694
421k
  SKIP_BLANKS;
10695
421k
  xmlXPathCompPathExpr(ctxt);
10696
10697
421k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10698
10699
421k
  SKIP_BLANKS;
10700
421k
    }
10701
124k
}
10702
10703
/**
10704
 * xmlXPathCompUnaryExpr:
10705
 * @ctxt:  the XPath Parser context
10706
 *
10707
 *  [27]   UnaryExpr ::=   UnionExpr
10708
 *                   | '-' UnaryExpr
10709
 *
10710
 * Compile an unary expression.
10711
 */
10712
10713
static void
10714
151k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10715
151k
    int minus = 0;
10716
151k
    int found = 0;
10717
10718
151k
    SKIP_BLANKS;
10719
171k
    while (CUR == '-') {
10720
19.3k
        minus = 1 - minus;
10721
19.3k
  found = 1;
10722
19.3k
  NEXT;
10723
19.3k
  SKIP_BLANKS;
10724
19.3k
    }
10725
10726
151k
    xmlXPathCompUnionExpr(ctxt);
10727
151k
    CHECK_ERROR;
10728
124k
    if (found) {
10729
19.3k
  if (minus)
10730
19.3k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10731
0
  else
10732
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10733
19.3k
    }
10734
124k
}
10735
10736
/**
10737
 * xmlXPathCompMultiplicativeExpr:
10738
 * @ctxt:  the XPath Parser context
10739
 *
10740
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10741
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10742
 *                   | MultiplicativeExpr 'div' UnaryExpr
10743
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10744
 *  [34]   MultiplyOperator ::=   '*'
10745
 *
10746
 * Compile an Additive expression.
10747
 */
10748
10749
static void
10750
74.5k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10751
74.5k
    xmlXPathCompUnaryExpr(ctxt);
10752
74.5k
    CHECK_ERROR;
10753
60.3k
    SKIP_BLANKS;
10754
124k
    while ((CUR == '*') ||
10755
124k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10756
124k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10757
77.4k
  int op = -1;
10758
77.4k
  int op1 = ctxt->comp->last;
10759
10760
77.4k
        if (CUR == '*') {
10761
77.3k
      op = 0;
10762
77.3k
      NEXT;
10763
77.3k
  } else if (CUR == 'd') {
10764
1
      op = 1;
10765
1
      SKIP(3);
10766
12
  } else if (CUR == 'm') {
10767
12
      op = 2;
10768
12
      SKIP(3);
10769
12
  }
10770
77.4k
  SKIP_BLANKS;
10771
77.4k
        xmlXPathCompUnaryExpr(ctxt);
10772
77.4k
  CHECK_ERROR;
10773
64.5k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10774
64.5k
  SKIP_BLANKS;
10775
64.5k
    }
10776
60.3k
}
10777
10778
/**
10779
 * xmlXPathCompAdditiveExpr:
10780
 * @ctxt:  the XPath Parser context
10781
 *
10782
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10783
 *                   | AdditiveExpr '+' MultiplicativeExpr
10784
 *                   | AdditiveExpr '-' MultiplicativeExpr
10785
 *
10786
 * Compile an Additive expression.
10787
 */
10788
10789
static void
10790
74.3k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10791
10792
74.3k
    xmlXPathCompMultiplicativeExpr(ctxt);
10793
74.3k
    CHECK_ERROR;
10794
47.4k
    SKIP_BLANKS;
10795
47.5k
    while ((CUR == '+') || (CUR == '-')) {
10796
128
  int plus;
10797
128
  int op1 = ctxt->comp->last;
10798
10799
128
        if (CUR == '+') plus = 1;
10800
8
  else plus = 0;
10801
128
  NEXT;
10802
128
  SKIP_BLANKS;
10803
128
        xmlXPathCompMultiplicativeExpr(ctxt);
10804
128
  CHECK_ERROR;
10805
89
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10806
89
  SKIP_BLANKS;
10807
89
    }
10808
47.4k
}
10809
10810
/**
10811
 * xmlXPathCompRelationalExpr:
10812
 * @ctxt:  the XPath Parser context
10813
 *
10814
 *  [24]   RelationalExpr ::=   AdditiveExpr
10815
 *                 | RelationalExpr '<' AdditiveExpr
10816
 *                 | RelationalExpr '>' AdditiveExpr
10817
 *                 | RelationalExpr '<=' AdditiveExpr
10818
 *                 | RelationalExpr '>=' AdditiveExpr
10819
 *
10820
 *  A <= B > C is allowed ? Answer from James, yes with
10821
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10822
 *  which is basically what got implemented.
10823
 *
10824
 * Compile a Relational expression, then push the result
10825
 * on the stack
10826
 */
10827
10828
static void
10829
73.7k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10830
73.7k
    xmlXPathCompAdditiveExpr(ctxt);
10831
73.7k
    CHECK_ERROR;
10832
46.7k
    SKIP_BLANKS;
10833
47.3k
    while ((CUR == '<') || (CUR == '>')) {
10834
635
  int inf, strict;
10835
635
  int op1 = ctxt->comp->last;
10836
10837
635
        if (CUR == '<') inf = 1;
10838
103
  else inf = 0;
10839
635
  if (NXT(1) == '=') strict = 0;
10840
634
  else strict = 1;
10841
635
  NEXT;
10842
635
  if (!strict) NEXT;
10843
635
  SKIP_BLANKS;
10844
635
        xmlXPathCompAdditiveExpr(ctxt);
10845
635
  CHECK_ERROR;
10846
602
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10847
602
  SKIP_BLANKS;
10848
602
    }
10849
46.7k
}
10850
10851
/**
10852
 * xmlXPathCompEqualityExpr:
10853
 * @ctxt:  the XPath Parser context
10854
 *
10855
 *  [23]   EqualityExpr ::=   RelationalExpr
10856
 *                 | EqualityExpr '=' RelationalExpr
10857
 *                 | EqualityExpr '!=' RelationalExpr
10858
 *
10859
 *  A != B != C is allowed ? Answer from James, yes with
10860
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10861
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10862
 *  which is basically what got implemented.
10863
 *
10864
 * Compile an Equality expression.
10865
 *
10866
 */
10867
static void
10868
73.6k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10869
73.6k
    xmlXPathCompRelationalExpr(ctxt);
10870
73.6k
    CHECK_ERROR;
10871
46.7k
    SKIP_BLANKS;
10872
46.7k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10873
95
  int eq;
10874
95
  int op1 = ctxt->comp->last;
10875
10876
95
        if (CUR == '=') eq = 1;
10877
15
  else eq = 0;
10878
95
  NEXT;
10879
95
  if (!eq) NEXT;
10880
95
  SKIP_BLANKS;
10881
95
        xmlXPathCompRelationalExpr(ctxt);
10882
95
  CHECK_ERROR;
10883
58
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10884
58
  SKIP_BLANKS;
10885
58
    }
10886
46.7k
}
10887
10888
/**
10889
 * xmlXPathCompAndExpr:
10890
 * @ctxt:  the XPath Parser context
10891
 *
10892
 *  [22]   AndExpr ::=   EqualityExpr
10893
 *                 | AndExpr 'and' EqualityExpr
10894
 *
10895
 * Compile an AND expression.
10896
 *
10897
 */
10898
static void
10899
73.6k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10900
73.6k
    xmlXPathCompEqualityExpr(ctxt);
10901
73.6k
    CHECK_ERROR;
10902
46.6k
    SKIP_BLANKS;
10903
46.6k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10904
0
  int op1 = ctxt->comp->last;
10905
0
        SKIP(3);
10906
0
  SKIP_BLANKS;
10907
0
        xmlXPathCompEqualityExpr(ctxt);
10908
0
  CHECK_ERROR;
10909
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10910
0
  SKIP_BLANKS;
10911
0
    }
10912
46.6k
}
10913
10914
/**
10915
 * xmlXPathCompileExpr:
10916
 * @ctxt:  the XPath Parser context
10917
 *
10918
 *  [14]   Expr ::=   OrExpr
10919
 *  [21]   OrExpr ::=   AndExpr
10920
 *                 | OrExpr 'or' AndExpr
10921
 *
10922
 * Parse and compile an expression
10923
 */
10924
static void
10925
86.4k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10926
86.4k
    xmlXPathContextPtr xpctxt = ctxt->context;
10927
10928
86.4k
    if (xpctxt != NULL) {
10929
86.4k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10930
73.6k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10931
        /*
10932
         * Parsing a single '(' pushes about 10 functions on the call stack
10933
         * before recursing!
10934
         */
10935
73.6k
        xpctxt->depth += 10;
10936
73.6k
    }
10937
10938
73.6k
    xmlXPathCompAndExpr(ctxt);
10939
73.6k
    CHECK_ERROR;
10940
46.6k
    SKIP_BLANKS;
10941
46.6k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10942
22
  int op1 = ctxt->comp->last;
10943
22
        SKIP(2);
10944
22
  SKIP_BLANKS;
10945
22
        xmlXPathCompAndExpr(ctxt);
10946
22
  CHECK_ERROR;
10947
19
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10948
19
  SKIP_BLANKS;
10949
19
    }
10950
46.6k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10951
  /* more ops could be optimized too */
10952
  /*
10953
  * This is the main place to eliminate sorting for
10954
  * operations which don't require a sorted node-set.
10955
  * E.g. count().
10956
  */
10957
46.3k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10958
46.3k
    }
10959
10960
46.6k
    if (xpctxt != NULL)
10961
46.6k
        xpctxt->depth -= 10;
10962
46.6k
}
10963
10964
/**
10965
 * xmlXPathCompPredicate:
10966
 * @ctxt:  the XPath Parser context
10967
 * @filter:  act as a filter
10968
 *
10969
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10970
 *  [9]   PredicateExpr ::=   Expr
10971
 *
10972
 * Compile a predicate expression
10973
 */
10974
static void
10975
19.5k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10976
19.5k
    int op1 = ctxt->comp->last;
10977
10978
19.5k
    SKIP_BLANKS;
10979
19.5k
    if (CUR != '[') {
10980
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10981
0
    }
10982
19.5k
    NEXT;
10983
19.5k
    SKIP_BLANKS;
10984
10985
19.5k
    ctxt->comp->last = -1;
10986
    /*
10987
    * This call to xmlXPathCompileExpr() will deactivate sorting
10988
    * of the predicate result.
10989
    * TODO: Sorting is still activated for filters, since I'm not
10990
    *  sure if needed. Normally sorting should not be needed, since
10991
    *  a filter can only diminish the number of items in a sequence,
10992
    *  but won't change its order; so if the initial sequence is sorted,
10993
    *  subsequent sorting is not needed.
10994
    */
10995
19.5k
    if (! filter)
10996
137
  xmlXPathCompileExpr(ctxt, 0);
10997
19.3k
    else
10998
19.3k
  xmlXPathCompileExpr(ctxt, 1);
10999
19.5k
    CHECK_ERROR;
11000
11001
6.61k
    if (CUR != ']') {
11002
2
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11003
0
    }
11004
11005
6.61k
    if (filter)
11006
6.53k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11007
71
    else
11008
71
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11009
11010
6.61k
    NEXT;
11011
6.61k
    SKIP_BLANKS;
11012
6.61k
}
11013
11014
/**
11015
 * xmlXPathCompNodeTest:
11016
 * @ctxt:  the XPath Parser context
11017
 * @test:  pointer to a xmlXPathTestVal
11018
 * @type:  pointer to a xmlXPathTypeVal
11019
 * @prefix:  placeholder for a possible name prefix
11020
 *
11021
 * [7] NodeTest ::=   NameTest
11022
 *        | NodeType '(' ')'
11023
 *        | 'processing-instruction' '(' Literal ')'
11024
 *
11025
 * [37] NameTest ::=  '*'
11026
 *        | NCName ':' '*'
11027
 *        | QName
11028
 * [38] NodeType ::= 'comment'
11029
 *       | 'text'
11030
 *       | 'processing-instruction'
11031
 *       | 'node'
11032
 *
11033
 * Returns the name found and updates @test, @type and @prefix appropriately
11034
 */
11035
static xmlChar *
11036
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11037
               xmlXPathTypeVal *type, xmlChar **prefix,
11038
571k
         xmlChar *name) {
11039
571k
    int blanks;
11040
11041
571k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11042
0
  STRANGE;
11043
0
  return(NULL);
11044
0
    }
11045
571k
    *type = (xmlXPathTypeVal) 0;
11046
571k
    *test = (xmlXPathTestVal) 0;
11047
571k
    *prefix = NULL;
11048
571k
    SKIP_BLANKS;
11049
11050
571k
    if ((name == NULL) && (CUR == '*')) {
11051
  /*
11052
   * All elements
11053
   */
11054
80.2k
  NEXT;
11055
80.2k
  *test = NODE_TEST_ALL;
11056
80.2k
  return(NULL);
11057
80.2k
    }
11058
11059
491k
    if (name == NULL)
11060
72
  name = xmlXPathParseNCName(ctxt);
11061
491k
    if (name == NULL) {
11062
28
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11063
0
    }
11064
11065
491k
    blanks = IS_BLANK_CH(CUR);
11066
491k
    SKIP_BLANKS;
11067
491k
    if (CUR == '(') {
11068
231
  NEXT;
11069
  /*
11070
   * NodeType or PI search
11071
   */
11072
231
  if (xmlStrEqual(name, BAD_CAST "comment"))
11073
3
      *type = NODE_TYPE_COMMENT;
11074
228
  else if (xmlStrEqual(name, BAD_CAST "node"))
11075
225
      *type = NODE_TYPE_NODE;
11076
3
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11077
0
      *type = NODE_TYPE_PI;
11078
3
  else if (xmlStrEqual(name, BAD_CAST "text"))
11079
3
      *type = NODE_TYPE_TEXT;
11080
0
  else {
11081
0
      if (name != NULL)
11082
0
    xmlFree(name);
11083
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11084
0
  }
11085
11086
231
  *test = NODE_TEST_TYPE;
11087
11088
231
  SKIP_BLANKS;
11089
231
  if (*type == NODE_TYPE_PI) {
11090
      /*
11091
       * Specific case: search a PI by name.
11092
       */
11093
0
      if (name != NULL)
11094
0
    xmlFree(name);
11095
0
      name = NULL;
11096
0
      if (CUR != ')') {
11097
0
    name = xmlXPathParseLiteral(ctxt);
11098
0
                if (name == NULL) {
11099
0
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11100
0
                }
11101
0
    *test = NODE_TEST_PI;
11102
0
    SKIP_BLANKS;
11103
0
      }
11104
0
  }
11105
231
  if (CUR != ')') {
11106
0
      if (name != NULL)
11107
0
    xmlFree(name);
11108
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11109
0
  }
11110
231
  NEXT;
11111
231
  return(name);
11112
231
    }
11113
490k
    *test = NODE_TEST_NAME;
11114
490k
    if ((!blanks) && (CUR == ':')) {
11115
67
  NEXT;
11116
11117
  /*
11118
   * Since currently the parser context don't have a
11119
   * namespace list associated:
11120
   * The namespace name for this prefix can be computed
11121
   * only at evaluation time. The compilation is done
11122
   * outside of any context.
11123
   */
11124
#if 0
11125
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11126
  if (name != NULL)
11127
      xmlFree(name);
11128
  if (*prefix == NULL) {
11129
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11130
  }
11131
#else
11132
67
  *prefix = name;
11133
67
#endif
11134
11135
67
  if (CUR == '*') {
11136
      /*
11137
       * All elements
11138
       */
11139
0
      NEXT;
11140
0
      *test = NODE_TEST_ALL;
11141
0
      return(NULL);
11142
0
  }
11143
11144
67
  name = xmlXPathParseNCName(ctxt);
11145
67
  if (name == NULL) {
11146
26
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11147
0
  }
11148
67
    }
11149
490k
    return(name);
11150
490k
}
11151
11152
/**
11153
 * xmlXPathIsAxisName:
11154
 * @name:  a preparsed name token
11155
 *
11156
 * [6] AxisName ::=   'ancestor'
11157
 *                  | 'ancestor-or-self'
11158
 *                  | 'attribute'
11159
 *                  | 'child'
11160
 *                  | 'descendant'
11161
 *                  | 'descendant-or-self'
11162
 *                  | 'following'
11163
 *                  | 'following-sibling'
11164
 *                  | 'namespace'
11165
 *                  | 'parent'
11166
 *                  | 'preceding'
11167
 *                  | 'preceding-sibling'
11168
 *                  | 'self'
11169
 *
11170
 * Returns the axis or 0
11171
 */
11172
static xmlXPathAxisVal
11173
491k
xmlXPathIsAxisName(const xmlChar *name) {
11174
491k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11175
491k
    switch (name[0]) {
11176
22.1k
  case 'a':
11177
22.1k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11178
0
    ret = AXIS_ANCESTOR;
11179
22.1k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11180
0
    ret = AXIS_ANCESTOR_OR_SELF;
11181
22.1k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11182
0
    ret = AXIS_ATTRIBUTE;
11183
22.1k
      break;
11184
3
  case 'c':
11185
3
      if (xmlStrEqual(name, BAD_CAST "child"))
11186
0
    ret = AXIS_CHILD;
11187
3
      break;
11188
346
  case 'd':
11189
346
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11190
4
    ret = AXIS_DESCENDANT;
11191
346
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11192
0
    ret = AXIS_DESCENDANT_OR_SELF;
11193
346
      break;
11194
10
  case 'f':
11195
10
      if (xmlStrEqual(name, BAD_CAST "following"))
11196
0
    ret = AXIS_FOLLOWING;
11197
10
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11198
0
    ret = AXIS_FOLLOWING_SIBLING;
11199
10
      break;
11200
427
  case 'n':
11201
427
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11202
160
    ret = AXIS_NAMESPACE;
11203
427
      break;
11204
33
  case 'p':
11205
33
      if (xmlStrEqual(name, BAD_CAST "parent"))
11206
0
    ret = AXIS_PARENT;
11207
33
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11208
12
    ret = AXIS_PRECEDING;
11209
33
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11210
4
    ret = AXIS_PRECEDING_SIBLING;
11211
33
      break;
11212
139
  case 's':
11213
139
      if (xmlStrEqual(name, BAD_CAST "self"))
11214
0
    ret = AXIS_SELF;
11215
139
      break;
11216
491k
    }
11217
491k
    return(ret);
11218
491k
}
11219
11220
/**
11221
 * xmlXPathCompStep:
11222
 * @ctxt:  the XPath Parser context
11223
 *
11224
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11225
 *                  | AbbreviatedStep
11226
 *
11227
 * [12] AbbreviatedStep ::=   '.' | '..'
11228
 *
11229
 * [5] AxisSpecifier ::= AxisName '::'
11230
 *                  | AbbreviatedAxisSpecifier
11231
 *
11232
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11233
 *
11234
 * Modified for XPtr range support as:
11235
 *
11236
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11237
 *                     | AbbreviatedStep
11238
 *                     | 'range-to' '(' Expr ')' Predicate*
11239
 *
11240
 * Compile one step in a Location Path
11241
 * A location step of . is short for self::node(). This is
11242
 * particularly useful in conjunction with //. For example, the
11243
 * location path .//para is short for
11244
 * self::node()/descendant-or-self::node()/child::para
11245
 * and so will select all para descendant elements of the context
11246
 * node.
11247
 * Similarly, a location step of .. is short for parent::node().
11248
 * For example, ../title is short for parent::node()/child::title
11249
 * and so will select the title children of the parent of the context
11250
 * node.
11251
 */
11252
static void
11253
690k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11254
#ifdef LIBXML_XPTR_LOCS_ENABLED
11255
    int rangeto = 0;
11256
    int op2 = -1;
11257
#endif
11258
11259
690k
    SKIP_BLANKS;
11260
690k
    if ((CUR == '.') && (NXT(1) == '.')) {
11261
27
  SKIP(2);
11262
27
  SKIP_BLANKS;
11263
27
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11264
27
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11265
690k
    } else if (CUR == '.') {
11266
26.0k
  NEXT;
11267
26.0k
  SKIP_BLANKS;
11268
664k
    } else {
11269
664k
  xmlChar *name = NULL;
11270
664k
  xmlChar *prefix = NULL;
11271
664k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11272
664k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11273
664k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11274
664k
  int op1;
11275
11276
  /*
11277
   * The modification needed for XPointer change to the production
11278
   */
11279
#ifdef LIBXML_XPTR_LOCS_ENABLED
11280
  if (ctxt->xptr) {
11281
      name = xmlXPathParseNCName(ctxt);
11282
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11283
                op2 = ctxt->comp->last;
11284
    xmlFree(name);
11285
    SKIP_BLANKS;
11286
    if (CUR != '(') {
11287
        XP_ERROR(XPATH_EXPR_ERROR);
11288
    }
11289
    NEXT;
11290
    SKIP_BLANKS;
11291
11292
    xmlXPathCompileExpr(ctxt, 1);
11293
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11294
    CHECK_ERROR;
11295
11296
    SKIP_BLANKS;
11297
    if (CUR != ')') {
11298
        XP_ERROR(XPATH_EXPR_ERROR);
11299
    }
11300
    NEXT;
11301
    rangeto = 1;
11302
    goto eval_predicates;
11303
      }
11304
  }
11305
#endif
11306
664k
  if (CUR == '*') {
11307
80.1k
      axis = AXIS_CHILD;
11308
583k
  } else {
11309
583k
      if (name == NULL)
11310
583k
    name = xmlXPathParseNCName(ctxt);
11311
583k
      if (name != NULL) {
11312
491k
    axis = xmlXPathIsAxisName(name);
11313
491k
    if (axis != 0) {
11314
180
        SKIP_BLANKS;
11315
180
        if ((CUR == ':') && (NXT(1) == ':')) {
11316
180
      SKIP(2);
11317
180
      xmlFree(name);
11318
180
      name = NULL;
11319
180
        } else {
11320
      /* an element name can conflict with an axis one :-\ */
11321
0
      axis = AXIS_CHILD;
11322
0
        }
11323
491k
    } else {
11324
491k
        axis = AXIS_CHILD;
11325
491k
    }
11326
491k
      } else if (CUR == '@') {
11327
32
    NEXT;
11328
32
    axis = AXIS_ATTRIBUTE;
11329
92.2k
      } else {
11330
92.2k
    axis = AXIS_CHILD;
11331
92.2k
      }
11332
583k
  }
11333
11334
664k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11335
92.6k
            xmlFree(name);
11336
92.6k
            return;
11337
92.6k
        }
11338
11339
571k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11340
571k
  if (test == 0)
11341
28
      return;
11342
11343
571k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11344
571k
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11345
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11346
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11347
0
      }
11348
0
  }
11349
#ifdef DEBUG_STEP
11350
  xmlGenericError(xmlGenericErrorContext,
11351
    "Basis : computing new set\n");
11352
#endif
11353
11354
#ifdef DEBUG_STEP
11355
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11356
  if (ctxt->value == NULL)
11357
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11358
  else if (ctxt->value->nodesetval == NULL)
11359
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11360
  else
11361
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11362
#endif
11363
11364
#ifdef LIBXML_XPTR_LOCS_ENABLED
11365
eval_predicates:
11366
#endif
11367
571k
  op1 = ctxt->comp->last;
11368
571k
  ctxt->comp->last = -1;
11369
11370
571k
  SKIP_BLANKS;
11371
571k
  while (CUR == '[') {
11372
137
      xmlXPathCompPredicate(ctxt, 0);
11373
137
  }
11374
11375
#ifdef LIBXML_XPTR_LOCS_ENABLED
11376
  if (rangeto) {
11377
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11378
  } else
11379
#endif
11380
571k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11381
571k
                           test, type, (void *)prefix, (void *)name) == -1) {
11382
0
            xmlFree(prefix);
11383
0
            xmlFree(name);
11384
0
        }
11385
571k
    }
11386
#ifdef DEBUG_STEP
11387
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11388
    if (ctxt->value == NULL)
11389
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11390
    else if (ctxt->value->nodesetval == NULL)
11391
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11392
    else
11393
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11394
    ctxt->value->nodesetval);
11395
#endif
11396
690k
}
11397
11398
/**
11399
 * xmlXPathCompRelativeLocationPath:
11400
 * @ctxt:  the XPath Parser context
11401
 *
11402
 *  [3]   RelativeLocationPath ::=   Step
11403
 *                     | RelativeLocationPath '/' Step
11404
 *                     | AbbreviatedRelativeLocationPath
11405
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11406
 *
11407
 * Compile a relative location path.
11408
 */
11409
static void
11410
xmlXPathCompRelativeLocationPath
11411
532k
(xmlXPathParserContextPtr ctxt) {
11412
532k
    SKIP_BLANKS;
11413
532k
    if ((CUR == '/') && (NXT(1) == '/')) {
11414
3
  SKIP(2);
11415
3
  SKIP_BLANKS;
11416
3
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11417
3
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11418
532k
    } else if (CUR == '/') {
11419
6.56k
      NEXT;
11420
6.56k
  SKIP_BLANKS;
11421
6.56k
    }
11422
532k
    xmlXPathCompStep(ctxt);
11423
532k
    CHECK_ERROR;
11424
531k
    SKIP_BLANKS;
11425
689k
    while (CUR == '/') {
11426
158k
  if ((CUR == '/') && (NXT(1) == '/')) {
11427
92.2k
      SKIP(2);
11428
92.2k
      SKIP_BLANKS;
11429
92.2k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11430
92.2k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11431
92.2k
      xmlXPathCompStep(ctxt);
11432
92.2k
  } else if (CUR == '/') {
11433
65.8k
      NEXT;
11434
65.8k
      SKIP_BLANKS;
11435
65.8k
      xmlXPathCompStep(ctxt);
11436
65.8k
  }
11437
158k
  SKIP_BLANKS;
11438
158k
    }
11439
531k
}
11440
11441
/**
11442
 * xmlXPathCompLocationPath:
11443
 * @ctxt:  the XPath Parser context
11444
 *
11445
 *  [1]   LocationPath ::=   RelativeLocationPath
11446
 *                     | AbsoluteLocationPath
11447
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11448
 *                     | AbbreviatedAbsoluteLocationPath
11449
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11450
 *                           '//' RelativeLocationPath
11451
 *
11452
 * Compile a location path
11453
 *
11454
 * // is short for /descendant-or-self::node()/. For example,
11455
 * //para is short for /descendant-or-self::node()/child::para and
11456
 * so will select any para element in the document (even a para element
11457
 * that is a document element will be selected by //para since the
11458
 * document element node is a child of the root node); div//para is
11459
 * short for div/descendant-or-self::node()/child::para and so will
11460
 * select all para descendants of div children.
11461
 */
11462
static void
11463
532k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11464
532k
    SKIP_BLANKS;
11465
532k
    if (CUR != '/') {
11466
499k
        xmlXPathCompRelativeLocationPath(ctxt);
11467
499k
    } else {
11468
67.1k
  while (CUR == '/') {
11469
33.6k
      if ((CUR == '/') && (NXT(1) == '/')) {
11470
19.6k
    SKIP(2);
11471
19.6k
    SKIP_BLANKS;
11472
19.6k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11473
19.6k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11474
19.6k
    xmlXPathCompRelativeLocationPath(ctxt);
11475
19.6k
      } else if (CUR == '/') {
11476
13.9k
    NEXT;
11477
13.9k
    SKIP_BLANKS;
11478
13.9k
    if ((CUR != 0 ) &&
11479
13.9k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11480
13.8k
         (CUR == '@') || (CUR == '*')))
11481
6.78k
        xmlXPathCompRelativeLocationPath(ctxt);
11482
13.9k
      }
11483
33.6k
      CHECK_ERROR;
11484
33.6k
  }
11485
33.6k
    }
11486
532k
}
11487
11488
/************************************************************************
11489
 *                  *
11490
 *    XPath precompiled expression evaluation     *
11491
 *                  *
11492
 ************************************************************************/
11493
11494
static int
11495
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11496
11497
#ifdef DEBUG_STEP
11498
static void
11499
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11500
        int nbNodes)
11501
{
11502
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11503
    switch (op->value) {
11504
        case AXIS_ANCESTOR:
11505
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11506
            break;
11507
        case AXIS_ANCESTOR_OR_SELF:
11508
            xmlGenericError(xmlGenericErrorContext,
11509
                            "axis 'ancestors-or-self' ");
11510
            break;
11511
        case AXIS_ATTRIBUTE:
11512
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11513
            break;
11514
        case AXIS_CHILD:
11515
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11516
            break;
11517
        case AXIS_DESCENDANT:
11518
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11519
            break;
11520
        case AXIS_DESCENDANT_OR_SELF:
11521
            xmlGenericError(xmlGenericErrorContext,
11522
                            "axis 'descendant-or-self' ");
11523
            break;
11524
        case AXIS_FOLLOWING:
11525
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11526
            break;
11527
        case AXIS_FOLLOWING_SIBLING:
11528
            xmlGenericError(xmlGenericErrorContext,
11529
                            "axis 'following-siblings' ");
11530
            break;
11531
        case AXIS_NAMESPACE:
11532
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11533
            break;
11534
        case AXIS_PARENT:
11535
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11536
            break;
11537
        case AXIS_PRECEDING:
11538
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11539
            break;
11540
        case AXIS_PRECEDING_SIBLING:
11541
            xmlGenericError(xmlGenericErrorContext,
11542
                            "axis 'preceding-sibling' ");
11543
            break;
11544
        case AXIS_SELF:
11545
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11546
            break;
11547
    }
11548
    xmlGenericError(xmlGenericErrorContext,
11549
  " context contains %d nodes\n", nbNodes);
11550
    switch (op->value2) {
11551
        case NODE_TEST_NONE:
11552
            xmlGenericError(xmlGenericErrorContext,
11553
                            "           searching for none !!!\n");
11554
            break;
11555
        case NODE_TEST_TYPE:
11556
            xmlGenericError(xmlGenericErrorContext,
11557
                            "           searching for type %d\n", op->value3);
11558
            break;
11559
        case NODE_TEST_PI:
11560
            xmlGenericError(xmlGenericErrorContext,
11561
                            "           searching for PI !!!\n");
11562
            break;
11563
        case NODE_TEST_ALL:
11564
            xmlGenericError(xmlGenericErrorContext,
11565
                            "           searching for *\n");
11566
            break;
11567
        case NODE_TEST_NS:
11568
            xmlGenericError(xmlGenericErrorContext,
11569
                            "           searching for namespace %s\n",
11570
                            op->value5);
11571
            break;
11572
        case NODE_TEST_NAME:
11573
            xmlGenericError(xmlGenericErrorContext,
11574
                            "           searching for name %s\n", op->value5);
11575
            if (op->value4)
11576
                xmlGenericError(xmlGenericErrorContext,
11577
                                "           with namespace %s\n", op->value4);
11578
            break;
11579
    }
11580
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11581
}
11582
#endif /* DEBUG_STEP */
11583
11584
/**
11585
 * xmlXPathNodeSetFilter:
11586
 * @ctxt:  the XPath Parser context
11587
 * @set: the node set to filter
11588
 * @filterOpIndex: the index of the predicate/filter op
11589
 * @minPos: minimum position in the filtered set (1-based)
11590
 * @maxPos: maximum position in the filtered set (1-based)
11591
 * @hasNsNodes: true if the node set may contain namespace nodes
11592
 *
11593
 * Filter a node set, keeping only nodes for which the predicate expression
11594
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11595
 * filtered result.
11596
 */
11597
static void
11598
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11599
          xmlNodeSetPtr set,
11600
          int filterOpIndex,
11601
                      int minPos, int maxPos,
11602
          int hasNsNodes)
11603
14.0k
{
11604
14.0k
    xmlXPathContextPtr xpctxt;
11605
14.0k
    xmlNodePtr oldnode;
11606
14.0k
    xmlDocPtr olddoc;
11607
14.0k
    xmlXPathStepOpPtr filterOp;
11608
14.0k
    int oldcs, oldpp;
11609
14.0k
    int i, j, pos;
11610
11611
14.0k
    if ((set == NULL) || (set->nodeNr == 0))
11612
0
        return;
11613
11614
    /*
11615
    * Check if the node set contains a sufficient number of nodes for
11616
    * the requested range.
11617
    */
11618
14.0k
    if (set->nodeNr < minPos) {
11619
0
        xmlXPathNodeSetClear(set, hasNsNodes);
11620
0
        return;
11621
0
    }
11622
11623
14.0k
    xpctxt = ctxt->context;
11624
14.0k
    oldnode = xpctxt->node;
11625
14.0k
    olddoc = xpctxt->doc;
11626
14.0k
    oldcs = xpctxt->contextSize;
11627
14.0k
    oldpp = xpctxt->proximityPosition;
11628
14.0k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11629
11630
14.0k
    xpctxt->contextSize = set->nodeNr;
11631
11632
303k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11633
292k
        xmlNodePtr node = set->nodeTab[i];
11634
292k
        int res;
11635
11636
292k
        xpctxt->node = node;
11637
292k
        xpctxt->proximityPosition = i + 1;
11638
11639
        /*
11640
        * Also set the xpath document in case things like
11641
        * key() are evaluated in the predicate.
11642
        *
11643
        * TODO: Get real doc for namespace nodes.
11644
        */
11645
292k
        if ((node->type != XML_NAMESPACE_DECL) &&
11646
292k
            (node->doc != NULL))
11647
292k
            xpctxt->doc = node->doc;
11648
11649
292k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11650
11651
292k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11652
131
            break;
11653
292k
        if (res < 0) {
11654
            /* Shouldn't happen */
11655
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11656
0
            break;
11657
0
        }
11658
11659
292k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11660
154k
            if (i != j) {
11661
684
                set->nodeTab[j] = node;
11662
684
                set->nodeTab[i] = NULL;
11663
684
            }
11664
11665
154k
            j += 1;
11666
154k
        } else {
11667
            /* Remove the entry from the initial node set. */
11668
137k
            set->nodeTab[i] = NULL;
11669
137k
            if (node->type == XML_NAMESPACE_DECL)
11670
238
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11671
137k
        }
11672
11673
292k
        if (res != 0) {
11674
234k
            if (pos == maxPos) {
11675
3.11k
                i += 1;
11676
3.11k
                break;
11677
3.11k
            }
11678
11679
231k
            pos += 1;
11680
231k
        }
11681
292k
    }
11682
11683
    /* Free remaining nodes. */
11684
14.0k
    if (hasNsNodes) {
11685
20.9k
        for (; i < set->nodeNr; i++) {
11686
14.2k
            xmlNodePtr node = set->nodeTab[i];
11687
14.2k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11688
2
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11689
14.2k
        }
11690
6.64k
    }
11691
11692
14.0k
    set->nodeNr = j;
11693
11694
    /* If too many elements were removed, shrink table to preserve memory. */
11695
14.0k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11696
14.0k
        (set->nodeNr < set->nodeMax / 2)) {
11697
745
        xmlNodePtr *tmp;
11698
745
        int nodeMax = set->nodeNr;
11699
11700
745
        if (nodeMax < XML_NODESET_DEFAULT)
11701
734
            nodeMax = XML_NODESET_DEFAULT;
11702
745
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11703
745
                nodeMax * sizeof(xmlNodePtr));
11704
745
        if (tmp == NULL) {
11705
13
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11706
732
        } else {
11707
732
            set->nodeTab = tmp;
11708
732
            set->nodeMax = nodeMax;
11709
732
        }
11710
745
    }
11711
11712
14.0k
    xpctxt->node = oldnode;
11713
14.0k
    xpctxt->doc = olddoc;
11714
14.0k
    xpctxt->contextSize = oldcs;
11715
14.0k
    xpctxt->proximityPosition = oldpp;
11716
14.0k
}
11717
11718
#ifdef LIBXML_XPTR_LOCS_ENABLED
11719
/**
11720
 * xmlXPathLocationSetFilter:
11721
 * @ctxt:  the XPath Parser context
11722
 * @locset: the location set to filter
11723
 * @filterOpIndex: the index of the predicate/filter op
11724
 * @minPos: minimum position in the filtered set (1-based)
11725
 * @maxPos: maximum position in the filtered set (1-based)
11726
 *
11727
 * Filter a location set, keeping only nodes for which the predicate
11728
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11729
 * in the filtered result.
11730
 */
11731
static void
11732
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11733
              xmlLocationSetPtr locset,
11734
              int filterOpIndex,
11735
                          int minPos, int maxPos)
11736
{
11737
    xmlXPathContextPtr xpctxt;
11738
    xmlNodePtr oldnode;
11739
    xmlDocPtr olddoc;
11740
    xmlXPathStepOpPtr filterOp;
11741
    int oldcs, oldpp;
11742
    int i, j, pos;
11743
11744
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11745
        return;
11746
11747
    xpctxt = ctxt->context;
11748
    oldnode = xpctxt->node;
11749
    olddoc = xpctxt->doc;
11750
    oldcs = xpctxt->contextSize;
11751
    oldpp = xpctxt->proximityPosition;
11752
    filterOp = &ctxt->comp->steps[filterOpIndex];
11753
11754
    xpctxt->contextSize = locset->locNr;
11755
11756
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11757
        xmlNodePtr contextNode = locset->locTab[i]->user;
11758
        int res;
11759
11760
        xpctxt->node = contextNode;
11761
        xpctxt->proximityPosition = i + 1;
11762
11763
        /*
11764
        * Also set the xpath document in case things like
11765
        * key() are evaluated in the predicate.
11766
        *
11767
        * TODO: Get real doc for namespace nodes.
11768
        */
11769
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11770
            (contextNode->doc != NULL))
11771
            xpctxt->doc = contextNode->doc;
11772
11773
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11774
11775
        if (ctxt->error != XPATH_EXPRESSION_OK)
11776
            break;
11777
        if (res < 0) {
11778
            /* Shouldn't happen */
11779
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11780
            break;
11781
        }
11782
11783
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11784
            if (i != j) {
11785
                locset->locTab[j] = locset->locTab[i];
11786
                locset->locTab[i] = NULL;
11787
            }
11788
11789
            j += 1;
11790
        } else {
11791
            /* Remove the entry from the initial location set. */
11792
            xmlXPathFreeObject(locset->locTab[i]);
11793
            locset->locTab[i] = NULL;
11794
        }
11795
11796
        if (res != 0) {
11797
            if (pos == maxPos) {
11798
                i += 1;
11799
                break;
11800
            }
11801
11802
            pos += 1;
11803
        }
11804
    }
11805
11806
    /* Free remaining nodes. */
11807
    for (; i < locset->locNr; i++)
11808
        xmlXPathFreeObject(locset->locTab[i]);
11809
11810
    locset->locNr = j;
11811
11812
    /* If too many elements were removed, shrink table to preserve memory. */
11813
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11814
        (locset->locNr < locset->locMax / 2)) {
11815
        xmlXPathObjectPtr *tmp;
11816
        int locMax = locset->locNr;
11817
11818
        if (locMax < XML_NODESET_DEFAULT)
11819
            locMax = XML_NODESET_DEFAULT;
11820
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11821
                locMax * sizeof(xmlXPathObjectPtr));
11822
        if (tmp == NULL) {
11823
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11824
        } else {
11825
            locset->locTab = tmp;
11826
            locset->locMax = locMax;
11827
        }
11828
    }
11829
11830
    xpctxt->node = oldnode;
11831
    xpctxt->doc = olddoc;
11832
    xpctxt->contextSize = oldcs;
11833
    xpctxt->proximityPosition = oldpp;
11834
}
11835
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11836
11837
/**
11838
 * xmlXPathCompOpEvalPredicate:
11839
 * @ctxt:  the XPath Parser context
11840
 * @op: the predicate op
11841
 * @set: the node set to filter
11842
 * @minPos: minimum position in the filtered set (1-based)
11843
 * @maxPos: maximum position in the filtered set (1-based)
11844
 * @hasNsNodes: true if the node set may contain namespace nodes
11845
 *
11846
 * Filter a node set, keeping only nodes for which the sequence of predicate
11847
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11848
 * in the filtered result.
11849
 */
11850
static void
11851
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11852
          xmlXPathStepOpPtr op,
11853
          xmlNodeSetPtr set,
11854
                            int minPos, int maxPos,
11855
          int hasNsNodes)
11856
7.43k
{
11857
7.43k
    if (op->ch1 != -1) {
11858
0
  xmlXPathCompExprPtr comp = ctxt->comp;
11859
  /*
11860
  * Process inner predicates first.
11861
  */
11862
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11863
0
            xmlGenericError(xmlGenericErrorContext,
11864
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11865
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11866
0
  }
11867
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11868
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11869
0
        ctxt->context->depth += 1;
11870
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11871
0
                                    1, set->nodeNr, hasNsNodes);
11872
0
        ctxt->context->depth -= 1;
11873
0
  CHECK_ERROR;
11874
0
    }
11875
11876
7.43k
    if (op->ch2 != -1)
11877
7.43k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11878
7.43k
}
11879
11880
static int
11881
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11882
          xmlXPathStepOpPtr op,
11883
          int *maxPos)
11884
757
{
11885
11886
757
    xmlXPathStepOpPtr exprOp;
11887
11888
    /*
11889
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11890
    */
11891
11892
    /*
11893
    * If not -1, then ch1 will point to:
11894
    * 1) For predicates (XPATH_OP_PREDICATE):
11895
    *    - an inner predicate operator
11896
    * 2) For filters (XPATH_OP_FILTER):
11897
    *    - an inner filter operator OR
11898
    *    - an expression selecting the node set.
11899
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11900
    */
11901
757
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11902
0
  return(0);
11903
11904
757
    if (op->ch2 != -1) {
11905
757
  exprOp = &ctxt->comp->steps[op->ch2];
11906
757
    } else
11907
0
  return(0);
11908
11909
757
    if ((exprOp != NULL) &&
11910
757
  (exprOp->op == XPATH_OP_VALUE) &&
11911
757
  (exprOp->value4 != NULL) &&
11912
757
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11913
241
    {
11914
241
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11915
11916
  /*
11917
  * We have a "[n]" predicate here.
11918
  * TODO: Unfortunately this simplistic test here is not
11919
  * able to detect a position() predicate in compound
11920
  * expressions like "[@attr = 'a" and position() = 1],
11921
  * and even not the usage of position() in
11922
  * "[position() = 1]"; thus - obviously - a position-range,
11923
  * like it "[position() < 5]", is also not detected.
11924
  * Maybe we could rewrite the AST to ease the optimization.
11925
  */
11926
11927
241
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11928
241
      *maxPos = (int) floatval;
11929
241
            if (floatval == (double) *maxPos)
11930
241
                return(1);
11931
241
        }
11932
241
    }
11933
516
    return(0);
11934
757
}
11935
11936
static int
11937
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11938
                           xmlXPathStepOpPtr op,
11939
         xmlNodePtr * first, xmlNodePtr * last,
11940
         int toBool)
11941
93.4k
{
11942
11943
93.4k
#define XP_TEST_HIT \
11944
3.05M
    if (hasAxisRange != 0) { \
11945
14.7k
  if (++pos == maxPos) { \
11946
0
      if (addNode(seq, cur) < 0) \
11947
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11948
0
      goto axis_range_end; } \
11949
3.03M
    } else { \
11950
3.03M
  if (addNode(seq, cur) < 0) \
11951
3.03M
      ctxt->error = XPATH_MEMORY_ERROR; \
11952
3.03M
  if (breakOnFirstHit) goto first_hit; }
11953
11954
93.4k
#define XP_TEST_HIT_NS \
11955
109k
    if (hasAxisRange != 0) { \
11956
0
  if (++pos == maxPos) { \
11957
0
      hasNsNodes = 1; \
11958
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11959
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11960
0
  goto axis_range_end; } \
11961
109k
    } else { \
11962
109k
  hasNsNodes = 1; \
11963
109k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964
109k
      ctxt->error = XPATH_MEMORY_ERROR; \
11965
109k
  if (breakOnFirstHit) goto first_hit; }
11966
11967
93.4k
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11968
93.4k
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11969
93.4k
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11970
93.4k
    const xmlChar *prefix = op->value4;
11971
93.4k
    const xmlChar *name = op->value5;
11972
93.4k
    const xmlChar *URI = NULL;
11973
11974
#ifdef DEBUG_STEP
11975
    int nbMatches = 0, prevMatches = 0;
11976
#endif
11977
93.4k
    int total = 0, hasNsNodes = 0;
11978
    /* The popped object holding the context nodes */
11979
93.4k
    xmlXPathObjectPtr obj;
11980
    /* The set of context nodes for the node tests */
11981
93.4k
    xmlNodeSetPtr contextSeq;
11982
93.4k
    int contextIdx;
11983
93.4k
    xmlNodePtr contextNode;
11984
    /* The final resulting node set wrt to all context nodes */
11985
93.4k
    xmlNodeSetPtr outSeq;
11986
    /*
11987
    * The temporary resulting node set wrt 1 context node.
11988
    * Used to feed predicate evaluation.
11989
    */
11990
93.4k
    xmlNodeSetPtr seq;
11991
93.4k
    xmlNodePtr cur;
11992
    /* First predicate operator */
11993
93.4k
    xmlXPathStepOpPtr predOp;
11994
93.4k
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11995
93.4k
    int hasPredicateRange, hasAxisRange, pos;
11996
93.4k
    int breakOnFirstHit;
11997
11998
93.4k
    xmlXPathTraversalFunction next = NULL;
11999
93.4k
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12000
93.4k
    xmlXPathNodeSetMergeFunction mergeAndClear;
12001
93.4k
    xmlNodePtr oldContextNode;
12002
93.4k
    xmlXPathContextPtr xpctxt = ctxt->context;
12003
12004
12005
93.4k
    CHECK_TYPE0(XPATH_NODESET);
12006
93.4k
    obj = valuePop(ctxt);
12007
    /*
12008
    * Setup namespaces.
12009
    */
12010
93.4k
    if (prefix != NULL) {
12011
26
        URI = xmlXPathNsLookup(xpctxt, prefix);
12012
26
        if (URI == NULL) {
12013
17
      xmlXPathReleaseObject(xpctxt, obj);
12014
17
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12015
0
  }
12016
26
    }
12017
    /*
12018
    * Setup axis.
12019
    *
12020
    * MAYBE FUTURE TODO: merging optimizations:
12021
    * - If the nodes to be traversed wrt to the initial nodes and
12022
    *   the current axis cannot overlap, then we could avoid searching
12023
    *   for duplicates during the merge.
12024
    *   But the question is how/when to evaluate if they cannot overlap.
12025
    *   Example: if we know that for two initial nodes, the one is
12026
    *   not in the ancestor-or-self axis of the other, then we could safely
12027
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12028
    *   the descendant-or-self axis.
12029
    */
12030
93.4k
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12031
93.4k
    switch (axis) {
12032
0
        case AXIS_ANCESTOR:
12033
0
            first = NULL;
12034
0
            next = xmlXPathNextAncestor;
12035
0
            break;
12036
0
        case AXIS_ANCESTOR_OR_SELF:
12037
0
            first = NULL;
12038
0
            next = xmlXPathNextAncestorOrSelf;
12039
0
            break;
12040
5
        case AXIS_ATTRIBUTE:
12041
5
            first = NULL;
12042
5
      last = NULL;
12043
5
            next = xmlXPathNextAttribute;
12044
5
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12045
5
            break;
12046
74.9k
        case AXIS_CHILD:
12047
74.9k
      last = NULL;
12048
74.9k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12049
74.9k
    (type == NODE_TYPE_NODE))
12050
74.6k
      {
12051
    /*
12052
    * Optimization if an element node type is 'element'.
12053
    */
12054
74.6k
    next = xmlXPathNextChildElement;
12055
74.6k
      } else
12056
253
    next = xmlXPathNextChild;
12057
74.9k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058
74.9k
            break;
12059
10.6k
        case AXIS_DESCENDANT:
12060
10.6k
      last = NULL;
12061
10.6k
            next = xmlXPathNextDescendant;
12062
10.6k
            break;
12063
7.61k
        case AXIS_DESCENDANT_OR_SELF:
12064
7.61k
      last = NULL;
12065
7.61k
            next = xmlXPathNextDescendantOrSelf;
12066
7.61k
            break;
12067
0
        case AXIS_FOLLOWING:
12068
0
      last = NULL;
12069
0
            next = xmlXPathNextFollowing;
12070
0
            break;
12071
0
        case AXIS_FOLLOWING_SIBLING:
12072
0
      last = NULL;
12073
0
            next = xmlXPathNextFollowingSibling;
12074
0
            break;
12075
294
        case AXIS_NAMESPACE:
12076
294
            first = NULL;
12077
294
      last = NULL;
12078
294
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12079
294
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080
294
            break;
12081
17
        case AXIS_PARENT:
12082
17
            first = NULL;
12083
17
            next = xmlXPathNextParent;
12084
17
            break;
12085
12
        case AXIS_PRECEDING:
12086
12
            first = NULL;
12087
12
            next = xmlXPathNextPrecedingInternal;
12088
12
            break;
12089
4
        case AXIS_PRECEDING_SIBLING:
12090
4
            first = NULL;
12091
4
            next = xmlXPathNextPrecedingSibling;
12092
4
            break;
12093
0
        case AXIS_SELF:
12094
0
            first = NULL;
12095
0
      last = NULL;
12096
0
            next = xmlXPathNextSelf;
12097
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12098
0
            break;
12099
93.4k
    }
12100
12101
#ifdef DEBUG_STEP
12102
    xmlXPathDebugDumpStepAxis(op,
12103
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12104
#endif
12105
12106
93.4k
    if (next == NULL) {
12107
0
  xmlXPathReleaseObject(xpctxt, obj);
12108
0
        return(0);
12109
0
    }
12110
93.4k
    contextSeq = obj->nodesetval;
12111
93.4k
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12112
4.63k
  xmlXPathReleaseObject(xpctxt, obj);
12113
4.63k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12114
4.63k
        return(0);
12115
4.63k
    }
12116
    /*
12117
    * Predicate optimization ---------------------------------------------
12118
    * If this step has a last predicate, which contains a position(),
12119
    * then we'll optimize (although not exactly "position()", but only
12120
    * the  short-hand form, i.e., "[n]".
12121
    *
12122
    * Example - expression "/foo[parent::bar][1]":
12123
    *
12124
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12125
    *   ROOT                               -- op->ch1
12126
    *   PREDICATE                          -- op->ch2 (predOp)
12127
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12128
    *       SORT
12129
    *         COLLECT  'parent' 'name' 'node' bar
12130
    *           NODE
12131
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12132
    *
12133
    */
12134
88.8k
    maxPos = 0;
12135
88.8k
    predOp = NULL;
12136
88.8k
    hasPredicateRange = 0;
12137
88.8k
    hasAxisRange = 0;
12138
88.8k
    if (op->ch2 != -1) {
12139
  /*
12140
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12141
  */
12142
757
  predOp = &ctxt->comp->steps[op->ch2];
12143
757
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12144
241
      if (predOp->ch1 != -1) {
12145
    /*
12146
    * Use the next inner predicate operator.
12147
    */
12148
239
    predOp = &ctxt->comp->steps[predOp->ch1];
12149
239
    hasPredicateRange = 1;
12150
239
      } else {
12151
    /*
12152
    * There's no other predicate than the [n] predicate.
12153
    */
12154
2
    predOp = NULL;
12155
2
    hasAxisRange = 1;
12156
2
      }
12157
241
  }
12158
757
    }
12159
88.8k
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12160
    /*
12161
    * Axis traversal -----------------------------------------------------
12162
    */
12163
    /*
12164
     * 2.3 Node Tests
12165
     *  - For the attribute axis, the principal node type is attribute.
12166
     *  - For the namespace axis, the principal node type is namespace.
12167
     *  - For other axes, the principal node type is element.
12168
     *
12169
     * A node test * is true for any node of the
12170
     * principal node type. For example, child::* will
12171
     * select all element children of the context node
12172
     */
12173
88.8k
    oldContextNode = xpctxt->node;
12174
88.8k
    addNode = xmlXPathNodeSetAddUnique;
12175
88.8k
    outSeq = NULL;
12176
88.8k
    seq = NULL;
12177
88.8k
    contextNode = NULL;
12178
88.8k
    contextIdx = 0;
12179
12180
12181
507k
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12182
507k
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12183
418k
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12184
12185
418k
  if (seq == NULL) {
12186
89.3k
      seq = xmlXPathNodeSetCreate(NULL);
12187
89.3k
      if (seq == NULL) {
12188
                /* TODO: Propagate memory error. */
12189
63
    total = 0;
12190
63
    goto error;
12191
63
      }
12192
89.3k
  }
12193
  /*
12194
  * Traverse the axis and test the nodes.
12195
  */
12196
418k
  pos = 0;
12197
418k
  cur = NULL;
12198
418k
  hasNsNodes = 0;
12199
5.17M
        do {
12200
5.17M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12201
7
                goto error;
12202
12203
5.17M
            cur = next(ctxt, cur);
12204
5.17M
            if (cur == NULL)
12205
363k
                break;
12206
12207
      /*
12208
      * QUESTION TODO: What does the "first" and "last" stuff do?
12209
      */
12210
4.80M
            if ((first != NULL) && (*first != NULL)) {
12211
55.2k
    if (*first == cur)
12212
2
        break;
12213
55.2k
    if (((total % 256) == 0) &&
12214
55.2k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215
55.2k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12216
#else
12217
        (xmlXPathCmpNodes(*first, cur) >= 0))
12218
#endif
12219
55.2k
    {
12220
55.2k
        break;
12221
55.2k
    }
12222
55.2k
      }
12223
4.75M
      if ((last != NULL) && (*last != NULL)) {
12224
0
    if (*last == cur)
12225
0
        break;
12226
0
    if (((total % 256) == 0) &&
12227
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12228
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12229
#else
12230
        (xmlXPathCmpNodes(cur, *last) >= 0))
12231
#endif
12232
0
    {
12233
0
        break;
12234
0
    }
12235
0
      }
12236
12237
4.75M
            total++;
12238
12239
#ifdef DEBUG_STEP
12240
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12241
#endif
12242
12243
4.75M
      switch (test) {
12244
0
                case NODE_TEST_NONE:
12245
0
        total = 0;
12246
0
                    STRANGE
12247
0
        goto error;
12248
2.34M
                case NODE_TEST_TYPE:
12249
2.34M
        if (type == NODE_TYPE_NODE) {
12250
872k
      switch (cur->type) {
12251
7.45k
          case XML_DOCUMENT_NODE:
12252
7.45k
          case XML_HTML_DOCUMENT_NODE:
12253
489k
          case XML_ELEMENT_NODE:
12254
489k
          case XML_ATTRIBUTE_NODE:
12255
492k
          case XML_PI_NODE:
12256
493k
          case XML_COMMENT_NODE:
12257
493k
          case XML_CDATA_SECTION_NODE:
12258
854k
          case XML_TEXT_NODE:
12259
854k
        XP_TEST_HIT
12260
854k
        break;
12261
854k
          case XML_NAMESPACE_DECL: {
12262
17.3k
        if (axis == AXIS_NAMESPACE) {
12263
0
            XP_TEST_HIT_NS
12264
17.3k
        } else {
12265
17.3k
                              hasNsNodes = 1;
12266
17.3k
            XP_TEST_HIT
12267
17.3k
        }
12268
17.3k
        break;
12269
17.3k
                            }
12270
17.3k
          default:
12271
14
        break;
12272
872k
      }
12273
1.47M
        } else if (cur->type == (xmlElementType) type) {
12274
5.98k
      if (cur->type == XML_NAMESPACE_DECL)
12275
0
          XP_TEST_HIT_NS
12276
5.98k
      else
12277
5.98k
          XP_TEST_HIT
12278
1.46M
        } else if ((type == NODE_TYPE_TEXT) &&
12279
1.46M
       (cur->type == XML_CDATA_SECTION_NODE))
12280
0
        {
12281
0
      XP_TEST_HIT
12282
0
        }
12283
2.34M
        break;
12284
2.34M
                case NODE_TEST_PI:
12285
0
                    if ((cur->type == XML_PI_NODE) &&
12286
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12287
0
        {
12288
0
      XP_TEST_HIT
12289
0
                    }
12290
0
                    break;
12291
2.37M
                case NODE_TEST_ALL:
12292
2.37M
                    if (axis == AXIS_ATTRIBUTE) {
12293
179
                        if (cur->type == XML_ATTRIBUTE_NODE)
12294
179
      {
12295
179
                            if (prefix == NULL)
12296
179
          {
12297
179
        XP_TEST_HIT
12298
179
                            } else if ((cur->ns != NULL) &&
12299
0
        (xmlStrEqual(URI, cur->ns->href)))
12300
0
          {
12301
0
        XP_TEST_HIT
12302
0
                            }
12303
179
                        }
12304
2.37M
                    } else if (axis == AXIS_NAMESPACE) {
12305
109k
                        if (cur->type == XML_NAMESPACE_DECL)
12306
109k
      {
12307
109k
          XP_TEST_HIT_NS
12308
109k
                        }
12309
2.26M
                    } else {
12310
2.26M
                        if (cur->type == XML_ELEMENT_NODE) {
12311
2.17M
                            if (prefix == NULL)
12312
2.17M
          {
12313
2.17M
        XP_TEST_HIT
12314
12315
2.17M
                            } else if ((cur->ns != NULL) &&
12316
0
        (xmlStrEqual(URI, cur->ns->href)))
12317
0
          {
12318
0
        XP_TEST_HIT
12319
0
                            }
12320
2.17M
                        }
12321
2.26M
                    }
12322
2.37M
                    break;
12323
2.37M
                case NODE_TEST_NS:{
12324
0
                        TODO;
12325
0
                        break;
12326
2.37M
                    }
12327
39.7k
                case NODE_TEST_NAME:
12328
39.7k
                    if (axis == AXIS_ATTRIBUTE) {
12329
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
12330
0
          break;
12331
39.7k
        } else if (axis == AXIS_NAMESPACE) {
12332
0
                        if (cur->type != XML_NAMESPACE_DECL)
12333
0
          break;
12334
39.7k
        } else {
12335
39.7k
            if (cur->type != XML_ELEMENT_NODE)
12336
0
          break;
12337
39.7k
        }
12338
39.7k
                    switch (cur->type) {
12339
39.7k
                        case XML_ELEMENT_NODE:
12340
39.7k
                            if (xmlStrEqual(name, cur->name)) {
12341
196
                                if (prefix == NULL) {
12342
196
                                    if (cur->ns == NULL)
12343
196
            {
12344
196
          XP_TEST_HIT
12345
196
                                    }
12346
196
                                } else {
12347
0
                                    if ((cur->ns != NULL) &&
12348
0
                                        (xmlStrEqual(URI, cur->ns->href)))
12349
0
            {
12350
0
          XP_TEST_HIT
12351
0
                                    }
12352
0
                                }
12353
196
                            }
12354
39.7k
                            break;
12355
39.7k
                        case XML_ATTRIBUTE_NODE:{
12356
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12357
12358
0
                                if (xmlStrEqual(name, attr->name)) {
12359
0
                                    if (prefix == NULL) {
12360
0
                                        if ((attr->ns == NULL) ||
12361
0
                                            (attr->ns->prefix == NULL))
12362
0
          {
12363
0
              XP_TEST_HIT
12364
0
                                        }
12365
0
                                    } else {
12366
0
                                        if ((attr->ns != NULL) &&
12367
0
                                            (xmlStrEqual(URI,
12368
0
                attr->ns->href)))
12369
0
          {
12370
0
              XP_TEST_HIT
12371
0
                                        }
12372
0
                                    }
12373
0
                                }
12374
0
                                break;
12375
0
                            }
12376
0
                        case XML_NAMESPACE_DECL:
12377
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12378
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12379
12380
0
                                if ((ns->prefix != NULL) && (name != NULL)
12381
0
                                    && (xmlStrEqual(ns->prefix, name)))
12382
0
        {
12383
0
            XP_TEST_HIT_NS
12384
0
                                }
12385
0
                            }
12386
0
                            break;
12387
0
                        default:
12388
0
                            break;
12389
39.7k
                    }
12390
39.7k
                    break;
12391
4.75M
      } /* switch(test) */
12392
4.75M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12393
12394
418k
  goto apply_predicates;
12395
12396
418k
axis_range_end: /* ----------------------------------------------------- */
12397
  /*
12398
  * We have a "/foo[n]", and position() = n was reached.
12399
  * Note that we can have as well "/foo/::parent::foo[1]", so
12400
  * a duplicate-aware merge is still needed.
12401
  * Merge with the result.
12402
  */
12403
0
  if (outSeq == NULL) {
12404
0
      outSeq = seq;
12405
0
      seq = NULL;
12406
0
  } else
12407
            /* TODO: Check memory error. */
12408
0
      outSeq = mergeAndClear(outSeq, seq);
12409
  /*
12410
  * Break if only a true/false result was requested.
12411
  */
12412
0
  if (toBool)
12413
0
      break;
12414
0
  continue;
12415
12416
0
first_hit: /* ---------------------------------------------------------- */
12417
  /*
12418
  * Break if only a true/false result was requested and
12419
  * no predicates existed and a node test succeeded.
12420
  */
12421
0
  if (outSeq == NULL) {
12422
0
      outSeq = seq;
12423
0
      seq = NULL;
12424
0
  } else
12425
            /* TODO: Check memory error. */
12426
0
      outSeq = mergeAndClear(outSeq, seq);
12427
0
  break;
12428
12429
#ifdef DEBUG_STEP
12430
  if (seq != NULL)
12431
      nbMatches += seq->nodeNr;
12432
#endif
12433
12434
418k
apply_predicates: /* --------------------------------------------------- */
12435
418k
        if (ctxt->error != XPATH_EXPRESSION_OK)
12436
2
      goto error;
12437
12438
        /*
12439
  * Apply predicates.
12440
  */
12441
418k
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12442
      /*
12443
      * E.g. when we have a "/foo[some expression][n]".
12444
      */
12445
      /*
12446
      * QUESTION TODO: The old predicate evaluation took into
12447
      *  account location-sets.
12448
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12449
      *  Do we expect such a set here?
12450
      *  All what I learned now from the evaluation semantics
12451
      *  does not indicate that a location-set will be processed
12452
      *  here, so this looks OK.
12453
      */
12454
      /*
12455
      * Iterate over all predicates, starting with the outermost
12456
      * predicate.
12457
      * TODO: Problem: we cannot execute the inner predicates first
12458
      *  since we cannot go back *up* the operator tree!
12459
      *  Options we have:
12460
      *  1) Use of recursive functions (like is it currently done
12461
      *     via xmlXPathCompOpEval())
12462
      *  2) Add a predicate evaluation information stack to the
12463
      *     context struct
12464
      *  3) Change the way the operators are linked; we need a
12465
      *     "parent" field on xmlXPathStepOp
12466
      *
12467
      * For the moment, I'll try to solve this with a recursive
12468
      * function: xmlXPathCompOpEvalPredicate().
12469
      */
12470
7.43k
      if (hasPredicateRange != 0)
12471
659
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12472
659
              hasNsNodes);
12473
6.77k
      else
12474
6.77k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12475
6.77k
              hasNsNodes);
12476
12477
7.43k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12478
31
    total = 0;
12479
31
    goto error;
12480
31
      }
12481
7.43k
        }
12482
12483
418k
        if (seq->nodeNr > 0) {
12484
      /*
12485
      * Add to result set.
12486
      */
12487
80.1k
      if (outSeq == NULL) {
12488
37.9k
    outSeq = seq;
12489
37.9k
    seq = NULL;
12490
42.2k
      } else {
12491
                /* TODO: Check memory error. */
12492
42.2k
    outSeq = mergeAndClear(outSeq, seq);
12493
42.2k
      }
12494
12495
80.1k
            if (toBool)
12496
0
                break;
12497
80.1k
  }
12498
418k
    }
12499
12500
88.8k
error:
12501
88.8k
    if ((obj->boolval) && (obj->user != NULL)) {
12502
  /*
12503
  * QUESTION TODO: What does this do and why?
12504
  * TODO: Do we have to do this also for the "error"
12505
  * cleanup further down?
12506
  */
12507
0
  ctxt->value->boolval = 1;
12508
0
  ctxt->value->user = obj->user;
12509
0
  obj->user = NULL;
12510
0
  obj->boolval = 0;
12511
0
    }
12512
88.8k
    xmlXPathReleaseObject(xpctxt, obj);
12513
12514
    /*
12515
    * Ensure we return at least an empty set.
12516
    */
12517
88.8k
    if (outSeq == NULL) {
12518
50.9k
  if ((seq != NULL) && (seq->nodeNr == 0))
12519
50.8k
      outSeq = seq;
12520
72
  else
12521
            /* TODO: Check memory error. */
12522
72
      outSeq = xmlXPathNodeSetCreate(NULL);
12523
50.9k
    }
12524
88.8k
    if ((seq != NULL) && (seq != outSeq)) {
12525
518
   xmlXPathFreeNodeSet(seq);
12526
518
    }
12527
    /*
12528
    * Hand over the result. Better to push the set also in
12529
    * case of errors.
12530
    */
12531
88.8k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12532
    /*
12533
    * Reset the context node.
12534
    */
12535
88.8k
    xpctxt->node = oldContextNode;
12536
    /*
12537
    * When traversing the namespace axis in "toBool" mode, it's
12538
    * possible that tmpNsList wasn't freed.
12539
    */
12540
88.8k
    if (xpctxt->tmpNsList != NULL) {
12541
1
        xmlFree(xpctxt->tmpNsList);
12542
1
        xpctxt->tmpNsList = NULL;
12543
1
    }
12544
12545
#ifdef DEBUG_STEP
12546
    xmlGenericError(xmlGenericErrorContext,
12547
  "\nExamined %d nodes, found %d nodes at that step\n",
12548
  total, nbMatches);
12549
#endif
12550
12551
88.8k
    return(total);
12552
88.8k
}
12553
12554
static int
12555
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12556
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12557
12558
/**
12559
 * xmlXPathCompOpEvalFirst:
12560
 * @ctxt:  the XPath parser context with the compiled expression
12561
 * @op:  an XPath compiled operation
12562
 * @first:  the first elem found so far
12563
 *
12564
 * Evaluate the Precompiled XPath operation searching only the first
12565
 * element in document order
12566
 *
12567
 * Returns the number of examined objects.
12568
 */
12569
static int
12570
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12571
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12572
2.29k
{
12573
2.29k
    int total = 0, cur;
12574
2.29k
    xmlXPathCompExprPtr comp;
12575
2.29k
    xmlXPathObjectPtr arg1, arg2;
12576
12577
2.29k
    CHECK_ERROR0;
12578
2.29k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12579
0
        return(0);
12580
2.29k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12581
2.29k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12582
2.29k
    ctxt->context->depth += 1;
12583
2.29k
    comp = ctxt->comp;
12584
2.29k
    switch (op->op) {
12585
0
        case XPATH_OP_END:
12586
0
            break;
12587
764
        case XPATH_OP_UNION:
12588
764
            total =
12589
764
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12590
764
                                        first);
12591
764
      CHECK_ERROR0;
12592
764
            if ((ctxt->value != NULL)
12593
764
                && (ctxt->value->type == XPATH_NODESET)
12594
764
                && (ctxt->value->nodesetval != NULL)
12595
764
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12596
                /*
12597
                 * limit tree traversing to first node in the result
12598
                 */
12599
    /*
12600
    * OPTIMIZE TODO: This implicitly sorts
12601
    *  the result, even if not needed. E.g. if the argument
12602
    *  of the count() function, no sorting is needed.
12603
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12604
    *  already sorted?
12605
    */
12606
142
    if (ctxt->value->nodesetval->nodeNr > 1)
12607
4
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12608
142
                *first = ctxt->value->nodesetval->nodeTab[0];
12609
142
            }
12610
764
            cur =
12611
764
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12612
764
                                        first);
12613
764
      CHECK_ERROR0;
12614
12615
756
            arg2 = valuePop(ctxt);
12616
756
            arg1 = valuePop(ctxt);
12617
756
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12618
756
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12619
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12620
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12621
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12622
0
            }
12623
756
            if ((ctxt->context->opLimit != 0) &&
12624
756
                (((arg1->nodesetval != NULL) &&
12625
756
                  (xmlXPathCheckOpLimit(ctxt,
12626
516
                                        arg1->nodesetval->nodeNr) < 0)) ||
12627
756
                 ((arg2->nodesetval != NULL) &&
12628
756
                  (xmlXPathCheckOpLimit(ctxt,
12629
756
                                        arg2->nodesetval->nodeNr) < 0)))) {
12630
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12631
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12632
0
                break;
12633
0
            }
12634
12635
            /* TODO: Check memory error. */
12636
756
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12637
756
                                                    arg2->nodesetval);
12638
756
            valuePush(ctxt, arg1);
12639
756
      xmlXPathReleaseObject(ctxt->context, arg2);
12640
            /* optimizer */
12641
756
      if (total > cur)
12642
4
    xmlXPathCompSwap(op);
12643
756
            total += cur;
12644
756
            break;
12645
0
        case XPATH_OP_ROOT:
12646
0
            xmlXPathRoot(ctxt);
12647
0
            break;
12648
140
        case XPATH_OP_NODE:
12649
140
            if (op->ch1 != -1)
12650
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12651
140
      CHECK_ERROR0;
12652
140
            if (op->ch2 != -1)
12653
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12654
140
      CHECK_ERROR0;
12655
140
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12656
140
    ctxt->context->node));
12657
140
            break;
12658
1.00k
        case XPATH_OP_COLLECT:{
12659
1.00k
                if (op->ch1 == -1)
12660
0
                    break;
12661
12662
1.00k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12663
1.00k
    CHECK_ERROR0;
12664
12665
1.00k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12666
1.00k
                break;
12667
1.00k
            }
12668
0
        case XPATH_OP_VALUE:
12669
0
            valuePush(ctxt,
12670
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12671
0
      (xmlXPathObjectPtr) op->value4));
12672
0
            break;
12673
382
        case XPATH_OP_SORT:
12674
382
            if (op->ch1 != -1)
12675
382
                total +=
12676
382
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12677
382
                                            first);
12678
382
      CHECK_ERROR0;
12679
378
            if ((ctxt->value != NULL)
12680
378
                && (ctxt->value->type == XPATH_NODESET)
12681
378
                && (ctxt->value->nodesetval != NULL)
12682
378
    && (ctxt->value->nodesetval->nodeNr > 1))
12683
242
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12684
378
            break;
12685
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12686
0
  case XPATH_OP_FILTER:
12687
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12688
0
            break;
12689
0
#endif
12690
0
        default:
12691
0
            total += xmlXPathCompOpEval(ctxt, op);
12692
0
            break;
12693
2.29k
    }
12694
12695
2.27k
    ctxt->context->depth -= 1;
12696
2.27k
    return(total);
12697
2.29k
}
12698
12699
/**
12700
 * xmlXPathCompOpEvalLast:
12701
 * @ctxt:  the XPath parser context with the compiled expression
12702
 * @op:  an XPath compiled operation
12703
 * @last:  the last elem found so far
12704
 *
12705
 * Evaluate the Precompiled XPath operation searching only the last
12706
 * element in document order
12707
 *
12708
 * Returns the number of nodes traversed
12709
 */
12710
static int
12711
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12712
                       xmlNodePtr * last)
12713
24.6k
{
12714
24.6k
    int total = 0, cur;
12715
24.6k
    xmlXPathCompExprPtr comp;
12716
24.6k
    xmlXPathObjectPtr arg1, arg2;
12717
12718
24.6k
    CHECK_ERROR0;
12719
24.6k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12720
0
        return(0);
12721
24.6k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12722
24.6k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12723
24.6k
    ctxt->context->depth += 1;
12724
24.6k
    comp = ctxt->comp;
12725
24.6k
    switch (op->op) {
12726
0
        case XPATH_OP_END:
12727
0
            break;
12728
6.16k
        case XPATH_OP_UNION:
12729
6.16k
            total =
12730
6.16k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12731
6.16k
      CHECK_ERROR0;
12732
6.16k
            if ((ctxt->value != NULL)
12733
6.16k
                && (ctxt->value->type == XPATH_NODESET)
12734
6.16k
                && (ctxt->value->nodesetval != NULL)
12735
6.16k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12736
                /*
12737
                 * limit tree traversing to first node in the result
12738
                 */
12739
286
    if (ctxt->value->nodesetval->nodeNr > 1)
12740
270
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741
286
                *last =
12742
286
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12743
286
                                                     nodesetval->nodeNr -
12744
286
                                                     1];
12745
286
            }
12746
6.16k
            cur =
12747
6.16k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12748
6.16k
      CHECK_ERROR0;
12749
6.16k
            if ((ctxt->value != NULL)
12750
6.16k
                && (ctxt->value->type == XPATH_NODESET)
12751
6.16k
                && (ctxt->value->nodesetval != NULL)
12752
6.16k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12753
460
            }
12754
12755
6.16k
            arg2 = valuePop(ctxt);
12756
6.16k
            arg1 = valuePop(ctxt);
12757
6.16k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12758
6.16k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12759
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12760
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12761
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12762
0
            }
12763
6.16k
            if ((ctxt->context->opLimit != 0) &&
12764
6.16k
                (((arg1->nodesetval != NULL) &&
12765
6.16k
                  (xmlXPathCheckOpLimit(ctxt,
12766
6.13k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12767
6.16k
                 ((arg2->nodesetval != NULL) &&
12768
6.16k
                  (xmlXPathCheckOpLimit(ctxt,
12769
6.13k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12770
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12771
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12772
0
                break;
12773
0
            }
12774
12775
            /* TODO: Check memory error. */
12776
6.16k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12777
6.16k
                                                    arg2->nodesetval);
12778
6.16k
            valuePush(ctxt, arg1);
12779
6.16k
      xmlXPathReleaseObject(ctxt->context, arg2);
12780
            /* optimizer */
12781
6.16k
      if (total > cur)
12782
541
    xmlXPathCompSwap(op);
12783
6.16k
            total += cur;
12784
6.16k
            break;
12785
0
        case XPATH_OP_ROOT:
12786
0
            xmlXPathRoot(ctxt);
12787
0
            break;
12788
0
        case XPATH_OP_NODE:
12789
0
            if (op->ch1 != -1)
12790
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12791
0
      CHECK_ERROR0;
12792
0
            if (op->ch2 != -1)
12793
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12794
0
      CHECK_ERROR0;
12795
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12796
0
    ctxt->context->node));
12797
0
            break;
12798
12.3k
        case XPATH_OP_COLLECT:{
12799
12.3k
                if (op->ch1 == -1)
12800
0
                    break;
12801
12802
12.3k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12803
12.3k
    CHECK_ERROR0;
12804
12805
12.3k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12806
12.3k
                break;
12807
12.3k
            }
12808
0
        case XPATH_OP_VALUE:
12809
0
            valuePush(ctxt,
12810
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12811
0
      (xmlXPathObjectPtr) op->value4));
12812
0
            break;
12813
6.16k
        case XPATH_OP_SORT:
12814
6.16k
            if (op->ch1 != -1)
12815
6.16k
                total +=
12816
6.16k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12817
6.16k
                                           last);
12818
6.16k
      CHECK_ERROR0;
12819
6.16k
            if ((ctxt->value != NULL)
12820
6.16k
                && (ctxt->value->type == XPATH_NODESET)
12821
6.16k
                && (ctxt->value->nodesetval != NULL)
12822
6.16k
    && (ctxt->value->nodesetval->nodeNr > 1))
12823
560
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12824
6.16k
            break;
12825
0
        default:
12826
0
            total += xmlXPathCompOpEval(ctxt, op);
12827
0
            break;
12828
24.6k
    }
12829
12830
24.6k
    ctxt->context->depth -= 1;
12831
24.6k
    return (total);
12832
24.6k
}
12833
12834
#ifdef XP_OPTIMIZED_FILTER_FIRST
12835
static int
12836
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12837
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12838
0
{
12839
0
    int total = 0;
12840
0
    xmlXPathCompExprPtr comp;
12841
0
    xmlXPathObjectPtr obj;
12842
0
    xmlNodeSetPtr set;
12843
12844
0
    CHECK_ERROR0;
12845
0
    comp = ctxt->comp;
12846
    /*
12847
    * Optimization for ()[last()] selection i.e. the last elem
12848
    */
12849
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12850
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12851
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12852
0
  int f = comp->steps[op->ch2].ch1;
12853
12854
0
  if ((f != -1) &&
12855
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12856
0
      (comp->steps[f].value5 == NULL) &&
12857
0
      (comp->steps[f].value == 0) &&
12858
0
      (comp->steps[f].value4 != NULL) &&
12859
0
      (xmlStrEqual
12860
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
12861
0
      xmlNodePtr last = NULL;
12862
12863
0
      total +=
12864
0
    xmlXPathCompOpEvalLast(ctxt,
12865
0
        &comp->steps[op->ch1],
12866
0
        &last);
12867
0
      CHECK_ERROR0;
12868
      /*
12869
      * The nodeset should be in document order,
12870
      * Keep only the last value
12871
      */
12872
0
      if ((ctxt->value != NULL) &&
12873
0
    (ctxt->value->type == XPATH_NODESET) &&
12874
0
    (ctxt->value->nodesetval != NULL) &&
12875
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12876
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12877
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12878
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12879
0
      }
12880
0
      return (total);
12881
0
  }
12882
0
    }
12883
12884
0
    if (op->ch1 != -1)
12885
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12886
0
    CHECK_ERROR0;
12887
0
    if (op->ch2 == -1)
12888
0
  return (total);
12889
0
    if (ctxt->value == NULL)
12890
0
  return (total);
12891
12892
#ifdef LIBXML_XPTR_LOCS_ENABLED
12893
    /*
12894
    * Hum are we filtering the result of an XPointer expression
12895
    */
12896
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12897
        xmlLocationSetPtr locset = ctxt->value->user;
12898
12899
        if (locset != NULL) {
12900
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12901
            if (locset->locNr > 0)
12902
                *first = (xmlNodePtr) locset->locTab[0]->user;
12903
        }
12904
12905
  return (total);
12906
    }
12907
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12908
12909
    /*
12910
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12911
     * the stack. We have to temporarily remove the nodeset object from the
12912
     * stack to avoid freeing it prematurely.
12913
     */
12914
0
    CHECK_TYPE0(XPATH_NODESET);
12915
0
    obj = valuePop(ctxt);
12916
0
    set = obj->nodesetval;
12917
0
    if (set != NULL) {
12918
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12919
0
        if (set->nodeNr > 0)
12920
0
            *first = set->nodeTab[0];
12921
0
    }
12922
0
    valuePush(ctxt, obj);
12923
12924
0
    return (total);
12925
0
}
12926
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12927
12928
/**
12929
 * xmlXPathCompOpEval:
12930
 * @ctxt:  the XPath parser context with the compiled expression
12931
 * @op:  an XPath compiled operation
12932
 *
12933
 * Evaluate the Precompiled XPath operation
12934
 * Returns the number of nodes traversed
12935
 */
12936
static int
12937
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12938
2.22M
{
12939
2.22M
    int total = 0;
12940
2.22M
    int equal, ret;
12941
2.22M
    xmlXPathCompExprPtr comp;
12942
2.22M
    xmlXPathObjectPtr arg1, arg2;
12943
12944
2.22M
    CHECK_ERROR0;
12945
2.22M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12946
6
        return(0);
12947
2.22M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12948
2.22M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12949
2.22M
    ctxt->context->depth += 1;
12950
2.22M
    comp = ctxt->comp;
12951
2.22M
    switch (op->op) {
12952
0
        case XPATH_OP_END:
12953
0
            break;
12954
0
        case XPATH_OP_AND:
12955
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12956
0
      CHECK_ERROR0;
12957
0
            xmlXPathBooleanFunction(ctxt, 1);
12958
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12959
0
                break;
12960
0
            arg2 = valuePop(ctxt);
12961
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12962
0
      if (ctxt->error) {
12963
0
    xmlXPathFreeObject(arg2);
12964
0
    break;
12965
0
      }
12966
0
            xmlXPathBooleanFunction(ctxt, 1);
12967
0
            if (ctxt->value != NULL)
12968
0
                ctxt->value->boolval &= arg2->boolval;
12969
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12970
0
            break;
12971
82.7k
        case XPATH_OP_OR:
12972
82.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12973
82.7k
      CHECK_ERROR0;
12974
82.7k
            xmlXPathBooleanFunction(ctxt, 1);
12975
82.7k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12976
0
                break;
12977
82.7k
            arg2 = valuePop(ctxt);
12978
82.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12979
82.7k
      if (ctxt->error) {
12980
1
    xmlXPathFreeObject(arg2);
12981
1
    break;
12982
1
      }
12983
82.7k
            xmlXPathBooleanFunction(ctxt, 1);
12984
82.7k
            if (ctxt->value != NULL)
12985
82.7k
                ctxt->value->boolval |= arg2->boolval;
12986
82.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
12987
82.7k
            break;
12988
85.1k
        case XPATH_OP_EQUAL:
12989
85.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990
85.1k
      CHECK_ERROR0;
12991
85.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12992
85.1k
      CHECK_ERROR0;
12993
85.1k
      if (op->value)
12994
79.8k
    equal = xmlXPathEqualValues(ctxt);
12995
5.27k
      else
12996
5.27k
    equal = xmlXPathNotEqualValues(ctxt);
12997
85.1k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12998
85.1k
            break;
12999
82.8k
        case XPATH_OP_CMP:
13000
82.8k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13001
82.8k
      CHECK_ERROR0;
13002
82.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13003
82.7k
      CHECK_ERROR0;
13004
82.7k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13005
82.7k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13006
82.7k
            break;
13007
172k
        case XPATH_OP_PLUS:
13008
172k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13009
172k
      CHECK_ERROR0;
13010
172k
            if (op->ch2 != -1) {
13011
254
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13012
254
      }
13013
172k
      CHECK_ERROR0;
13014
172k
            if (op->value == 0)
13015
206
                xmlXPathSubValues(ctxt);
13016
172k
            else if (op->value == 1)
13017
46
                xmlXPathAddValues(ctxt);
13018
172k
            else if (op->value == 2)
13019
172k
                xmlXPathValueFlipSign(ctxt);
13020
0
            else if (op->value == 3) {
13021
0
                CAST_TO_NUMBER;
13022
0
                CHECK_TYPE0(XPATH_NUMBER);
13023
0
            }
13024
172k
            break;
13025
172k
        case XPATH_OP_MULT:
13026
26.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13027
26.0k
      CHECK_ERROR0;
13028
26.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13029
26.0k
      CHECK_ERROR0;
13030
25.9k
            if (op->value == 0)
13031
25.9k
                xmlXPathMultValues(ctxt);
13032
0
            else if (op->value == 1)
13033
0
                xmlXPathDivValues(ctxt);
13034
0
            else if (op->value == 2)
13035
0
                xmlXPathModValues(ctxt);
13036
25.9k
            break;
13037
24.3k
        case XPATH_OP_UNION:
13038
24.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13039
24.3k
      CHECK_ERROR0;
13040
23.9k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13041
23.9k
      CHECK_ERROR0;
13042
13043
23.9k
            arg2 = valuePop(ctxt);
13044
23.9k
            arg1 = valuePop(ctxt);
13045
23.9k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13046
23.9k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13047
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13048
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13049
0
                XP_ERROR0(XPATH_INVALID_TYPE);
13050
0
            }
13051
23.9k
            if ((ctxt->context->opLimit != 0) &&
13052
23.9k
                (((arg1->nodesetval != NULL) &&
13053
23.9k
                  (xmlXPathCheckOpLimit(ctxt,
13054
23.8k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13055
23.9k
                 ((arg2->nodesetval != NULL) &&
13056
23.9k
                  (xmlXPathCheckOpLimit(ctxt,
13057
23.8k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13058
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13059
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13060
0
                break;
13061
0
            }
13062
13063
23.9k
      if ((arg1->nodesetval == NULL) ||
13064
23.9k
    ((arg2->nodesetval != NULL) &&
13065
23.8k
     (arg2->nodesetval->nodeNr != 0)))
13066
23.8k
      {
13067
                /* TODO: Check memory error. */
13068
23.8k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13069
23.8k
              arg2->nodesetval);
13070
23.8k
      }
13071
13072
23.9k
            valuePush(ctxt, arg1);
13073
23.9k
      xmlXPathReleaseObject(ctxt->context, arg2);
13074
23.9k
            break;
13075
70.6k
        case XPATH_OP_ROOT:
13076
70.6k
            xmlXPathRoot(ctxt);
13077
70.6k
            break;
13078
155k
        case XPATH_OP_NODE:
13079
155k
            if (op->ch1 != -1)
13080
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13081
155k
      CHECK_ERROR0;
13082
155k
            if (op->ch2 != -1)
13083
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13084
155k
      CHECK_ERROR0;
13085
155k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13086
155k
    ctxt->context->node));
13087
155k
            break;
13088
80.0k
        case XPATH_OP_COLLECT:{
13089
80.0k
                if (op->ch1 == -1)
13090
0
                    break;
13091
13092
80.0k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13093
80.0k
    CHECK_ERROR0;
13094
13095
79.9k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13096
79.9k
                break;
13097
80.0k
            }
13098
537k
        case XPATH_OP_VALUE:
13099
537k
            valuePush(ctxt,
13100
537k
                      xmlXPathCacheObjectCopy(ctxt->context,
13101
537k
      (xmlXPathObjectPtr) op->value4));
13102
537k
            break;
13103
0
        case XPATH_OP_VARIABLE:{
13104
0
    xmlXPathObjectPtr val;
13105
13106
0
                if (op->ch1 != -1)
13107
0
                    total +=
13108
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109
0
                if (op->value5 == NULL) {
13110
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13111
0
        if (val == NULL)
13112
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13113
0
                    valuePush(ctxt, val);
13114
0
    } else {
13115
0
                    const xmlChar *URI;
13116
13117
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13118
0
                    if (URI == NULL) {
13119
0
                        xmlGenericError(xmlGenericErrorContext,
13120
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13121
0
                                    (char *) op->value4, (char *)op->value5);
13122
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13123
0
                        break;
13124
0
                    }
13125
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13126
0
                                                       op->value4, URI);
13127
0
        if (val == NULL)
13128
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129
0
                    valuePush(ctxt, val);
13130
0
                }
13131
0
                break;
13132
0
            }
13133
206k
        case XPATH_OP_FUNCTION:{
13134
206k
                xmlXPathFunction func;
13135
206k
                const xmlChar *oldFunc, *oldFuncURI;
13136
206k
    int i;
13137
206k
                int frame;
13138
13139
206k
                frame = ctxt->valueNr;
13140
206k
                if (op->ch1 != -1) {
13141
187k
                    total +=
13142
187k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13143
187k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
13144
22
                        break;
13145
187k
                }
13146
206k
    if (ctxt->valueNr < frame + op->value) {
13147
0
        xmlGenericError(xmlGenericErrorContext,
13148
0
          "xmlXPathCompOpEval: parameter error\n");
13149
0
        ctxt->error = XPATH_INVALID_OPERAND;
13150
0
        break;
13151
0
    }
13152
564k
    for (i = 0; i < op->value; i++) {
13153
358k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13154
0
      xmlGenericError(xmlGenericErrorContext,
13155
0
        "xmlXPathCompOpEval: parameter error\n");
13156
0
      ctxt->error = XPATH_INVALID_OPERAND;
13157
0
      break;
13158
0
        }
13159
358k
                }
13160
206k
                if (op->cache != NULL)
13161
199k
                    func = op->cache;
13162
6.60k
                else {
13163
6.60k
                    const xmlChar *URI = NULL;
13164
13165
6.60k
                    if (op->value5 == NULL)
13166
30
                        func =
13167
30
                            xmlXPathFunctionLookup(ctxt->context,
13168
30
                                                   op->value4);
13169
6.57k
                    else {
13170
6.57k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13171
6.57k
                        if (URI == NULL) {
13172
0
                            xmlGenericError(xmlGenericErrorContext,
13173
0
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13174
0
                                    (char *)op->value4, (char *)op->value5);
13175
0
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13176
0
                            break;
13177
0
                        }
13178
6.57k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13179
6.57k
                                                        op->value4, URI);
13180
6.57k
                    }
13181
6.60k
                    if (func == NULL) {
13182
6
                        xmlGenericError(xmlGenericErrorContext,
13183
6
                                "xmlXPathCompOpEval: function %s not found\n",
13184
6
                                        (char *)op->value4);
13185
6
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13186
0
                    }
13187
6.59k
                    op->cache = func;
13188
6.59k
                    op->cacheURI = (void *) URI;
13189
6.59k
                }
13190
206k
                oldFunc = ctxt->context->function;
13191
206k
                oldFuncURI = ctxt->context->functionURI;
13192
206k
                ctxt->context->function = op->value4;
13193
206k
                ctxt->context->functionURI = op->cacheURI;
13194
206k
                func(ctxt, op->value);
13195
206k
                ctxt->context->function = oldFunc;
13196
206k
                ctxt->context->functionURI = oldFuncURI;
13197
206k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13198
206k
                    (ctxt->valueNr != frame + 1))
13199
206k
                    XP_ERROR0(XPATH_STACK_ERROR);
13200
206k
                break;
13201
206k
            }
13202
358k
        case XPATH_OP_ARG:
13203
358k
            if (op->ch1 != -1) {
13204
171k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13205
171k
          CHECK_ERROR0;
13206
171k
            }
13207
358k
            if (op->ch2 != -1) {
13208
358k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13209
358k
          CHECK_ERROR0;
13210
358k
      }
13211
358k
            break;
13212
358k
        case XPATH_OP_PREDICATE:
13213
13.1k
        case XPATH_OP_FILTER:{
13214
13.1k
                xmlXPathObjectPtr obj;
13215
13.1k
                xmlNodeSetPtr set;
13216
13217
                /*
13218
                 * Optimization for ()[1] selection i.e. the first elem
13219
                 */
13220
13.1k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13221
13.1k
#ifdef XP_OPTIMIZED_FILTER_FIRST
13222
        /*
13223
        * FILTER TODO: Can we assume that the inner processing
13224
        *  will result in an ordered list if we have an
13225
        *  XPATH_OP_FILTER?
13226
        *  What about an additional field or flag on
13227
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13228
        *  to assume anything, so it would be more robust and
13229
        *  easier to optimize.
13230
        */
13231
13.1k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13232
13.1k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13233
#else
13234
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13235
#endif
13236
13.1k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13237
399
                    xmlXPathObjectPtr val;
13238
13239
399
                    val = comp->steps[op->ch2].value4;
13240
399
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13241
399
                        (val->floatval == 1.0)) {
13242
382
                        xmlNodePtr first = NULL;
13243
13244
382
                        total +=
13245
382
                            xmlXPathCompOpEvalFirst(ctxt,
13246
382
                                                    &comp->steps[op->ch1],
13247
382
                                                    &first);
13248
382
      CHECK_ERROR0;
13249
                        /*
13250
                         * The nodeset should be in document order,
13251
                         * Keep only the first value
13252
                         */
13253
378
                        if ((ctxt->value != NULL) &&
13254
378
                            (ctxt->value->type == XPATH_NODESET) &&
13255
378
                            (ctxt->value->nodesetval != NULL) &&
13256
378
                            (ctxt->value->nodesetval->nodeNr > 1))
13257
242
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13258
242
                                                        1, 1);
13259
378
                        break;
13260
382
                    }
13261
399
                }
13262
                /*
13263
                 * Optimization for ()[last()] selection i.e. the last elem
13264
                 */
13265
12.7k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13266
12.7k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13267
12.7k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13268
12.7k
                    int f = comp->steps[op->ch2].ch1;
13269
13270
12.7k
                    if ((f != -1) &&
13271
12.7k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13272
12.7k
                        (comp->steps[f].value5 == NULL) &&
13273
12.7k
                        (comp->steps[f].value == 0) &&
13274
12.7k
                        (comp->steps[f].value4 != NULL) &&
13275
12.7k
                        (xmlStrEqual
13276
6.16k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13277
6.16k
                        xmlNodePtr last = NULL;
13278
13279
6.16k
                        total +=
13280
6.16k
                            xmlXPathCompOpEvalLast(ctxt,
13281
6.16k
                                                   &comp->steps[op->ch1],
13282
6.16k
                                                   &last);
13283
6.16k
      CHECK_ERROR0;
13284
                        /*
13285
                         * The nodeset should be in document order,
13286
                         * Keep only the last value
13287
                         */
13288
6.16k
                        if ((ctxt->value != NULL) &&
13289
6.16k
                            (ctxt->value->type == XPATH_NODESET) &&
13290
6.16k
                            (ctxt->value->nodesetval != NULL) &&
13291
6.16k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13292
6.16k
                            (ctxt->value->nodesetval->nodeNr > 1))
13293
560
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13294
6.16k
                        break;
13295
6.16k
                    }
13296
12.7k
                }
13297
    /*
13298
    * Process inner predicates first.
13299
    * Example "index[parent::book][1]":
13300
    * ...
13301
    *   PREDICATE   <-- we are here "[1]"
13302
    *     PREDICATE <-- process "[parent::book]" first
13303
    *       SORT
13304
    *         COLLECT  'parent' 'name' 'node' book
13305
    *           NODE
13306
    *     ELEM Object is a number : 1
13307
    */
13308
6.59k
                if (op->ch1 != -1)
13309
6.59k
                    total +=
13310
6.59k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311
6.59k
    CHECK_ERROR0;
13312
6.58k
                if (op->ch2 == -1)
13313
0
                    break;
13314
6.58k
                if (ctxt->value == NULL)
13315
0
                    break;
13316
13317
#ifdef LIBXML_XPTR_LOCS_ENABLED
13318
                /*
13319
                 * Hum are we filtering the result of an XPointer expression
13320
                 */
13321
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13322
                    xmlLocationSetPtr locset = ctxt->value->user;
13323
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13324
                                              1, locset->locNr);
13325
                    break;
13326
                }
13327
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13328
13329
                /*
13330
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
13331
                 * nodes from the stack. We have to temporarily remove the
13332
                 * nodeset object from the stack to avoid freeing it
13333
                 * prematurely.
13334
                 */
13335
6.58k
                CHECK_TYPE0(XPATH_NODESET);
13336
6.58k
                obj = valuePop(ctxt);
13337
6.58k
                set = obj->nodesetval;
13338
6.58k
                if (set != NULL)
13339
6.58k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13340
6.58k
                                          1, set->nodeNr, 1);
13341
6.58k
                valuePush(ctxt, obj);
13342
6.58k
                break;
13343
6.58k
            }
13344
330k
        case XPATH_OP_SORT:
13345
330k
            if (op->ch1 != -1)
13346
330k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13347
330k
      CHECK_ERROR0;
13348
330k
            if ((ctxt->value != NULL) &&
13349
330k
                (ctxt->value->type == XPATH_NODESET) &&
13350
330k
                (ctxt->value->nodesetval != NULL) &&
13351
330k
    (ctxt->value->nodesetval->nodeNr > 1))
13352
10.1k
      {
13353
10.1k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13354
10.1k
      }
13355
330k
            break;
13356
#ifdef LIBXML_XPTR_LOCS_ENABLED
13357
        case XPATH_OP_RANGETO:{
13358
                xmlXPathObjectPtr range;
13359
                xmlXPathObjectPtr res, obj;
13360
                xmlXPathObjectPtr tmp;
13361
                xmlLocationSetPtr newlocset = NULL;
13362
        xmlLocationSetPtr oldlocset;
13363
                xmlNodeSetPtr oldset;
13364
                xmlNodePtr oldnode = ctxt->context->node;
13365
                int oldcs = ctxt->context->contextSize;
13366
                int oldpp = ctxt->context->proximityPosition;
13367
                int i, j;
13368
13369
                if (op->ch1 != -1) {
13370
                    total +=
13371
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13372
                    CHECK_ERROR0;
13373
                }
13374
                if (ctxt->value == NULL) {
13375
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13376
                }
13377
                if (op->ch2 == -1)
13378
                    break;
13379
13380
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13381
                    /*
13382
                     * Extract the old locset, and then evaluate the result of the
13383
                     * expression for all the element in the locset. use it to grow
13384
                     * up a new locset.
13385
                     */
13386
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13387
13388
                    if ((ctxt->value->user == NULL) ||
13389
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13390
                        break;
13391
13392
                    obj = valuePop(ctxt);
13393
                    oldlocset = obj->user;
13394
13395
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13396
13397
                    for (i = 0; i < oldlocset->locNr; i++) {
13398
                        /*
13399
                         * Run the evaluation with a node list made of a
13400
                         * single item in the nodelocset.
13401
                         */
13402
                        ctxt->context->node = oldlocset->locTab[i]->user;
13403
                        ctxt->context->contextSize = oldlocset->locNr;
13404
                        ctxt->context->proximityPosition = i + 1;
13405
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13406
          ctxt->context->node);
13407
                        valuePush(ctxt, tmp);
13408
13409
                        if (op->ch2 != -1)
13410
                            total +=
13411
                                xmlXPathCompOpEval(ctxt,
13412
                                                   &comp->steps[op->ch2]);
13413
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13414
                            xmlXPtrFreeLocationSet(newlocset);
13415
                            goto rangeto_error;
13416
      }
13417
13418
                        res = valuePop(ctxt);
13419
      if (res->type == XPATH_LOCATIONSET) {
13420
          xmlLocationSetPtr rloc =
13421
              (xmlLocationSetPtr)res->user;
13422
          for (j=0; j<rloc->locNr; j++) {
13423
              range = xmlXPtrNewRange(
13424
          oldlocset->locTab[i]->user,
13425
          oldlocset->locTab[i]->index,
13426
          rloc->locTab[j]->user2,
13427
          rloc->locTab[j]->index2);
13428
        if (range != NULL) {
13429
            xmlXPtrLocationSetAdd(newlocset, range);
13430
        }
13431
          }
13432
      } else {
13433
          range = xmlXPtrNewRangeNodeObject(
13434
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13435
                            if (range != NULL) {
13436
                                xmlXPtrLocationSetAdd(newlocset,range);
13437
          }
13438
                        }
13439
13440
                        /*
13441
                         * Cleanup
13442
                         */
13443
                        if (res != NULL) {
13444
          xmlXPathReleaseObject(ctxt->context, res);
13445
      }
13446
                        if (ctxt->value == tmp) {
13447
                            res = valuePop(ctxt);
13448
          xmlXPathReleaseObject(ctxt->context, res);
13449
                        }
13450
                    }
13451
    } else {  /* Not a location set */
13452
                    CHECK_TYPE0(XPATH_NODESET);
13453
                    obj = valuePop(ctxt);
13454
                    oldset = obj->nodesetval;
13455
13456
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13457
13458
                    if (oldset != NULL) {
13459
                        for (i = 0; i < oldset->nodeNr; i++) {
13460
                            /*
13461
                             * Run the evaluation with a node list made of a single item
13462
                             * in the nodeset.
13463
                             */
13464
                            ctxt->context->node = oldset->nodeTab[i];
13465
          /*
13466
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13467
          */
13468
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13469
        ctxt->context->node);
13470
                            valuePush(ctxt, tmp);
13471
13472
                            if (op->ch2 != -1)
13473
                                total +=
13474
                                    xmlXPathCompOpEval(ctxt,
13475
                                                   &comp->steps[op->ch2]);
13476
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13477
                                xmlXPtrFreeLocationSet(newlocset);
13478
                                goto rangeto_error;
13479
          }
13480
13481
                            res = valuePop(ctxt);
13482
                            range =
13483
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13484
                                                      res);
13485
                            if (range != NULL) {
13486
                                xmlXPtrLocationSetAdd(newlocset, range);
13487
                            }
13488
13489
                            /*
13490
                             * Cleanup
13491
                             */
13492
                            if (res != NULL) {
13493
        xmlXPathReleaseObject(ctxt->context, res);
13494
          }
13495
                            if (ctxt->value == tmp) {
13496
                                res = valuePop(ctxt);
13497
        xmlXPathReleaseObject(ctxt->context, res);
13498
                            }
13499
                        }
13500
                    }
13501
                }
13502
13503
                /*
13504
                 * The result is used as the new evaluation set.
13505
                 */
13506
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13507
rangeto_error:
13508
    xmlXPathReleaseObject(ctxt->context, obj);
13509
                ctxt->context->node = oldnode;
13510
                ctxt->context->contextSize = oldcs;
13511
                ctxt->context->proximityPosition = oldpp;
13512
                break;
13513
            }
13514
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13515
0
        default:
13516
0
            xmlGenericError(xmlGenericErrorContext,
13517
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13518
0
            ctxt->error = XPATH_INVALID_OPERAND;
13519
0
            break;
13520
2.22M
    }
13521
13522
2.22M
    ctxt->context->depth -= 1;
13523
2.22M
    return (total);
13524
2.22M
}
13525
13526
/**
13527
 * xmlXPathCompOpEvalToBoolean:
13528
 * @ctxt:  the XPath parser context
13529
 *
13530
 * Evaluates if the expression evaluates to true.
13531
 *
13532
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13533
 */
13534
static int
13535
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13536
          xmlXPathStepOpPtr op,
13537
          int isPredicate)
13538
292k
{
13539
292k
    xmlXPathObjectPtr resObj = NULL;
13540
13541
335k
start:
13542
335k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13543
92
        return(0);
13544
    /* comp = ctxt->comp; */
13545
335k
    switch (op->op) {
13546
0
        case XPATH_OP_END:
13547
0
            return (0);
13548
704
  case XPATH_OP_VALUE:
13549
704
      resObj = (xmlXPathObjectPtr) op->value4;
13550
704
      if (isPredicate)
13551
704
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13552
0
      return(xmlXPathCastToBoolean(resObj));
13553
43.2k
  case XPATH_OP_SORT:
13554
      /*
13555
      * We don't need sorting for boolean results. Skip this one.
13556
      */
13557
43.2k
            if (op->ch1 != -1) {
13558
43.2k
    op = &ctxt->comp->steps[op->ch1];
13559
43.2k
    goto start;
13560
43.2k
      }
13561
0
      return(0);
13562
202
  case XPATH_OP_COLLECT:
13563
202
      if (op->ch1 == -1)
13564
0
    return(0);
13565
13566
202
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13567
202
      if (ctxt->error != XPATH_EXPRESSION_OK)
13568
3
    return(-1);
13569
13570
199
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13571
199
      if (ctxt->error != XPATH_EXPRESSION_OK)
13572
0
    return(-1);
13573
13574
199
      resObj = valuePop(ctxt);
13575
199
      if (resObj == NULL)
13576
0
    return(-1);
13577
199
      break;
13578
291k
  default:
13579
      /*
13580
      * Fallback to call xmlXPathCompOpEval().
13581
      */
13582
291k
      xmlXPathCompOpEval(ctxt, op);
13583
291k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13584
36
    return(-1);
13585
13586
291k
      resObj = valuePop(ctxt);
13587
291k
      if (resObj == NULL)
13588
0
    return(-1);
13589
291k
      break;
13590
335k
    }
13591
13592
291k
    if (resObj) {
13593
291k
  int res;
13594
13595
291k
  if (resObj->type == XPATH_BOOLEAN) {
13596
162k
      res = resObj->boolval;
13597
162k
  } else if (isPredicate) {
13598
      /*
13599
      * For predicates a result of type "number" is handled
13600
      * differently:
13601
      * SPEC XPath 1.0:
13602
      * "If the result is a number, the result will be converted
13603
      *  to true if the number is equal to the context position
13604
      *  and will be converted to false otherwise;"
13605
      */
13606
128k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13607
128k
  } else {
13608
0
      res = xmlXPathCastToBoolean(resObj);
13609
0
  }
13610
291k
  xmlXPathReleaseObject(ctxt->context, resObj);
13611
291k
  return(res);
13612
291k
    }
13613
13614
0
    return(0);
13615
291k
}
13616
13617
#ifdef XPATH_STREAMING
13618
/**
13619
 * xmlXPathRunStreamEval:
13620
 * @ctxt:  the XPath parser context with the compiled expression
13621
 *
13622
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13623
 */
13624
static int
13625
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13626
          xmlXPathObjectPtr *resultSeq, int toBool)
13627
425
{
13628
425
    int max_depth, min_depth;
13629
425
    int from_root;
13630
425
    int ret, depth;
13631
425
    int eval_all_nodes;
13632
425
    xmlNodePtr cur = NULL, limit = NULL;
13633
425
    xmlStreamCtxtPtr patstream = NULL;
13634
13635
425
    if ((ctxt == NULL) || (comp == NULL))
13636
0
        return(-1);
13637
425
    max_depth = xmlPatternMaxDepth(comp);
13638
425
    if (max_depth == -1)
13639
0
        return(-1);
13640
425
    if (max_depth == -2)
13641
7
        max_depth = 10000;
13642
425
    min_depth = xmlPatternMinDepth(comp);
13643
425
    if (min_depth == -1)
13644
0
        return(-1);
13645
425
    from_root = xmlPatternFromRoot(comp);
13646
425
    if (from_root < 0)
13647
0
        return(-1);
13648
#if 0
13649
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13650
#endif
13651
13652
425
    if (! toBool) {
13653
425
  if (resultSeq == NULL)
13654
0
      return(-1);
13655
425
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13656
425
  if (*resultSeq == NULL)
13657
0
      return(-1);
13658
425
    }
13659
13660
    /*
13661
     * handle the special cases of "/" amd "." being matched
13662
     */
13663
425
    if (min_depth == 0) {
13664
0
  if (from_root) {
13665
      /* Select "/" */
13666
0
      if (toBool)
13667
0
    return(1);
13668
            /* TODO: Check memory error. */
13669
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13670
0
                         (xmlNodePtr) ctxt->doc);
13671
0
  } else {
13672
      /* Select "self::node()" */
13673
0
      if (toBool)
13674
0
    return(1);
13675
            /* TODO: Check memory error. */
13676
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13677
0
  }
13678
0
    }
13679
425
    if (max_depth == 0) {
13680
0
  return(0);
13681
0
    }
13682
13683
425
    if (from_root) {
13684
3
        cur = (xmlNodePtr)ctxt->doc;
13685
422
    } else if (ctxt->node != NULL) {
13686
422
        switch (ctxt->node->type) {
13687
0
            case XML_ELEMENT_NODE:
13688
422
            case XML_DOCUMENT_NODE:
13689
422
            case XML_DOCUMENT_FRAG_NODE:
13690
422
            case XML_HTML_DOCUMENT_NODE:
13691
422
          cur = ctxt->node;
13692
422
    break;
13693
0
            case XML_ATTRIBUTE_NODE:
13694
0
            case XML_TEXT_NODE:
13695
0
            case XML_CDATA_SECTION_NODE:
13696
0
            case XML_ENTITY_REF_NODE:
13697
0
            case XML_ENTITY_NODE:
13698
0
            case XML_PI_NODE:
13699
0
            case XML_COMMENT_NODE:
13700
0
            case XML_NOTATION_NODE:
13701
0
            case XML_DTD_NODE:
13702
0
            case XML_DOCUMENT_TYPE_NODE:
13703
0
            case XML_ELEMENT_DECL:
13704
0
            case XML_ATTRIBUTE_DECL:
13705
0
            case XML_ENTITY_DECL:
13706
0
            case XML_NAMESPACE_DECL:
13707
0
            case XML_XINCLUDE_START:
13708
0
            case XML_XINCLUDE_END:
13709
0
    break;
13710
422
  }
13711
422
  limit = cur;
13712
422
    }
13713
425
    if (cur == NULL) {
13714
0
        return(0);
13715
0
    }
13716
13717
425
    patstream = xmlPatternGetStreamCtxt(comp);
13718
425
    if (patstream == NULL) {
13719
  /*
13720
  * QUESTION TODO: Is this an error?
13721
  */
13722
0
  return(0);
13723
0
    }
13724
13725
425
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13726
13727
425
    if (from_root) {
13728
3
  ret = xmlStreamPush(patstream, NULL, NULL);
13729
3
  if (ret < 0) {
13730
3
  } else if (ret == 1) {
13731
0
      if (toBool)
13732
0
    goto return_1;
13733
            /* TODO: Check memory error. */
13734
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13735
0
  }
13736
3
    }
13737
425
    depth = 0;
13738
425
    goto scan_children;
13739
12
next_node:
13740
432
    do {
13741
432
        if (ctxt->opLimit != 0) {
13742
432
            if (ctxt->opCount >= ctxt->opLimit) {
13743
0
                xmlGenericError(xmlGenericErrorContext,
13744
0
                        "XPath operation limit exceeded\n");
13745
0
                xmlFreeStreamCtxt(patstream);
13746
0
                return(-1);
13747
0
            }
13748
432
            ctxt->opCount++;
13749
432
        }
13750
13751
432
  switch (cur->type) {
13752
423
      case XML_ELEMENT_NODE:
13753
432
      case XML_TEXT_NODE:
13754
432
      case XML_CDATA_SECTION_NODE:
13755
432
      case XML_COMMENT_NODE:
13756
432
      case XML_PI_NODE:
13757
432
    if (cur->type == XML_ELEMENT_NODE) {
13758
423
        ret = xmlStreamPush(patstream, cur->name,
13759
423
        (cur->ns ? cur->ns->href : NULL));
13760
423
    } else if (eval_all_nodes)
13761
0
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13762
9
    else
13763
9
        break;
13764
13765
423
    if (ret < 0) {
13766
        /* NOP. */
13767
423
    } else if (ret == 1) {
13768
0
        if (toBool)
13769
0
      goto return_1;
13770
0
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13771
0
            < 0) {
13772
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13773
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13774
0
        }
13775
0
    }
13776
423
    if ((cur->children == NULL) || (depth >= max_depth)) {
13777
420
        ret = xmlStreamPop(patstream);
13778
420
        while (cur->next != NULL) {
13779
6
      cur = cur->next;
13780
6
      if ((cur->type != XML_ENTITY_DECL) &&
13781
6
          (cur->type != XML_DTD_NODE))
13782
6
          goto next_node;
13783
6
        }
13784
420
    }
13785
417
      default:
13786
417
    break;
13787
432
  }
13788
13789
851
scan_children:
13790
851
  if (cur->type == XML_NAMESPACE_DECL) break;
13791
851
  if ((cur->children != NULL) && (depth < max_depth)) {
13792
      /*
13793
       * Do not descend on entities declarations
13794
       */
13795
420
      if (cur->children->type != XML_ENTITY_DECL) {
13796
420
    cur = cur->children;
13797
420
    depth++;
13798
    /*
13799
     * Skip DTDs
13800
     */
13801
420
    if (cur->type != XML_DTD_NODE)
13802
420
        continue;
13803
420
      }
13804
420
  }
13805
13806
431
  if (cur == limit)
13807
8
      break;
13808
13809
423
  while (cur->next != NULL) {
13810
6
      cur = cur->next;
13811
6
      if ((cur->type != XML_ENTITY_DECL) &&
13812
6
    (cur->type != XML_DTD_NODE))
13813
6
    goto next_node;
13814
6
  }
13815
13816
420
  do {
13817
420
      cur = cur->parent;
13818
420
      depth--;
13819
420
      if ((cur == NULL) || (cur == limit) ||
13820
420
                (cur->type == XML_DOCUMENT_NODE))
13821
417
          goto done;
13822
3
      if (cur->type == XML_ELEMENT_NODE) {
13823
3
    ret = xmlStreamPop(patstream);
13824
3
      } else if ((eval_all_nodes) &&
13825
0
    ((cur->type == XML_TEXT_NODE) ||
13826
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13827
0
     (cur->type == XML_COMMENT_NODE) ||
13828
0
     (cur->type == XML_PI_NODE)))
13829
0
      {
13830
0
    ret = xmlStreamPop(patstream);
13831
0
      }
13832
3
      if (cur->next != NULL) {
13833
0
    cur = cur->next;
13834
0
    break;
13835
0
      }
13836
3
  } while (cur != NULL);
13837
13838
420
    } while ((cur != NULL) && (depth >= 0));
13839
13840
425
done:
13841
13842
425
    if (patstream)
13843
425
  xmlFreeStreamCtxt(patstream);
13844
425
    return(0);
13845
13846
0
return_1:
13847
0
    if (patstream)
13848
0
  xmlFreeStreamCtxt(patstream);
13849
0
    return(1);
13850
12
}
13851
#endif /* XPATH_STREAMING */
13852
13853
/**
13854
 * xmlXPathRunEval:
13855
 * @ctxt:  the XPath parser context with the compiled expression
13856
 * @toBool:  evaluate to a boolean result
13857
 *
13858
 * Evaluate the Precompiled XPath expression in the given context.
13859
 */
13860
static int
13861
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13862
12.5k
{
13863
12.5k
    xmlXPathCompExprPtr comp;
13864
12.5k
    int oldDepth;
13865
13866
12.5k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13867
0
  return(-1);
13868
13869
12.5k
    if (ctxt->valueTab == NULL) {
13870
  /* Allocate the value stack */
13871
152
  ctxt->valueTab = (xmlXPathObjectPtr *)
13872
152
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13873
152
  if (ctxt->valueTab == NULL) {
13874
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13875
0
      return(-1);
13876
0
  }
13877
152
  ctxt->valueNr = 0;
13878
152
  ctxt->valueMax = 10;
13879
152
  ctxt->value = NULL;
13880
152
    }
13881
12.5k
#ifdef XPATH_STREAMING
13882
12.5k
    if (ctxt->comp->stream) {
13883
425
  int res;
13884
13885
425
  if (toBool) {
13886
      /*
13887
      * Evaluation to boolean result.
13888
      */
13889
0
      res = xmlXPathRunStreamEval(ctxt->context,
13890
0
    ctxt->comp->stream, NULL, 1);
13891
0
      if (res != -1)
13892
0
    return(res);
13893
425
  } else {
13894
425
      xmlXPathObjectPtr resObj = NULL;
13895
13896
      /*
13897
      * Evaluation to a sequence.
13898
      */
13899
425
      res = xmlXPathRunStreamEval(ctxt->context,
13900
425
    ctxt->comp->stream, &resObj, 0);
13901
13902
425
      if ((res != -1) && (resObj != NULL)) {
13903
425
    valuePush(ctxt, resObj);
13904
425
    return(0);
13905
425
      }
13906
0
      if (resObj != NULL)
13907
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13908
0
  }
13909
  /*
13910
  * QUESTION TODO: This falls back to normal XPath evaluation
13911
  * if res == -1. Is this intended?
13912
  */
13913
425
    }
13914
12.0k
#endif
13915
12.0k
    comp = ctxt->comp;
13916
12.0k
    if (comp->last < 0) {
13917
0
  xmlGenericError(xmlGenericErrorContext,
13918
0
      "xmlXPathRunEval: last is less than zero\n");
13919
0
  return(-1);
13920
0
    }
13921
12.0k
    oldDepth = ctxt->context->depth;
13922
12.0k
    if (toBool)
13923
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13924
0
      &comp->steps[comp->last], 0));
13925
12.0k
    else
13926
12.0k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13927
12.0k
    ctxt->context->depth = oldDepth;
13928
13929
12.0k
    return(0);
13930
12.0k
}
13931
13932
/************************************************************************
13933
 *                  *
13934
 *      Public interfaces       *
13935
 *                  *
13936
 ************************************************************************/
13937
13938
/**
13939
 * xmlXPathEvalPredicate:
13940
 * @ctxt:  the XPath context
13941
 * @res:  the Predicate Expression evaluation result
13942
 *
13943
 * Evaluate a predicate result for the current node.
13944
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13945
 * the result to a boolean. If the result is a number, the result will
13946
 * be converted to true if the number is equal to the position of the
13947
 * context node in the context node list (as returned by the position
13948
 * function) and will be converted to false otherwise; if the result
13949
 * is not a number, then the result will be converted as if by a call
13950
 * to the boolean function.
13951
 *
13952
 * Returns 1 if predicate is true, 0 otherwise
13953
 */
13954
int
13955
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13956
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13957
0
    switch (res->type) {
13958
0
        case XPATH_BOOLEAN:
13959
0
      return(res->boolval);
13960
0
        case XPATH_NUMBER:
13961
0
      return(res->floatval == ctxt->proximityPosition);
13962
0
        case XPATH_NODESET:
13963
0
        case XPATH_XSLT_TREE:
13964
0
      if (res->nodesetval == NULL)
13965
0
    return(0);
13966
0
      return(res->nodesetval->nodeNr != 0);
13967
0
        case XPATH_STRING:
13968
0
      return((res->stringval != NULL) &&
13969
0
             (xmlStrlen(res->stringval) != 0));
13970
0
        default:
13971
0
      STRANGE
13972
0
    }
13973
0
    return(0);
13974
0
}
13975
13976
/**
13977
 * xmlXPathEvaluatePredicateResult:
13978
 * @ctxt:  the XPath Parser context
13979
 * @res:  the Predicate Expression evaluation result
13980
 *
13981
 * Evaluate a predicate result for the current node.
13982
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13983
 * the result to a boolean. If the result is a number, the result will
13984
 * be converted to true if the number is equal to the position of the
13985
 * context node in the context node list (as returned by the position
13986
 * function) and will be converted to false otherwise; if the result
13987
 * is not a number, then the result will be converted as if by a call
13988
 * to the boolean function.
13989
 *
13990
 * Returns 1 if predicate is true, 0 otherwise
13991
 */
13992
int
13993
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13994
129k
                                xmlXPathObjectPtr res) {
13995
129k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13996
129k
    switch (res->type) {
13997
0
        case XPATH_BOOLEAN:
13998
0
      return(res->boolval);
13999
34.6k
        case XPATH_NUMBER:
14000
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14001
      return((res->floatval == ctxt->context->proximityPosition) &&
14002
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14003
#else
14004
34.6k
      return(res->floatval == ctxt->context->proximityPosition);
14005
0
#endif
14006
30.9k
        case XPATH_NODESET:
14007
30.9k
        case XPATH_XSLT_TREE:
14008
30.9k
      if (res->nodesetval == NULL)
14009
30
    return(0);
14010
30.8k
      return(res->nodesetval->nodeNr != 0);
14011
64.1k
        case XPATH_STRING:
14012
64.1k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14013
#ifdef LIBXML_XPTR_LOCS_ENABLED
14014
  case XPATH_LOCATIONSET:{
14015
      xmlLocationSetPtr ptr = res->user;
14016
      if (ptr == NULL)
14017
          return(0);
14018
      return (ptr->locNr != 0);
14019
      }
14020
#endif
14021
0
        default:
14022
0
      STRANGE
14023
129k
    }
14024
0
    return(0);
14025
129k
}
14026
14027
#ifdef XPATH_STREAMING
14028
/**
14029
 * xmlXPathTryStreamCompile:
14030
 * @ctxt: an XPath context
14031
 * @str:  the XPath expression
14032
 *
14033
 * Try to compile the XPath expression as a streamable subset.
14034
 *
14035
 * Returns the compiled expression or NULL if failed to compile.
14036
 */
14037
static xmlXPathCompExprPtr
14038
22.5k
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14039
    /*
14040
     * Optimization: use streaming patterns when the XPath expression can
14041
     * be compiled to a stream lookup
14042
     */
14043
22.5k
    xmlPatternPtr stream;
14044
22.5k
    xmlXPathCompExprPtr comp;
14045
22.5k
    xmlDictPtr dict = NULL;
14046
22.5k
    const xmlChar **namespaces = NULL;
14047
22.5k
    xmlNsPtr ns;
14048
22.5k
    int i, j;
14049
14050
22.5k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14051
22.5k
        (!xmlStrchr(str, '@'))) {
14052
2.41k
  const xmlChar *tmp;
14053
14054
  /*
14055
   * We don't try to handle expressions using the verbose axis
14056
   * specifiers ("::"), just the simplified form at this point.
14057
   * Additionally, if there is no list of namespaces available and
14058
   *  there's a ":" in the expression, indicating a prefixed QName,
14059
   *  then we won't try to compile either. xmlPatterncompile() needs
14060
   *  to have a list of namespaces at compilation time in order to
14061
   *  compile prefixed name tests.
14062
   */
14063
2.41k
  tmp = xmlStrchr(str, ':');
14064
2.41k
  if ((tmp != NULL) &&
14065
2.41k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14066
216
      return(NULL);
14067
14068
2.20k
  if (ctxt != NULL) {
14069
2.20k
      dict = ctxt->dict;
14070
2.20k
      if (ctxt->nsNr > 0) {
14071
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14072
0
    if (namespaces == NULL) {
14073
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14074
0
        return(NULL);
14075
0
    }
14076
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14077
0
        ns = ctxt->namespaces[j];
14078
0
        namespaces[i++] = ns->href;
14079
0
        namespaces[i++] = ns->prefix;
14080
0
    }
14081
0
    namespaces[i++] = NULL;
14082
0
    namespaces[i] = NULL;
14083
0
      }
14084
2.20k
  }
14085
14086
2.20k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14087
2.20k
  if (namespaces != NULL) {
14088
0
      xmlFree((xmlChar **)namespaces);
14089
0
  }
14090
2.20k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14091
1.05k
      comp = xmlXPathNewCompExpr();
14092
1.05k
      if (comp == NULL) {
14093
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14094
0
          xmlFreePattern(stream);
14095
0
    return(NULL);
14096
0
      }
14097
1.05k
      comp->stream = stream;
14098
1.05k
      comp->dict = dict;
14099
1.05k
      if (comp->dict)
14100
0
    xmlDictReference(comp->dict);
14101
1.05k
      return(comp);
14102
1.05k
  }
14103
1.14k
  xmlFreePattern(stream);
14104
1.14k
    }
14105
21.2k
    return(NULL);
14106
22.5k
}
14107
#endif /* XPATH_STREAMING */
14108
14109
static void
14110
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14111
                           xmlXPathStepOpPtr op)
14112
378k
{
14113
378k
    xmlXPathCompExprPtr comp = pctxt->comp;
14114
378k
    xmlXPathContextPtr ctxt;
14115
14116
    /*
14117
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14118
    * internal representation.
14119
    */
14120
14121
378k
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14122
378k
        (op->ch1 != -1) &&
14123
378k
        (op->ch2 == -1 /* no predicate */))
14124
106k
    {
14125
106k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14126
14127
106k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14128
106k
            ((xmlXPathAxisVal) prevop->value ==
14129
565
                AXIS_DESCENDANT_OR_SELF) &&
14130
106k
            (prevop->ch2 == -1) &&
14131
106k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14132
106k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14133
192
        {
14134
            /*
14135
            * This is a "descendant-or-self::node()" without predicates.
14136
            * Try to eliminate it.
14137
            */
14138
14139
192
            switch ((xmlXPathAxisVal) op->value) {
14140
179
                case AXIS_CHILD:
14141
179
                case AXIS_DESCENDANT:
14142
                    /*
14143
                    * Convert "descendant-or-self::node()/child::" or
14144
                    * "descendant-or-self::node()/descendant::" to
14145
                    * "descendant::"
14146
                    */
14147
179
                    op->ch1   = prevop->ch1;
14148
179
                    op->value = AXIS_DESCENDANT;
14149
179
                    break;
14150
0
                case AXIS_SELF:
14151
1
                case AXIS_DESCENDANT_OR_SELF:
14152
                    /*
14153
                    * Convert "descendant-or-self::node()/self::" or
14154
                    * "descendant-or-self::node()/descendant-or-self::" to
14155
                    * to "descendant-or-self::"
14156
                    */
14157
1
                    op->ch1   = prevop->ch1;
14158
1
                    op->value = AXIS_DESCENDANT_OR_SELF;
14159
1
                    break;
14160
12
                default:
14161
12
                    break;
14162
192
            }
14163
192
  }
14164
106k
    }
14165
14166
    /* OP_VALUE has invalid ch1. */
14167
378k
    if (op->op == XPATH_OP_VALUE)
14168
133
        return;
14169
14170
    /* Recurse */
14171
378k
    ctxt = pctxt->context;
14172
378k
    if (ctxt != NULL) {
14173
378k
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14174
339
            return;
14175
377k
        ctxt->depth += 1;
14176
377k
    }
14177
377k
    if (op->ch1 != -1)
14178
258k
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14179
377k
    if (op->ch2 != -1)
14180
112k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14181
377k
    if (ctxt != NULL)
14182
377k
        ctxt->depth -= 1;
14183
377k
}
14184
14185
/**
14186
 * xmlXPathCtxtCompile:
14187
 * @ctxt: an XPath context
14188
 * @str:  the XPath expression
14189
 *
14190
 * Compile an XPath expression
14191
 *
14192
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14193
 *         the caller has to free the object.
14194
 */
14195
xmlXPathCompExprPtr
14196
22.3k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14197
22.3k
    xmlXPathParserContextPtr pctxt;
14198
22.3k
    xmlXPathCompExprPtr comp;
14199
22.3k
    int oldDepth = 0;
14200
14201
22.3k
#ifdef XPATH_STREAMING
14202
22.3k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14203
22.3k
    if (comp != NULL)
14204
1.05k
        return(comp);
14205
21.3k
#endif
14206
14207
21.3k
    xmlInitParser();
14208
14209
21.3k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14210
21.3k
    if (pctxt == NULL)
14211
0
        return NULL;
14212
21.3k
    if (ctxt != NULL)
14213
21.3k
        oldDepth = ctxt->depth;
14214
21.3k
    xmlXPathCompileExpr(pctxt, 1);
14215
21.3k
    if (ctxt != NULL)
14216
21.3k
        ctxt->depth = oldDepth;
14217
14218
21.3k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14219
14.0k
    {
14220
14.0k
        xmlXPathFreeParserContext(pctxt);
14221
14.0k
        return(NULL);
14222
14.0k
    }
14223
14224
7.25k
    if (*pctxt->cur != 0) {
14225
  /*
14226
   * aleksey: in some cases this line prints *second* error message
14227
   * (see bug #78858) and probably this should be fixed.
14228
   * However, we are not sure that all error messages are printed
14229
   * out in other places. It's not critical so we leave it as-is for now
14230
   */
14231
488
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14232
488
  comp = NULL;
14233
6.76k
    } else {
14234
6.76k
  comp = pctxt->comp;
14235
6.76k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14236
6.76k
            if (ctxt != NULL)
14237
6.76k
                oldDepth = ctxt->depth;
14238
6.76k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14239
6.76k
            if (ctxt != NULL)
14240
6.76k
                ctxt->depth = oldDepth;
14241
6.76k
  }
14242
6.76k
  pctxt->comp = NULL;
14243
6.76k
    }
14244
7.25k
    xmlXPathFreeParserContext(pctxt);
14245
14246
7.25k
    if (comp != NULL) {
14247
6.76k
  comp->expr = xmlStrdup(str);
14248
#ifdef DEBUG_EVAL_COUNTS
14249
  comp->string = xmlStrdup(str);
14250
  comp->nb = 0;
14251
#endif
14252
6.76k
    }
14253
7.25k
    return(comp);
14254
21.3k
}
14255
14256
/**
14257
 * xmlXPathCompile:
14258
 * @str:  the XPath expression
14259
 *
14260
 * Compile an XPath expression
14261
 *
14262
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14263
 *         the caller has to free the object.
14264
 */
14265
xmlXPathCompExprPtr
14266
0
xmlXPathCompile(const xmlChar *str) {
14267
0
    return(xmlXPathCtxtCompile(NULL, str));
14268
0
}
14269
14270
/**
14271
 * xmlXPathCompiledEvalInternal:
14272
 * @comp:  the compiled XPath expression
14273
 * @ctxt:  the XPath context
14274
 * @resObj: the resulting XPath object or NULL
14275
 * @toBool: 1 if only a boolean result is requested
14276
 *
14277
 * Evaluate the Precompiled XPath expression in the given context.
14278
 * The caller has to free @resObj.
14279
 *
14280
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14281
 *         the caller has to free the object.
14282
 */
14283
static int
14284
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14285
           xmlXPathContextPtr ctxt,
14286
           xmlXPathObjectPtr *resObjPtr,
14287
           int toBool)
14288
12.3k
{
14289
12.3k
    xmlXPathParserContextPtr pctxt;
14290
12.3k
    xmlXPathObjectPtr resObj;
14291
#ifndef LIBXML_THREAD_ENABLED
14292
    static int reentance = 0;
14293
#endif
14294
12.3k
    int res;
14295
14296
12.3k
    CHECK_CTXT_NEG(ctxt)
14297
14298
12.3k
    if (comp == NULL)
14299
0
  return(-1);
14300
12.3k
    xmlInitParser();
14301
14302
#ifndef LIBXML_THREAD_ENABLED
14303
    reentance++;
14304
    if (reentance > 1)
14305
  xmlXPathDisableOptimizer = 1;
14306
#endif
14307
14308
#ifdef DEBUG_EVAL_COUNTS
14309
    comp->nb++;
14310
    if ((comp->string != NULL) && (comp->nb > 100)) {
14311
  fprintf(stderr, "100 x %s\n", comp->string);
14312
  comp->nb = 0;
14313
    }
14314
#endif
14315
12.3k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14316
12.3k
    if (pctxt == NULL)
14317
0
        return(-1);
14318
12.3k
    res = xmlXPathRunEval(pctxt, toBool);
14319
14320
12.3k
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14321
142
        resObj = NULL;
14322
12.2k
    } else {
14323
12.2k
        resObj = valuePop(pctxt);
14324
12.2k
        if (resObj == NULL) {
14325
0
            if (!toBool)
14326
0
                xmlGenericError(xmlGenericErrorContext,
14327
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14328
12.2k
        } else if (pctxt->valueNr > 0) {
14329
0
            xmlGenericError(xmlGenericErrorContext,
14330
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14331
0
                pctxt->valueNr);
14332
0
        }
14333
12.2k
    }
14334
14335
12.3k
    if (resObjPtr)
14336
12.3k
        *resObjPtr = resObj;
14337
0
    else
14338
0
        xmlXPathReleaseObject(ctxt, resObj);
14339
14340
12.3k
    pctxt->comp = NULL;
14341
12.3k
    xmlXPathFreeParserContext(pctxt);
14342
#ifndef LIBXML_THREAD_ENABLED
14343
    reentance--;
14344
#endif
14345
14346
12.3k
    return(res);
14347
12.3k
}
14348
14349
/**
14350
 * xmlXPathCompiledEval:
14351
 * @comp:  the compiled XPath expression
14352
 * @ctx:  the XPath context
14353
 *
14354
 * Evaluate the Precompiled XPath expression in the given context.
14355
 *
14356
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14357
 *         the caller has to free the object.
14358
 */
14359
xmlXPathObjectPtr
14360
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14361
12.3k
{
14362
12.3k
    xmlXPathObjectPtr res = NULL;
14363
14364
12.3k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14365
12.3k
    return(res);
14366
12.3k
}
14367
14368
/**
14369
 * xmlXPathCompiledEvalToBoolean:
14370
 * @comp:  the compiled XPath expression
14371
 * @ctxt:  the XPath context
14372
 *
14373
 * Applies the XPath boolean() function on the result of the given
14374
 * compiled expression.
14375
 *
14376
 * Returns 1 if the expression evaluated to true, 0 if to false and
14377
 *         -1 in API and internal errors.
14378
 */
14379
int
14380
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14381
            xmlXPathContextPtr ctxt)
14382
0
{
14383
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14384
0
}
14385
14386
/**
14387
 * xmlXPathEvalExpr:
14388
 * @ctxt:  the XPath Parser context
14389
 *
14390
 * Parse and evaluate an XPath expression in the given context,
14391
 * then push the result on the context stack
14392
 */
14393
void
14394
152
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14395
152
#ifdef XPATH_STREAMING
14396
152
    xmlXPathCompExprPtr comp;
14397
152
#endif
14398
152
    int oldDepth = 0;
14399
14400
152
    if (ctxt == NULL) return;
14401
14402
152
#ifdef XPATH_STREAMING
14403
152
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14404
152
    if (comp != NULL) {
14405
0
        if (ctxt->comp != NULL)
14406
0
      xmlXPathFreeCompExpr(ctxt->comp);
14407
0
        ctxt->comp = comp;
14408
0
    } else
14409
152
#endif
14410
152
    {
14411
152
        if (ctxt->context != NULL)
14412
152
            oldDepth = ctxt->context->depth;
14413
152
  xmlXPathCompileExpr(ctxt, 1);
14414
152
        if (ctxt->context != NULL)
14415
152
            ctxt->context->depth = oldDepth;
14416
152
        CHECK_ERROR;
14417
14418
        /* Check for trailing characters. */
14419
152
        if (*ctxt->cur != 0)
14420
152
            XP_ERROR(XPATH_EXPR_ERROR);
14421
14422
152
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14423
152
            if (ctxt->context != NULL)
14424
152
                oldDepth = ctxt->context->depth;
14425
152
      xmlXPathOptimizeExpression(ctxt,
14426
152
    &ctxt->comp->steps[ctxt->comp->last]);
14427
152
            if (ctxt->context != NULL)
14428
152
                ctxt->context->depth = oldDepth;
14429
152
        }
14430
152
    }
14431
14432
152
    xmlXPathRunEval(ctxt, 0);
14433
152
}
14434
14435
/**
14436
 * xmlXPathEval:
14437
 * @str:  the XPath expression
14438
 * @ctx:  the XPath context
14439
 *
14440
 * Evaluate the XPath Location Path in the given context.
14441
 *
14442
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14443
 *         the caller has to free the object.
14444
 */
14445
xmlXPathObjectPtr
14446
152
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14447
152
    xmlXPathParserContextPtr ctxt;
14448
152
    xmlXPathObjectPtr res;
14449
14450
152
    CHECK_CTXT(ctx)
14451
14452
152
    xmlInitParser();
14453
14454
152
    ctxt = xmlXPathNewParserContext(str, ctx);
14455
152
    if (ctxt == NULL)
14456
0
        return NULL;
14457
152
    xmlXPathEvalExpr(ctxt);
14458
14459
152
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14460
0
  res = NULL;
14461
152
    } else {
14462
152
  res = valuePop(ctxt);
14463
152
        if (res == NULL) {
14464
0
            xmlGenericError(xmlGenericErrorContext,
14465
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14466
152
        } else if (ctxt->valueNr > 0) {
14467
0
            xmlGenericError(xmlGenericErrorContext,
14468
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14469
0
                ctxt->valueNr);
14470
0
        }
14471
152
    }
14472
14473
152
    xmlXPathFreeParserContext(ctxt);
14474
152
    return(res);
14475
152
}
14476
14477
/**
14478
 * xmlXPathSetContextNode:
14479
 * @node: the node to to use as the context node
14480
 * @ctx:  the XPath context
14481
 *
14482
 * Sets 'node' as the context node. The node must be in the same
14483
 * document as that associated with the context.
14484
 *
14485
 * Returns -1 in case of error or 0 if successful
14486
 */
14487
int
14488
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14489
0
    if ((node == NULL) || (ctx == NULL))
14490
0
        return(-1);
14491
14492
0
    if (node->doc == ctx->doc) {
14493
0
        ctx->node = node;
14494
0
  return(0);
14495
0
    }
14496
0
    return(-1);
14497
0
}
14498
14499
/**
14500
 * xmlXPathNodeEval:
14501
 * @node: the node to to use as the context node
14502
 * @str:  the XPath expression
14503
 * @ctx:  the XPath context
14504
 *
14505
 * Evaluate the XPath Location Path in the given context. The node 'node'
14506
 * is set as the context node. The context node is not restored.
14507
 *
14508
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14509
 *         the caller has to free the object.
14510
 */
14511
xmlXPathObjectPtr
14512
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14513
0
    if (str == NULL)
14514
0
        return(NULL);
14515
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14516
0
        return(NULL);
14517
0
    return(xmlXPathEval(str, ctx));
14518
0
}
14519
14520
/**
14521
 * xmlXPathEvalExpression:
14522
 * @str:  the XPath expression
14523
 * @ctxt:  the XPath context
14524
 *
14525
 * Alias for xmlXPathEval().
14526
 *
14527
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14528
 *         the caller has to free the object.
14529
 */
14530
xmlXPathObjectPtr
14531
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14532
0
    return(xmlXPathEval(str, ctxt));
14533
0
}
14534
14535
/************************************************************************
14536
 *                  *
14537
 *  Extra functions not pertaining to the XPath spec    *
14538
 *                  *
14539
 ************************************************************************/
14540
/**
14541
 * xmlXPathEscapeUriFunction:
14542
 * @ctxt:  the XPath Parser context
14543
 * @nargs:  the number of arguments
14544
 *
14545
 * Implement the escape-uri() XPath function
14546
 *    string escape-uri(string $str, bool $escape-reserved)
14547
 *
14548
 * This function applies the URI escaping rules defined in section 2 of [RFC
14549
 * 2396] to the string supplied as $uri-part, which typically represents all
14550
 * or part of a URI. The effect of the function is to replace any special
14551
 * character in the string by an escape sequence of the form %xx%yy...,
14552
 * where xxyy... is the hexadecimal representation of the octets used to
14553
 * represent the character in UTF-8.
14554
 *
14555
 * The set of characters that are escaped depends on the setting of the
14556
 * boolean argument $escape-reserved.
14557
 *
14558
 * If $escape-reserved is true, all characters are escaped other than lower
14559
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14560
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14561
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14562
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14563
 * A-F).
14564
 *
14565
 * If $escape-reserved is false, the behavior differs in that characters
14566
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14567
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14568
 *
14569
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14570
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14571
 * compared using string comparison functions, this function must always use
14572
 * the upper-case letters A-F.
14573
 *
14574
 * Generally, $escape-reserved should be set to true when escaping a string
14575
 * that is to form a single part of a URI, and to false when escaping an
14576
 * entire URI or URI reference.
14577
 *
14578
 * In the case of non-ascii characters, the string is encoded according to
14579
 * utf-8 and then converted according to RFC 2396.
14580
 *
14581
 * Examples
14582
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14583
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14584
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14585
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14586
 *
14587
 */
14588
static void
14589
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14590
0
    xmlXPathObjectPtr str;
14591
0
    int escape_reserved;
14592
0
    xmlBufPtr target;
14593
0
    xmlChar *cptr;
14594
0
    xmlChar escape[4];
14595
14596
0
    CHECK_ARITY(2);
14597
14598
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14599
14600
0
    CAST_TO_STRING;
14601
0
    str = valuePop(ctxt);
14602
14603
0
    target = xmlBufCreate();
14604
14605
0
    escape[0] = '%';
14606
0
    escape[3] = 0;
14607
14608
0
    if (target) {
14609
0
  for (cptr = str->stringval; *cptr; cptr++) {
14610
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14611
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14612
0
    (*cptr >= '0' && *cptr <= '9') ||
14613
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14614
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14615
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14616
0
    (*cptr == '%' &&
14617
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14618
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14619
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14620
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14621
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14622
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14623
0
    (!escape_reserved &&
14624
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14625
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14626
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14627
0
      *cptr == ','))) {
14628
0
    xmlBufAdd(target, cptr, 1);
14629
0
      } else {
14630
0
    if ((*cptr >> 4) < 10)
14631
0
        escape[1] = '0' + (*cptr >> 4);
14632
0
    else
14633
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14634
0
    if ((*cptr & 0xF) < 10)
14635
0
        escape[2] = '0' + (*cptr & 0xF);
14636
0
    else
14637
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14638
14639
0
    xmlBufAdd(target, &escape[0], 3);
14640
0
      }
14641
0
  }
14642
0
    }
14643
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14644
0
  xmlBufContent(target)));
14645
0
    xmlBufFree(target);
14646
0
    xmlXPathReleaseObject(ctxt->context, str);
14647
0
}
14648
14649
/**
14650
 * xmlXPathRegisterAllFunctions:
14651
 * @ctxt:  the XPath context
14652
 *
14653
 * Registers all default XPath functions in this context
14654
 */
14655
void
14656
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14657
155
{
14658
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14659
155
                         xmlXPathBooleanFunction);
14660
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14661
155
                         xmlXPathCeilingFunction);
14662
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14663
155
                         xmlXPathCountFunction);
14664
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14665
155
                         xmlXPathConcatFunction);
14666
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14667
155
                         xmlXPathContainsFunction);
14668
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14669
155
                         xmlXPathIdFunction);
14670
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14671
155
                         xmlXPathFalseFunction);
14672
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14673
155
                         xmlXPathFloorFunction);
14674
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14675
155
                         xmlXPathLastFunction);
14676
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14677
155
                         xmlXPathLangFunction);
14678
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14679
155
                         xmlXPathLocalNameFunction);
14680
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14681
155
                         xmlXPathNotFunction);
14682
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14683
155
                         xmlXPathNameFunction);
14684
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14685
155
                         xmlXPathNamespaceURIFunction);
14686
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14687
155
                         xmlXPathNormalizeFunction);
14688
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14689
155
                         xmlXPathNumberFunction);
14690
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14691
155
                         xmlXPathPositionFunction);
14692
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14693
155
                         xmlXPathRoundFunction);
14694
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14695
155
                         xmlXPathStringFunction);
14696
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14697
155
                         xmlXPathStringLengthFunction);
14698
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14699
155
                         xmlXPathStartsWithFunction);
14700
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14701
155
                         xmlXPathSubstringFunction);
14702
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14703
155
                         xmlXPathSubstringBeforeFunction);
14704
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14705
155
                         xmlXPathSubstringAfterFunction);
14706
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14707
155
                         xmlXPathSumFunction);
14708
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14709
155
                         xmlXPathTrueFunction);
14710
155
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14711
155
                         xmlXPathTranslateFunction);
14712
14713
155
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14714
155
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14715
155
                         xmlXPathEscapeUriFunction);
14716
155
}
14717
14718
#endif /* LIBXML_XPATH_ENABLED */