Coverage Report

Created: 2025-01-16 12:50

/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
20
    xmlGenericError(xmlGenericErrorContext,       \
62
20
      "Unimplemented block at %s:%d\n",       \
63
20
            __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
13.8k
#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
134
#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
166k
#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
3.74M
#define XPATH_MAX_RECURSION_DEPTH 500
134
#elif defined(_WIN32)
135
/* Windows typically limits stack size to 1MB. */
136
#define XPATH_MAX_RECURSION_DEPTH 1000
137
#else
138
#define XPATH_MAX_RECURSION_DEPTH 5000
139
#endif
140
141
/*
142
 * TODO:
143
 * There are a few spots where some tests are done which depend upon ascii
144
 * data.  These should be enhanced for full UTF8 support (see particularly
145
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146
 */
147
148
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
149
/**
150
 * xmlXPathCmpNodesExt:
151
 * @node1:  the first node
152
 * @node2:  the second node
153
 *
154
 * Compare two nodes w.r.t document order.
155
 * This one is optimized for handling of non-element nodes.
156
 *
157
 * Returns -2 in case of error 1 if first point < second point, 0 if
158
 *         it's the same node, -1 otherwise
159
 */
160
static int
161
1.71M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
162
1.71M
    int depth1, depth2;
163
1.71M
    int misc = 0, precedence1 = 0, precedence2 = 0;
164
1.71M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
165
1.71M
    xmlNodePtr cur, root;
166
1.71M
    ptrdiff_t l1, l2;
167
168
1.71M
    if ((node1 == NULL) || (node2 == NULL))
169
0
  return(-2);
170
171
1.71M
    if (node1 == node2)
172
0
  return(0);
173
174
    /*
175
     * a couple of optimizations which will avoid computations in most cases
176
     */
177
1.71M
    switch (node1->type) {
178
1.25M
  case XML_ELEMENT_NODE:
179
1.25M
      if (node2->type == XML_ELEMENT_NODE) {
180
1.14M
    if ((0 > (ptrdiff_t) node1->content) &&
181
1.14M
        (0 > (ptrdiff_t) node2->content) &&
182
1.14M
        (node1->doc == node2->doc))
183
189k
    {
184
189k
        l1 = -((ptrdiff_t) node1->content);
185
189k
        l2 = -((ptrdiff_t) node2->content);
186
189k
        if (l1 < l2)
187
162k
      return(1);
188
27.8k
        if (l1 > l2)
189
27.8k
      return(-1);
190
27.8k
    } else
191
952k
        goto turtle_comparison;
192
1.14M
      }
193
116k
      break;
194
116k
  case XML_ATTRIBUTE_NODE:
195
1.65k
      precedence1 = 1; /* element is owner */
196
1.65k
      miscNode1 = node1;
197
1.65k
      node1 = node1->parent;
198
1.65k
      misc = 1;
199
1.65k
      break;
200
396k
  case XML_TEXT_NODE:
201
406k
  case XML_CDATA_SECTION_NODE:
202
420k
  case XML_COMMENT_NODE:
203
434k
  case XML_PI_NODE: {
204
434k
      miscNode1 = node1;
205
      /*
206
      * Find nearest element node.
207
      */
208
434k
      if (node1->prev != NULL) {
209
205k
    do {
210
205k
        node1 = node1->prev;
211
205k
        if (node1->type == XML_ELEMENT_NODE) {
212
142k
      precedence1 = 3; /* element in prev-sibl axis */
213
142k
      break;
214
142k
        }
215
63.2k
        if (node1->prev == NULL) {
216
0
      precedence1 = 2; /* element is parent */
217
      /*
218
      * URGENT TODO: Are there any cases, where the
219
      * parent of such a node is not an element node?
220
      */
221
0
      node1 = node1->parent;
222
0
      break;
223
0
        }
224
63.2k
    } while (1);
225
292k
      } else {
226
292k
    precedence1 = 2; /* element is parent */
227
292k
    node1 = node1->parent;
228
292k
      }
229
434k
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
230
434k
    (0 <= (ptrdiff_t) node1->content)) {
231
    /*
232
    * Fallback for whatever case.
233
    */
234
203k
    node1 = miscNode1;
235
203k
    precedence1 = 0;
236
203k
      } else
237
231k
    misc = 1;
238
434k
  }
239
0
      break;
240
20.8k
  case XML_NAMESPACE_DECL:
241
      /*
242
      * TODO: why do we return 1 for namespace nodes?
243
      */
244
20.8k
      return(1);
245
3.64k
  default:
246
3.64k
      break;
247
1.71M
    }
248
556k
    switch (node2->type) {
249
118k
  case XML_ELEMENT_NODE:
250
118k
      break;
251
3.22k
  case XML_ATTRIBUTE_NODE:
252
3.22k
      precedence2 = 1; /* element is owner */
253
3.22k
      miscNode2 = node2;
254
3.22k
      node2 = node2->parent;
255
3.22k
      misc = 1;
256
3.22k
      break;
257
374k
  case XML_TEXT_NODE:
258
383k
  case XML_CDATA_SECTION_NODE:
259
398k
  case XML_COMMENT_NODE:
260
409k
  case XML_PI_NODE: {
261
409k
      miscNode2 = node2;
262
409k
      if (node2->prev != NULL) {
263
189k
    do {
264
189k
        node2 = node2->prev;
265
189k
        if (node2->type == XML_ELEMENT_NODE) {
266
124k
      precedence2 = 3; /* element in prev-sibl axis */
267
124k
      break;
268
124k
        }
269
64.7k
        if (node2->prev == NULL) {
270
0
      precedence2 = 2; /* element is parent */
271
0
      node2 = node2->parent;
272
0
      break;
273
0
        }
274
64.7k
    } while (1);
275
285k
      } else {
276
285k
    precedence2 = 2; /* element is parent */
277
285k
    node2 = node2->parent;
278
285k
      }
279
409k
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
280
409k
    (0 <= (ptrdiff_t) node2->content))
281
206k
      {
282
206k
    node2 = miscNode2;
283
206k
    precedence2 = 0;
284
206k
      } else
285
202k
    misc = 1;
286
409k
  }
287
0
      break;
288
925
  case XML_NAMESPACE_DECL:
289
925
      return(1);
290
24.2k
  default:
291
24.2k
      break;
292
556k
    }
293
555k
    if (misc) {
294
320k
  if (node1 == node2) {
295
132k
      if (precedence1 == precedence2) {
296
    /*
297
    * The ugly case; but normally there aren't many
298
    * adjacent non-element nodes around.
299
    */
300
30.3k
    cur = miscNode2->prev;
301
33.5k
    while (cur != NULL) {
302
33.5k
        if (cur == miscNode1)
303
27.0k
      return(1);
304
6.49k
        if (cur->type == XML_ELEMENT_NODE)
305
3.25k
      return(-1);
306
3.24k
        cur = cur->prev;
307
3.24k
    }
308
4
    return (-1);
309
101k
      } else {
310
    /*
311
    * Evaluate based on higher precedence wrt to the element.
312
    * TODO: This assumes attributes are sorted before content.
313
    *   Is this 100% correct?
314
    */
315
101k
    if (precedence1 < precedence2)
316
82.5k
        return(1);
317
19.1k
    else
318
19.1k
        return(-1);
319
101k
      }
320
132k
  }
321
  /*
322
  * Special case: One of the helper-elements is contained by the other.
323
  * <foo>
324
  *   <node2>
325
  *     <node1>Text-1(precedence1 == 2)</node1>
326
  *   </node2>
327
  *   Text-6(precedence2 == 3)
328
  * </foo>
329
  */
330
188k
  if ((precedence2 == 3) && (precedence1 > 1)) {
331
29.5k
      cur = node1->parent;
332
82.8k
      while (cur) {
333
61.7k
    if (cur == node2)
334
8.44k
        return(1);
335
53.3k
    cur = cur->parent;
336
53.3k
      }
337
29.5k
  }
338
179k
  if ((precedence1 == 3) && (precedence2 > 1)) {
339
26.0k
      cur = node2->parent;
340
73.7k
      while (cur) {
341
56.1k
    if (cur == node1)
342
8.57k
        return(-1);
343
47.6k
    cur = cur->parent;
344
47.6k
      }
345
26.0k
  }
346
179k
    }
347
348
    /*
349
     * Speedup using document order if available.
350
     */
351
406k
    if ((node1->type == XML_ELEMENT_NODE) &&
352
406k
  (node2->type == XML_ELEMENT_NODE) &&
353
406k
  (0 > (ptrdiff_t) node1->content) &&
354
406k
  (0 > (ptrdiff_t) node2->content) &&
355
406k
  (node1->doc == node2->doc)) {
356
357
153k
  l1 = -((ptrdiff_t) node1->content);
358
153k
  l2 = -((ptrdiff_t) node2->content);
359
153k
  if (l1 < l2)
360
85.2k
      return(1);
361
68.2k
  if (l1 > l2)
362
68.2k
      return(-1);
363
68.2k
    }
364
365
1.20M
turtle_comparison:
366
367
1.20M
    if (node1 == node2->prev)
368
934k
  return(1);
369
270k
    if (node1 == node2->next)
370
6.97k
  return(-1);
371
    /*
372
     * compute depth to root
373
     */
374
694k
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
375
439k
  if (cur->parent == node1)
376
9.67k
      return(1);
377
430k
  depth2++;
378
430k
    }
379
254k
    root = cur;
380
710k
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
381
487k
  if (cur->parent == node2)
382
30.7k
      return(-1);
383
456k
  depth1++;
384
456k
    }
385
    /*
386
     * Distinct document (or distinct entities :-( ) case.
387
     */
388
223k
    if (root != cur) {
389
1.41k
  return(-2);
390
1.41k
    }
391
    /*
392
     * get the nearest common ancestor.
393
     */
394
234k
    while (depth1 > depth2) {
395
11.9k
  depth1--;
396
11.9k
  node1 = node1->parent;
397
11.9k
    }
398
237k
    while (depth2 > depth1) {
399
15.0k
  depth2--;
400
15.0k
  node2 = node2->parent;
401
15.0k
    }
402
404k
    while (node1->parent != node2->parent) {
403
182k
  node1 = node1->parent;
404
182k
  node2 = node2->parent;
405
  /* should not happen but just in case ... */
406
182k
  if ((node1 == NULL) || (node2 == NULL))
407
0
      return(-2);
408
182k
    }
409
    /*
410
     * Find who's first.
411
     */
412
222k
    if (node1 == node2->prev)
413
176k
  return(1);
414
45.8k
    if (node1 == node2->next)
415
7.18k
  return(-1);
416
    /*
417
     * Speedup using document order if available.
418
     */
419
38.6k
    if ((node1->type == XML_ELEMENT_NODE) &&
420
38.6k
  (node2->type == XML_ELEMENT_NODE) &&
421
38.6k
  (0 > (ptrdiff_t) node1->content) &&
422
38.6k
  (0 > (ptrdiff_t) node2->content) &&
423
38.6k
  (node1->doc == node2->doc)) {
424
425
0
  l1 = -((ptrdiff_t) node1->content);
426
0
  l2 = -((ptrdiff_t) node2->content);
427
0
  if (l1 < l2)
428
0
      return(1);
429
0
  if (l1 > l2)
430
0
      return(-1);
431
0
    }
432
433
3.32M
    for (cur = node1->next;cur != NULL;cur = cur->next)
434
3.30M
  if (cur == node2)
435
18.2k
      return(1);
436
20.3k
    return(-1); /* assume there is no sibling list corruption */
437
38.6k
}
438
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
439
440
/*
441
 * Wrapper for the Timsort algorithm from timsort.h
442
 */
443
#ifdef WITH_TIM_SORT
444
#define SORT_NAME libxml_domnode
445
434k
#define SORT_TYPE xmlNodePtr
446
/**
447
 * wrap_cmp:
448
 * @x: a node
449
 * @y: another node
450
 *
451
 * Comparison function for the Timsort implementation
452
 *
453
 * Returns -2 in case of error -1 if first point < second point, 0 if
454
 *         it's the same node, +1 otherwise
455
 */
456
static
457
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
458
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
459
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
460
1.71M
    {
461
1.71M
        int res = xmlXPathCmpNodesExt(x, y);
462
1.71M
        return res == -2 ? res : -res;
463
1.71M
    }
464
#else
465
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
466
    {
467
        int res = xmlXPathCmpNodes(x, y);
468
        return res == -2 ? res : -res;
469
    }
470
#endif
471
1.71M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
472
#include "timsort.h"
473
#endif /* WITH_TIM_SORT */
474
475
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
476
477
/************************************************************************
478
 *                  *
479
 *      Floating point stuff        *
480
 *                  *
481
 ************************************************************************/
482
483
double xmlXPathNAN = 0.0;
484
double xmlXPathPINF = 0.0;
485
double xmlXPathNINF = 0.0;
486
487
/**
488
 * xmlXPathInit:
489
 *
490
 * DEPRECATED: Alias for xmlInitParser.
491
 */
492
void
493
0
xmlXPathInit(void) {
494
0
    xmlInitParser();
495
0
}
496
497
/**
498
 * xmlInitXPathInternal:
499
 *
500
 * Initialize the XPath environment
501
 */
502
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
503
void
504
88
xmlInitXPathInternal(void) {
505
88
#if defined(NAN) && defined(INFINITY)
506
88
    xmlXPathNAN = NAN;
507
88
    xmlXPathPINF = INFINITY;
508
88
    xmlXPathNINF = -INFINITY;
509
#else
510
    /* MSVC doesn't allow division by zero in constant expressions. */
511
    double zero = 0.0;
512
    xmlXPathNAN = 0.0 / zero;
513
    xmlXPathPINF = 1.0 / zero;
514
    xmlXPathNINF = -xmlXPathPINF;
515
#endif
516
88
}
517
518
/**
519
 * xmlXPathIsNaN:
520
 * @val:  a double value
521
 *
522
 * Returns 1 if the value is a NaN, 0 otherwise
523
 */
524
int
525
573k
xmlXPathIsNaN(double val) {
526
573k
#ifdef isnan
527
573k
    return isnan(val);
528
#else
529
    return !(val == val);
530
#endif
531
573k
}
532
533
/**
534
 * xmlXPathIsInf:
535
 * @val:  a double value
536
 *
537
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
538
 */
539
int
540
569k
xmlXPathIsInf(double val) {
541
569k
#ifdef isinf
542
569k
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
543
#else
544
    if (val >= xmlXPathPINF)
545
        return 1;
546
    if (val <= -xmlXPathPINF)
547
        return -1;
548
    return 0;
549
#endif
550
569k
}
551
552
#endif /* SCHEMAS or XPATH */
553
554
#ifdef LIBXML_XPATH_ENABLED
555
556
/*
557
 * TODO: when compatibility allows remove all "fake node libxslt" strings
558
 *       the test should just be name[0] = ' '
559
 */
560
#ifdef DEBUG_XPATH_EXPRESSION
561
#define DEBUG_STEP
562
#define DEBUG_EXPR
563
#define DEBUG_EVAL_COUNTS
564
#endif
565
566
static xmlNs xmlXPathXMLNamespaceStruct = {
567
    NULL,
568
    XML_NAMESPACE_DECL,
569
    XML_XML_NAMESPACE,
570
    BAD_CAST "xml",
571
    NULL,
572
    NULL
573
};
574
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
575
#ifndef LIBXML_THREAD_ENABLED
576
/*
577
 * Optimizer is disabled only when threaded apps are detected while
578
 * the library ain't compiled for thread safety.
579
 */
580
static int xmlXPathDisableOptimizer = 0;
581
#endif
582
583
/************************************************************************
584
 *                  *
585
 *      Error handling routines       *
586
 *                  *
587
 ************************************************************************/
588
589
/**
590
 * XP_ERRORNULL:
591
 * @X:  the error code
592
 *
593
 * Macro to raise an XPath error and return NULL.
594
 */
595
#define XP_ERRORNULL(X)             \
596
1.57k
    { xmlXPathErr(ctxt, X); return(NULL); }
597
598
/*
599
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
600
 */
601
static const char* const xmlXPathErrorMessages[] = {
602
    "Ok\n",
603
    "Number encoding\n",
604
    "Unfinished literal\n",
605
    "Start of literal\n",
606
    "Expected $ for variable reference\n",
607
    "Undefined variable\n",
608
    "Invalid predicate\n",
609
    "Invalid expression\n",
610
    "Missing closing curly brace\n",
611
    "Unregistered function\n",
612
    "Invalid operand\n",
613
    "Invalid type\n",
614
    "Invalid number of arguments\n",
615
    "Invalid context size\n",
616
    "Invalid context position\n",
617
    "Memory allocation error\n",
618
    "Syntax error\n",
619
    "Resource error\n",
620
    "Sub resource error\n",
621
    "Undefined namespace prefix\n",
622
    "Encoding error\n",
623
    "Char out of XML range\n",
624
    "Invalid or incomplete context\n",
625
    "Stack usage error\n",
626
    "Forbidden variable\n",
627
    "Operation limit exceeded\n",
628
    "Recursion limit exceeded\n",
629
    "?? Unknown error ??\n" /* Must be last in the list! */
630
};
631
2.60M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
632
2.60M
       sizeof(xmlXPathErrorMessages[0])) - 1)
633
/**
634
 * xmlXPathErrMemory:
635
 * @ctxt:  an XPath context
636
 * @extra:  extra information
637
 *
638
 * Handle a redefinition of attribute error
639
 */
640
static void
641
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
642
0
{
643
0
    if (ctxt != NULL) {
644
0
        xmlResetError(&ctxt->lastError);
645
0
        if (extra) {
646
0
            xmlChar buf[200];
647
648
0
            xmlStrPrintf(buf, 200,
649
0
                         "Memory allocation failed : %s\n",
650
0
                         extra);
651
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
652
0
        } else {
653
0
            ctxt->lastError.message = (char *)
654
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
655
0
        }
656
0
        ctxt->lastError.domain = XML_FROM_XPATH;
657
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
658
0
  if (ctxt->error != NULL)
659
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
660
0
    } else {
661
0
        if (extra)
662
0
            __xmlRaiseError(NULL, NULL, NULL,
663
0
                            NULL, NULL, XML_FROM_XPATH,
664
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665
0
                            extra, NULL, NULL, 0, 0,
666
0
                            "Memory allocation failed : %s\n", extra);
667
0
        else
668
0
            __xmlRaiseError(NULL, NULL, NULL,
669
0
                            NULL, NULL, XML_FROM_XPATH,
670
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671
0
                            NULL, NULL, NULL, 0, 0,
672
0
                            "Memory allocation failed\n");
673
0
    }
674
0
}
675
676
/**
677
 * xmlXPathPErrMemory:
678
 * @ctxt:  an XPath parser context
679
 * @extra:  extra information
680
 *
681
 * Handle a redefinition of attribute error
682
 */
683
static void
684
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685
0
{
686
0
    if (ctxt == NULL)
687
0
  xmlXPathErrMemory(NULL, extra);
688
0
    else {
689
0
  ctxt->error = XPATH_MEMORY_ERROR;
690
0
  xmlXPathErrMemory(ctxt->context, extra);
691
0
    }
692
0
}
693
694
/**
695
 * xmlXPathErr:
696
 * @ctxt:  a XPath parser context
697
 * @error:  the error code
698
 *
699
 * Handle an XPath error
700
 */
701
void
702
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703
2.60M
{
704
2.60M
    if ((error < 0) || (error > MAXERRNO))
705
0
  error = MAXERRNO;
706
2.60M
    if (ctxt == NULL) {
707
0
  __xmlRaiseError(NULL, NULL, NULL,
708
0
      NULL, NULL, XML_FROM_XPATH,
709
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710
0
      XML_ERR_ERROR, NULL, 0,
711
0
      NULL, NULL, NULL, 0, 0,
712
0
      "%s", xmlXPathErrorMessages[error]);
713
0
  return;
714
0
    }
715
2.60M
    ctxt->error = error;
716
2.60M
    if (ctxt->context == NULL) {
717
0
  __xmlRaiseError(NULL, NULL, NULL,
718
0
      NULL, NULL, XML_FROM_XPATH,
719
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720
0
      XML_ERR_ERROR, NULL, 0,
721
0
      (const char *) ctxt->base, NULL, NULL,
722
0
      ctxt->cur - ctxt->base, 0,
723
0
      "%s", xmlXPathErrorMessages[error]);
724
0
  return;
725
0
    }
726
727
    /* cleanup current last error */
728
2.60M
    xmlResetError(&ctxt->context->lastError);
729
730
2.60M
    ctxt->context->lastError.domain = XML_FROM_XPATH;
731
2.60M
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732
2.60M
                           XPATH_EXPRESSION_OK;
733
2.60M
    ctxt->context->lastError.level = XML_ERR_ERROR;
734
2.60M
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735
2.60M
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736
2.60M
    ctxt->context->lastError.node = ctxt->context->debugNode;
737
2.60M
    if (ctxt->context->error != NULL) {
738
0
  ctxt->context->error(ctxt->context->userData,
739
0
                       &ctxt->context->lastError);
740
2.60M
    } else {
741
2.60M
  __xmlRaiseError(NULL, NULL, NULL,
742
2.60M
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743
2.60M
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744
2.60M
      XML_ERR_ERROR, NULL, 0,
745
2.60M
      (const char *) ctxt->base, NULL, NULL,
746
2.60M
      ctxt->cur - ctxt->base, 0,
747
2.60M
      "%s", xmlXPathErrorMessages[error]);
748
2.60M
    }
749
750
2.60M
}
751
752
/**
753
 * xmlXPatherror:
754
 * @ctxt:  the XPath Parser context
755
 * @file:  the file name
756
 * @line:  the line number
757
 * @no:  the error number
758
 *
759
 * Formats an error message.
760
 */
761
void
762
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763
1.96k
              int line ATTRIBUTE_UNUSED, int no) {
764
1.96k
    xmlXPathErr(ctxt, no);
765
1.96k
}
766
767
/**
768
 * xmlXPathCheckOpLimit:
769
 * @ctxt:  the XPath Parser context
770
 * @opCount:  the number of operations to be added
771
 *
772
 * Adds opCount to the running total of operations and returns -1 if the
773
 * operation limit is exceeded. Returns 0 otherwise.
774
 */
775
static int
776
27.9M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
777
27.9M
    xmlXPathContextPtr xpctxt = ctxt->context;
778
779
27.9M
    if ((opCount > xpctxt->opLimit) ||
780
27.9M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
781
25
        xpctxt->opCount = xpctxt->opLimit;
782
25
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
783
25
        return(-1);
784
25
    }
785
786
27.9M
    xpctxt->opCount += opCount;
787
27.9M
    return(0);
788
27.9M
}
789
790
#define OP_LIMIT_EXCEEDED(ctxt, n) \
791
27.9M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
792
793
/************************************************************************
794
 *                  *
795
 *      Utilities         *
796
 *                  *
797
 ************************************************************************/
798
799
/**
800
 * xsltPointerList:
801
 *
802
 * Pointer-list for various purposes.
803
 */
804
typedef struct _xmlPointerList xmlPointerList;
805
typedef xmlPointerList *xmlPointerListPtr;
806
struct _xmlPointerList {
807
    void **items;
808
    int number;
809
    int size;
810
};
811
/*
812
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
813
* and here, we should make the functions public.
814
*/
815
static int
816
xmlPointerListAddSize(xmlPointerListPtr list,
817
           void *item,
818
           int initialSize)
819
3.32M
{
820
3.32M
    if (list->items == NULL) {
821
18.7k
  if (initialSize <= 0)
822
0
      initialSize = 1;
823
18.7k
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
824
18.7k
  if (list->items == NULL) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListCreate: allocating item\n");
827
0
      return(-1);
828
0
  }
829
18.7k
  list->number = 0;
830
18.7k
  list->size = initialSize;
831
3.30M
    } else if (list->size <= list->number) {
832
7.27k
        if (list->size > 50000000) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
            return(-1);
836
0
        }
837
7.27k
  list->size *= 2;
838
7.27k
  list->items = (void **) xmlRealloc(list->items,
839
7.27k
      list->size * sizeof(void *));
840
7.27k
  if (list->items == NULL) {
841
0
      xmlXPathErrMemory(NULL,
842
0
    "xmlPointerListAddSize: re-allocating item\n");
843
0
      list->size = 0;
844
0
      return(-1);
845
0
  }
846
7.27k
    }
847
3.32M
    list->items[list->number++] = item;
848
3.32M
    return(0);
849
3.32M
}
850
851
/**
852
 * xsltPointerListCreate:
853
 *
854
 * Creates an xsltPointerList structure.
855
 *
856
 * Returns a xsltPointerList structure or NULL in case of an error.
857
 */
858
static xmlPointerListPtr
859
xmlPointerListCreate(int initialSize)
860
18.7k
{
861
18.7k
    xmlPointerListPtr ret;
862
863
18.7k
    ret = xmlMalloc(sizeof(xmlPointerList));
864
18.7k
    if (ret == NULL) {
865
0
  xmlXPathErrMemory(NULL,
866
0
      "xmlPointerListCreate: allocating item\n");
867
0
  return (NULL);
868
0
    }
869
18.7k
    memset(ret, 0, sizeof(xmlPointerList));
870
18.7k
    if (initialSize > 0) {
871
18.7k
  xmlPointerListAddSize(ret, NULL, initialSize);
872
18.7k
  ret->number = 0;
873
18.7k
    }
874
18.7k
    return (ret);
875
18.7k
}
876
877
/**
878
 * xsltPointerListFree:
879
 *
880
 * Frees the xsltPointerList structure. This does not free
881
 * the content of the list.
882
 */
883
static void
884
xmlPointerListFree(xmlPointerListPtr list)
885
18.6k
{
886
18.6k
    if (list == NULL)
887
0
  return;
888
18.6k
    if (list->items != NULL)
889
18.6k
  xmlFree(list->items);
890
18.6k
    xmlFree(list);
891
18.6k
}
892
893
/************************************************************************
894
 *                  *
895
 *      Parser Types          *
896
 *                  *
897
 ************************************************************************/
898
899
/*
900
 * Types are private:
901
 */
902
903
typedef enum {
904
    XPATH_OP_END=0,
905
    XPATH_OP_AND,
906
    XPATH_OP_OR,
907
    XPATH_OP_EQUAL,
908
    XPATH_OP_CMP,
909
    XPATH_OP_PLUS,
910
    XPATH_OP_MULT,
911
    XPATH_OP_UNION,
912
    XPATH_OP_ROOT,
913
    XPATH_OP_NODE,
914
    XPATH_OP_COLLECT,
915
    XPATH_OP_VALUE, /* 11 */
916
    XPATH_OP_VARIABLE,
917
    XPATH_OP_FUNCTION,
918
    XPATH_OP_ARG,
919
    XPATH_OP_PREDICATE,
920
    XPATH_OP_FILTER, /* 16 */
921
    XPATH_OP_SORT /* 17 */
922
#ifdef LIBXML_XPTR_LOCS_ENABLED
923
    ,XPATH_OP_RANGETO
924
#endif
925
} xmlXPathOp;
926
927
typedef enum {
928
    AXIS_ANCESTOR = 1,
929
    AXIS_ANCESTOR_OR_SELF,
930
    AXIS_ATTRIBUTE,
931
    AXIS_CHILD,
932
    AXIS_DESCENDANT,
933
    AXIS_DESCENDANT_OR_SELF,
934
    AXIS_FOLLOWING,
935
    AXIS_FOLLOWING_SIBLING,
936
    AXIS_NAMESPACE,
937
    AXIS_PARENT,
938
    AXIS_PRECEDING,
939
    AXIS_PRECEDING_SIBLING,
940
    AXIS_SELF
941
} xmlXPathAxisVal;
942
943
typedef enum {
944
    NODE_TEST_NONE = 0,
945
    NODE_TEST_TYPE = 1,
946
    NODE_TEST_PI = 2,
947
    NODE_TEST_ALL = 3,
948
    NODE_TEST_NS = 4,
949
    NODE_TEST_NAME = 5
950
} xmlXPathTestVal;
951
952
typedef enum {
953
    NODE_TYPE_NODE = 0,
954
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
955
    NODE_TYPE_TEXT = XML_TEXT_NODE,
956
    NODE_TYPE_PI = XML_PI_NODE
957
} xmlXPathTypeVal;
958
959
typedef struct _xmlXPathStepOp xmlXPathStepOp;
960
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
961
struct _xmlXPathStepOp {
962
    xmlXPathOp op;    /* The identifier of the operation */
963
    int ch1;      /* First child */
964
    int ch2;      /* Second child */
965
    int value;
966
    int value2;
967
    int value3;
968
    void *value4;
969
    void *value5;
970
    xmlXPathFunction cache;
971
    void *cacheURI;
972
};
973
974
struct _xmlXPathCompExpr {
975
    int nbStep;     /* Number of steps in this expression */
976
    int maxStep;    /* Maximum number of steps allocated */
977
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
978
    int last;     /* index of last step in expression */
979
    xmlChar *expr;    /* the expression being computed */
980
    xmlDictPtr dict;    /* the dictionary to use if any */
981
#ifdef DEBUG_EVAL_COUNTS
982
    int nb;
983
    xmlChar *string;
984
#endif
985
#ifdef XPATH_STREAMING
986
    xmlPatternPtr stream;
987
#endif
988
};
989
990
/************************************************************************
991
 *                  *
992
 *      Forward declarations        *
993
 *                  *
994
 ************************************************************************/
995
static void
996
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
997
static void
998
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
999
static int
1000
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1001
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1002
static int
1003
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1004
          xmlXPathStepOpPtr op,
1005
          int isPredicate);
1006
static void
1007
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1008
1009
/************************************************************************
1010
 *                  *
1011
 *      Parser Type functions       *
1012
 *                  *
1013
 ************************************************************************/
1014
1015
/**
1016
 * xmlXPathNewCompExpr:
1017
 *
1018
 * Create a new Xpath component
1019
 *
1020
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1021
 */
1022
static xmlXPathCompExprPtr
1023
366k
xmlXPathNewCompExpr(void) {
1024
366k
    xmlXPathCompExprPtr cur;
1025
1026
366k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1027
366k
    if (cur == NULL) {
1028
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1029
0
  return(NULL);
1030
0
    }
1031
366k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1032
366k
    cur->maxStep = 10;
1033
366k
    cur->nbStep = 0;
1034
366k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1035
366k
                                     sizeof(xmlXPathStepOp));
1036
366k
    if (cur->steps == NULL) {
1037
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1038
0
  xmlFree(cur);
1039
0
  return(NULL);
1040
0
    }
1041
366k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1042
366k
    cur->last = -1;
1043
#ifdef DEBUG_EVAL_COUNTS
1044
    cur->nb = 0;
1045
#endif
1046
366k
    return(cur);
1047
366k
}
1048
1049
/**
1050
 * xmlXPathFreeCompExpr:
1051
 * @comp:  an XPATH comp
1052
 *
1053
 * Free up the memory allocated by @comp
1054
 */
1055
void
1056
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1057
366k
{
1058
366k
    xmlXPathStepOpPtr op;
1059
366k
    int i;
1060
1061
366k
    if (comp == NULL)
1062
0
        return;
1063
366k
    if (comp->dict == NULL) {
1064
3.90M
  for (i = 0; i < comp->nbStep; i++) {
1065
3.54M
      op = &comp->steps[i];
1066
3.54M
      if (op->value4 != NULL) {
1067
59.5k
    if (op->op == XPATH_OP_VALUE)
1068
38.2k
        xmlXPathFreeObject(op->value4);
1069
21.2k
    else
1070
21.2k
        xmlFree(op->value4);
1071
59.5k
      }
1072
3.54M
      if (op->value5 != NULL)
1073
149k
    xmlFree(op->value5);
1074
3.54M
  }
1075
366k
    } else {
1076
0
  for (i = 0; i < comp->nbStep; i++) {
1077
0
      op = &comp->steps[i];
1078
0
      if (op->value4 != NULL) {
1079
0
    if (op->op == XPATH_OP_VALUE)
1080
0
        xmlXPathFreeObject(op->value4);
1081
0
      }
1082
0
  }
1083
0
        xmlDictFree(comp->dict);
1084
0
    }
1085
366k
    if (comp->steps != NULL) {
1086
366k
        xmlFree(comp->steps);
1087
366k
    }
1088
#ifdef DEBUG_EVAL_COUNTS
1089
    if (comp->string != NULL) {
1090
        xmlFree(comp->string);
1091
    }
1092
#endif
1093
366k
#ifdef XPATH_STREAMING
1094
366k
    if (comp->stream != NULL) {
1095
623
        xmlFreePatternList(comp->stream);
1096
623
    }
1097
366k
#endif
1098
366k
    if (comp->expr != NULL) {
1099
11.8k
        xmlFree(comp->expr);
1100
11.8k
    }
1101
1102
366k
    xmlFree(comp);
1103
366k
}
1104
1105
/**
1106
 * xmlXPathCompExprAdd:
1107
 * @comp:  the compiled expression
1108
 * @ch1: first child index
1109
 * @ch2: second child index
1110
 * @op:  an op
1111
 * @value:  the first int value
1112
 * @value2:  the second int value
1113
 * @value3:  the third int value
1114
 * @value4:  the first string value
1115
 * @value5:  the second string value
1116
 *
1117
 * Add a step to an XPath Compiled Expression
1118
 *
1119
 * Returns -1 in case of failure, the index otherwise
1120
 */
1121
static int
1122
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1123
   xmlXPathOp op, int value,
1124
3.54M
   int value2, int value3, void *value4, void *value5) {
1125
3.54M
    xmlXPathCompExprPtr comp = ctxt->comp;
1126
3.54M
    if (comp->nbStep >= comp->maxStep) {
1127
13.8k
  xmlXPathStepOp *real;
1128
1129
13.8k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
        }
1133
13.8k
  comp->maxStep *= 2;
1134
13.8k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1135
13.8k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1136
13.8k
  if (real == NULL) {
1137
0
      comp->maxStep /= 2;
1138
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1139
0
      return(-1);
1140
0
  }
1141
13.8k
  comp->steps = real;
1142
13.8k
    }
1143
3.54M
    comp->last = comp->nbStep;
1144
3.54M
    comp->steps[comp->nbStep].ch1 = ch1;
1145
3.54M
    comp->steps[comp->nbStep].ch2 = ch2;
1146
3.54M
    comp->steps[comp->nbStep].op = op;
1147
3.54M
    comp->steps[comp->nbStep].value = value;
1148
3.54M
    comp->steps[comp->nbStep].value2 = value2;
1149
3.54M
    comp->steps[comp->nbStep].value3 = value3;
1150
3.54M
    if ((comp->dict != NULL) &&
1151
3.54M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1152
0
   (op == XPATH_OP_COLLECT))) {
1153
0
        if (value4 != NULL) {
1154
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1155
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1156
0
      xmlFree(value4);
1157
0
  } else
1158
0
      comp->steps[comp->nbStep].value4 = NULL;
1159
0
        if (value5 != NULL) {
1160
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1161
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1162
0
      xmlFree(value5);
1163
0
  } else
1164
0
      comp->steps[comp->nbStep].value5 = NULL;
1165
3.54M
    } else {
1166
3.54M
  comp->steps[comp->nbStep].value4 = value4;
1167
3.54M
  comp->steps[comp->nbStep].value5 = value5;
1168
3.54M
    }
1169
3.54M
    comp->steps[comp->nbStep].cache = NULL;
1170
3.54M
    return(comp->nbStep++);
1171
3.54M
}
1172
1173
/**
1174
 * xmlXPathCompSwap:
1175
 * @comp:  the compiled expression
1176
 * @op: operation index
1177
 *
1178
 * Swaps 2 operations in the compiled expression
1179
 */
1180
static void
1181
44
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1182
44
    int tmp;
1183
1184
#ifndef LIBXML_THREAD_ENABLED
1185
    /*
1186
     * Since this manipulates possibly shared variables, this is
1187
     * disabled if one detects that the library is used in a multithreaded
1188
     * application
1189
     */
1190
    if (xmlXPathDisableOptimizer)
1191
  return;
1192
#endif
1193
1194
44
    tmp = op->ch1;
1195
44
    op->ch1 = op->ch2;
1196
44
    op->ch2 = tmp;
1197
44
}
1198
1199
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1200
248k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1201
248k
                  (op), (val), (val2), (val3), (val4), (val5))
1202
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1203
124k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1204
124k
                  (op), (val), (val2), (val3), (val4), (val5))
1205
1206
1.57M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1207
1.57M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1208
1209
29.7k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1210
29.7k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1211
1212
1.56M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1213
1.56M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1214
1.56M
      (val), (val2), 0 ,NULL ,NULL)
1215
1216
/************************************************************************
1217
 *                  *
1218
 *    XPath object cache structures       *
1219
 *                  *
1220
 ************************************************************************/
1221
1222
/* #define XP_DEFAULT_CACHE_ON */
1223
1224
464k
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1225
1226
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1227
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1228
struct _xmlXPathContextCache {
1229
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1230
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1231
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1232
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1233
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1234
    int maxNodeset;
1235
    int maxString;
1236
    int maxBoolean;
1237
    int maxNumber;
1238
    int maxMisc;
1239
#ifdef XP_DEBUG_OBJ_USAGE
1240
    int dbgCachedAll;
1241
    int dbgCachedNodeset;
1242
    int dbgCachedString;
1243
    int dbgCachedBool;
1244
    int dbgCachedNumber;
1245
    int dbgCachedPoint;
1246
    int dbgCachedRange;
1247
    int dbgCachedLocset;
1248
    int dbgCachedUsers;
1249
    int dbgCachedXSLTTree;
1250
    int dbgCachedUndefined;
1251
1252
1253
    int dbgReusedAll;
1254
    int dbgReusedNodeset;
1255
    int dbgReusedString;
1256
    int dbgReusedBool;
1257
    int dbgReusedNumber;
1258
    int dbgReusedPoint;
1259
    int dbgReusedRange;
1260
    int dbgReusedLocset;
1261
    int dbgReusedUsers;
1262
    int dbgReusedXSLTTree;
1263
    int dbgReusedUndefined;
1264
1265
#endif
1266
};
1267
1268
/************************************************************************
1269
 *                  *
1270
 *    Debugging related functions       *
1271
 *                  *
1272
 ************************************************************************/
1273
1274
#define STRANGE             \
1275
0
    xmlGenericError(xmlGenericErrorContext,       \
1276
0
      "Internal error at %s:%d\n",        \
1277
0
            __FILE__, __LINE__);
1278
1279
#ifdef LIBXML_DEBUG_ENABLED
1280
static void
1281
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1282
0
    int i;
1283
0
    char shift[100];
1284
1285
0
    for (i = 0;((i < depth) && (i < 25));i++)
1286
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1287
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1288
0
    if (cur == NULL) {
1289
0
  fprintf(output, "%s", shift);
1290
0
  fprintf(output, "Node is NULL !\n");
1291
0
  return;
1292
1293
0
    }
1294
1295
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1296
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1297
0
  fprintf(output, "%s", shift);
1298
0
  fprintf(output, " /\n");
1299
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1300
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1301
0
    else
1302
0
  xmlDebugDumpOneNode(output, cur, depth);
1303
0
}
1304
static void
1305
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1306
0
    xmlNodePtr tmp;
1307
0
    int i;
1308
0
    char shift[100];
1309
1310
0
    for (i = 0;((i < depth) && (i < 25));i++)
1311
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1312
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1313
0
    if (cur == NULL) {
1314
0
  fprintf(output, "%s", shift);
1315
0
  fprintf(output, "Node is NULL !\n");
1316
0
  return;
1317
1318
0
    }
1319
1320
0
    while (cur != NULL) {
1321
0
  tmp = cur;
1322
0
  cur = cur->next;
1323
0
  xmlDebugDumpOneNode(output, tmp, depth);
1324
0
    }
1325
0
}
1326
1327
static void
1328
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1329
0
    int i;
1330
0
    char shift[100];
1331
1332
0
    for (i = 0;((i < depth) && (i < 25));i++)
1333
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1334
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1335
1336
0
    if (cur == NULL) {
1337
0
  fprintf(output, "%s", shift);
1338
0
  fprintf(output, "NodeSet is NULL !\n");
1339
0
  return;
1340
1341
0
    }
1342
1343
0
    if (cur != NULL) {
1344
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1345
0
  for (i = 0;i < cur->nodeNr;i++) {
1346
0
      fprintf(output, "%s", shift);
1347
0
      fprintf(output, "%d", i + 1);
1348
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1349
0
  }
1350
0
    }
1351
0
}
1352
1353
static void
1354
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1355
0
    int i;
1356
0
    char shift[100];
1357
1358
0
    for (i = 0;((i < depth) && (i < 25));i++)
1359
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1360
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1361
1362
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1363
0
  fprintf(output, "%s", shift);
1364
0
  fprintf(output, "Value Tree is NULL !\n");
1365
0
  return;
1366
1367
0
    }
1368
1369
0
    fprintf(output, "%s", shift);
1370
0
    fprintf(output, "%d", i + 1);
1371
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1372
0
}
1373
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1374
static void
1375
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1376
    int i;
1377
    char shift[100];
1378
1379
    for (i = 0;((i < depth) && (i < 25));i++)
1380
        shift[2 * i] = shift[2 * i + 1] = ' ';
1381
    shift[2 * i] = shift[2 * i + 1] = 0;
1382
1383
    if (cur == NULL) {
1384
  fprintf(output, "%s", shift);
1385
  fprintf(output, "LocationSet is NULL !\n");
1386
  return;
1387
1388
    }
1389
1390
    for (i = 0;i < cur->locNr;i++) {
1391
  fprintf(output, "%s", shift);
1392
        fprintf(output, "%d : ", i + 1);
1393
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1394
    }
1395
}
1396
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1397
1398
/**
1399
 * xmlXPathDebugDumpObject:
1400
 * @output:  the FILE * to dump the output
1401
 * @cur:  the object to inspect
1402
 * @depth:  indentation level
1403
 *
1404
 * Dump the content of the object for debugging purposes
1405
 */
1406
void
1407
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1408
0
    int i;
1409
0
    char shift[100];
1410
1411
0
    if (output == NULL) return;
1412
1413
0
    for (i = 0;((i < depth) && (i < 25));i++)
1414
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1415
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1416
1417
1418
0
    fprintf(output, "%s", shift);
1419
1420
0
    if (cur == NULL) {
1421
0
        fprintf(output, "Object is empty (NULL)\n");
1422
0
  return;
1423
0
    }
1424
0
    switch(cur->type) {
1425
0
        case XPATH_UNDEFINED:
1426
0
      fprintf(output, "Object is uninitialized\n");
1427
0
      break;
1428
0
        case XPATH_NODESET:
1429
0
      fprintf(output, "Object is a Node Set :\n");
1430
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1431
0
      break;
1432
0
  case XPATH_XSLT_TREE:
1433
0
      fprintf(output, "Object is an XSLT value tree :\n");
1434
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
        case XPATH_BOOLEAN:
1437
0
      fprintf(output, "Object is a Boolean : ");
1438
0
      if (cur->boolval) fprintf(output, "true\n");
1439
0
      else fprintf(output, "false\n");
1440
0
      break;
1441
0
        case XPATH_NUMBER:
1442
0
      switch (xmlXPathIsInf(cur->floatval)) {
1443
0
      case 1:
1444
0
    fprintf(output, "Object is a number : Infinity\n");
1445
0
    break;
1446
0
      case -1:
1447
0
    fprintf(output, "Object is a number : -Infinity\n");
1448
0
    break;
1449
0
      default:
1450
0
    if (xmlXPathIsNaN(cur->floatval)) {
1451
0
        fprintf(output, "Object is a number : NaN\n");
1452
0
    } else if (cur->floatval == 0) {
1453
                    /* Omit sign for negative zero. */
1454
0
        fprintf(output, "Object is a number : 0\n");
1455
0
    } else {
1456
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1457
0
    }
1458
0
      }
1459
0
      break;
1460
0
        case XPATH_STRING:
1461
0
      fprintf(output, "Object is a string : ");
1462
0
      xmlDebugDumpString(output, cur->stringval);
1463
0
      fprintf(output, "\n");
1464
0
      break;
1465
#ifdef LIBXML_XPTR_LOCS_ENABLED
1466
  case XPATH_POINT:
1467
      fprintf(output, "Object is a point : index %d in node", cur->index);
1468
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1469
      fprintf(output, "\n");
1470
      break;
1471
  case XPATH_RANGE:
1472
      if ((cur->user2 == NULL) ||
1473
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1474
    fprintf(output, "Object is a collapsed range :\n");
1475
    fprintf(output, "%s", shift);
1476
    if (cur->index >= 0)
1477
        fprintf(output, "index %d in ", cur->index);
1478
    fprintf(output, "node\n");
1479
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1480
                    depth + 1);
1481
      } else  {
1482
    fprintf(output, "Object is a range :\n");
1483
    fprintf(output, "%s", shift);
1484
    fprintf(output, "From ");
1485
    if (cur->index >= 0)
1486
        fprintf(output, "index %d in ", cur->index);
1487
    fprintf(output, "node\n");
1488
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1489
                    depth + 1);
1490
    fprintf(output, "%s", shift);
1491
    fprintf(output, "To ");
1492
    if (cur->index2 >= 0)
1493
        fprintf(output, "index %d in ", cur->index2);
1494
    fprintf(output, "node\n");
1495
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1496
                    depth + 1);
1497
    fprintf(output, "\n");
1498
      }
1499
      break;
1500
  case XPATH_LOCATIONSET:
1501
      fprintf(output, "Object is a Location Set:\n");
1502
      xmlXPathDebugDumpLocationSet(output,
1503
        (xmlLocationSetPtr) cur->user, depth);
1504
      break;
1505
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1506
0
  case XPATH_USERS:
1507
0
      fprintf(output, "Object is user defined\n");
1508
0
      break;
1509
0
    }
1510
0
}
1511
1512
static void
1513
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1514
0
                       xmlXPathStepOpPtr op, int depth) {
1515
0
    int i;
1516
0
    char shift[100];
1517
1518
0
    for (i = 0;((i < depth) && (i < 25));i++)
1519
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1520
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1521
1522
0
    fprintf(output, "%s", shift);
1523
0
    if (op == NULL) {
1524
0
  fprintf(output, "Step is NULL\n");
1525
0
  return;
1526
0
    }
1527
0
    switch (op->op) {
1528
0
        case XPATH_OP_END:
1529
0
      fprintf(output, "END"); break;
1530
0
        case XPATH_OP_AND:
1531
0
      fprintf(output, "AND"); break;
1532
0
        case XPATH_OP_OR:
1533
0
      fprintf(output, "OR"); break;
1534
0
        case XPATH_OP_EQUAL:
1535
0
       if (op->value)
1536
0
     fprintf(output, "EQUAL =");
1537
0
       else
1538
0
     fprintf(output, "EQUAL !=");
1539
0
       break;
1540
0
        case XPATH_OP_CMP:
1541
0
       if (op->value)
1542
0
     fprintf(output, "CMP <");
1543
0
       else
1544
0
     fprintf(output, "CMP >");
1545
0
       if (!op->value2)
1546
0
     fprintf(output, "=");
1547
0
       break;
1548
0
        case XPATH_OP_PLUS:
1549
0
       if (op->value == 0)
1550
0
     fprintf(output, "PLUS -");
1551
0
       else if (op->value == 1)
1552
0
     fprintf(output, "PLUS +");
1553
0
       else if (op->value == 2)
1554
0
     fprintf(output, "PLUS unary -");
1555
0
       else if (op->value == 3)
1556
0
     fprintf(output, "PLUS unary - -");
1557
0
       break;
1558
0
        case XPATH_OP_MULT:
1559
0
       if (op->value == 0)
1560
0
     fprintf(output, "MULT *");
1561
0
       else if (op->value == 1)
1562
0
     fprintf(output, "MULT div");
1563
0
       else
1564
0
     fprintf(output, "MULT mod");
1565
0
       break;
1566
0
        case XPATH_OP_UNION:
1567
0
       fprintf(output, "UNION"); break;
1568
0
        case XPATH_OP_ROOT:
1569
0
       fprintf(output, "ROOT"); break;
1570
0
        case XPATH_OP_NODE:
1571
0
       fprintf(output, "NODE"); break;
1572
0
        case XPATH_OP_SORT:
1573
0
       fprintf(output, "SORT"); break;
1574
0
        case XPATH_OP_COLLECT: {
1575
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1576
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1577
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1578
0
      const xmlChar *prefix = op->value4;
1579
0
      const xmlChar *name = op->value5;
1580
1581
0
      fprintf(output, "COLLECT ");
1582
0
      switch (axis) {
1583
0
    case AXIS_ANCESTOR:
1584
0
        fprintf(output, " 'ancestors' "); break;
1585
0
    case AXIS_ANCESTOR_OR_SELF:
1586
0
        fprintf(output, " 'ancestors-or-self' "); break;
1587
0
    case AXIS_ATTRIBUTE:
1588
0
        fprintf(output, " 'attributes' "); break;
1589
0
    case AXIS_CHILD:
1590
0
        fprintf(output, " 'child' "); break;
1591
0
    case AXIS_DESCENDANT:
1592
0
        fprintf(output, " 'descendant' "); break;
1593
0
    case AXIS_DESCENDANT_OR_SELF:
1594
0
        fprintf(output, " 'descendant-or-self' "); break;
1595
0
    case AXIS_FOLLOWING:
1596
0
        fprintf(output, " 'following' "); break;
1597
0
    case AXIS_FOLLOWING_SIBLING:
1598
0
        fprintf(output, " 'following-siblings' "); break;
1599
0
    case AXIS_NAMESPACE:
1600
0
        fprintf(output, " 'namespace' "); break;
1601
0
    case AXIS_PARENT:
1602
0
        fprintf(output, " 'parent' "); break;
1603
0
    case AXIS_PRECEDING:
1604
0
        fprintf(output, " 'preceding' "); break;
1605
0
    case AXIS_PRECEDING_SIBLING:
1606
0
        fprintf(output, " 'preceding-sibling' "); break;
1607
0
    case AXIS_SELF:
1608
0
        fprintf(output, " 'self' "); break;
1609
0
      }
1610
0
      switch (test) {
1611
0
                case NODE_TEST_NONE:
1612
0
        fprintf(output, "'none' "); break;
1613
0
                case NODE_TEST_TYPE:
1614
0
        fprintf(output, "'type' "); break;
1615
0
                case NODE_TEST_PI:
1616
0
        fprintf(output, "'PI' "); break;
1617
0
                case NODE_TEST_ALL:
1618
0
        fprintf(output, "'all' "); break;
1619
0
                case NODE_TEST_NS:
1620
0
        fprintf(output, "'namespace' "); break;
1621
0
                case NODE_TEST_NAME:
1622
0
        fprintf(output, "'name' "); break;
1623
0
      }
1624
0
      switch (type) {
1625
0
                case NODE_TYPE_NODE:
1626
0
        fprintf(output, "'node' "); break;
1627
0
                case NODE_TYPE_COMMENT:
1628
0
        fprintf(output, "'comment' "); break;
1629
0
                case NODE_TYPE_TEXT:
1630
0
        fprintf(output, "'text' "); break;
1631
0
                case NODE_TYPE_PI:
1632
0
        fprintf(output, "'PI' "); break;
1633
0
      }
1634
0
      if (prefix != NULL)
1635
0
    fprintf(output, "%s:", prefix);
1636
0
      if (name != NULL)
1637
0
    fprintf(output, "%s", (const char *) name);
1638
0
      break;
1639
1640
0
        }
1641
0
  case XPATH_OP_VALUE: {
1642
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1643
1644
0
      fprintf(output, "ELEM ");
1645
0
      xmlXPathDebugDumpObject(output, object, 0);
1646
0
      goto finish;
1647
0
  }
1648
0
  case XPATH_OP_VARIABLE: {
1649
0
      const xmlChar *prefix = op->value5;
1650
0
      const xmlChar *name = op->value4;
1651
1652
0
      if (prefix != NULL)
1653
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1654
0
      else
1655
0
    fprintf(output, "VARIABLE %s", name);
1656
0
      break;
1657
0
  }
1658
0
  case XPATH_OP_FUNCTION: {
1659
0
      int nbargs = op->value;
1660
0
      const xmlChar *prefix = op->value5;
1661
0
      const xmlChar *name = op->value4;
1662
1663
0
      if (prefix != NULL)
1664
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1665
0
      prefix, name, nbargs);
1666
0
      else
1667
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1668
0
      break;
1669
0
  }
1670
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1671
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1672
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1673
#ifdef LIBXML_XPTR_LOCS_ENABLED
1674
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1675
#endif
1676
0
  default:
1677
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1678
0
    }
1679
0
    fprintf(output, "\n");
1680
0
finish:
1681
0
    if (op->ch1 >= 0)
1682
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1683
0
    if (op->ch2 >= 0)
1684
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1685
0
}
1686
1687
/**
1688
 * xmlXPathDebugDumpCompExpr:
1689
 * @output:  the FILE * for the output
1690
 * @comp:  the precompiled XPath expression
1691
 * @depth:  the indentation level.
1692
 *
1693
 * Dumps the tree of the compiled XPath expression.
1694
 */
1695
void
1696
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1697
0
                    int depth) {
1698
0
    int i;
1699
0
    char shift[100];
1700
1701
0
    if ((output == NULL) || (comp == NULL)) return;
1702
1703
0
    for (i = 0;((i < depth) && (i < 25));i++)
1704
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1705
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1706
1707
0
    fprintf(output, "%s", shift);
1708
1709
0
#ifdef XPATH_STREAMING
1710
0
    if (comp->stream) {
1711
0
        fprintf(output, "Streaming Expression\n");
1712
0
    } else
1713
0
#endif
1714
0
    {
1715
0
        fprintf(output, "Compiled Expression : %d elements\n",
1716
0
                comp->nbStep);
1717
0
        i = comp->last;
1718
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1719
0
    }
1720
0
}
1721
1722
#ifdef XP_DEBUG_OBJ_USAGE
1723
1724
/*
1725
* XPath object usage related debugging variables.
1726
*/
1727
static int xmlXPathDebugObjCounterUndefined = 0;
1728
static int xmlXPathDebugObjCounterNodeset = 0;
1729
static int xmlXPathDebugObjCounterBool = 0;
1730
static int xmlXPathDebugObjCounterNumber = 0;
1731
static int xmlXPathDebugObjCounterString = 0;
1732
static int xmlXPathDebugObjCounterPoint = 0;
1733
static int xmlXPathDebugObjCounterRange = 0;
1734
static int xmlXPathDebugObjCounterLocset = 0;
1735
static int xmlXPathDebugObjCounterUsers = 0;
1736
static int xmlXPathDebugObjCounterXSLTTree = 0;
1737
static int xmlXPathDebugObjCounterAll = 0;
1738
1739
static int xmlXPathDebugObjTotalUndefined = 0;
1740
static int xmlXPathDebugObjTotalNodeset = 0;
1741
static int xmlXPathDebugObjTotalBool = 0;
1742
static int xmlXPathDebugObjTotalNumber = 0;
1743
static int xmlXPathDebugObjTotalString = 0;
1744
static int xmlXPathDebugObjTotalPoint = 0;
1745
static int xmlXPathDebugObjTotalRange = 0;
1746
static int xmlXPathDebugObjTotalLocset = 0;
1747
static int xmlXPathDebugObjTotalUsers = 0;
1748
static int xmlXPathDebugObjTotalXSLTTree = 0;
1749
static int xmlXPathDebugObjTotalAll = 0;
1750
1751
static int xmlXPathDebugObjMaxUndefined = 0;
1752
static int xmlXPathDebugObjMaxNodeset = 0;
1753
static int xmlXPathDebugObjMaxBool = 0;
1754
static int xmlXPathDebugObjMaxNumber = 0;
1755
static int xmlXPathDebugObjMaxString = 0;
1756
static int xmlXPathDebugObjMaxPoint = 0;
1757
static int xmlXPathDebugObjMaxRange = 0;
1758
static int xmlXPathDebugObjMaxLocset = 0;
1759
static int xmlXPathDebugObjMaxUsers = 0;
1760
static int xmlXPathDebugObjMaxXSLTTree = 0;
1761
static int xmlXPathDebugObjMaxAll = 0;
1762
1763
static void
1764
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1765
{
1766
    if (ctxt != NULL) {
1767
  if (ctxt->cache != NULL) {
1768
      xmlXPathContextCachePtr cache =
1769
    (xmlXPathContextCachePtr) ctxt->cache;
1770
1771
      cache->dbgCachedAll = 0;
1772
      cache->dbgCachedNodeset = 0;
1773
      cache->dbgCachedString = 0;
1774
      cache->dbgCachedBool = 0;
1775
      cache->dbgCachedNumber = 0;
1776
      cache->dbgCachedPoint = 0;
1777
      cache->dbgCachedRange = 0;
1778
      cache->dbgCachedLocset = 0;
1779
      cache->dbgCachedUsers = 0;
1780
      cache->dbgCachedXSLTTree = 0;
1781
      cache->dbgCachedUndefined = 0;
1782
1783
      cache->dbgReusedAll = 0;
1784
      cache->dbgReusedNodeset = 0;
1785
      cache->dbgReusedString = 0;
1786
      cache->dbgReusedBool = 0;
1787
      cache->dbgReusedNumber = 0;
1788
      cache->dbgReusedPoint = 0;
1789
      cache->dbgReusedRange = 0;
1790
      cache->dbgReusedLocset = 0;
1791
      cache->dbgReusedUsers = 0;
1792
      cache->dbgReusedXSLTTree = 0;
1793
      cache->dbgReusedUndefined = 0;
1794
  }
1795
    }
1796
1797
    xmlXPathDebugObjCounterUndefined = 0;
1798
    xmlXPathDebugObjCounterNodeset = 0;
1799
    xmlXPathDebugObjCounterBool = 0;
1800
    xmlXPathDebugObjCounterNumber = 0;
1801
    xmlXPathDebugObjCounterString = 0;
1802
    xmlXPathDebugObjCounterPoint = 0;
1803
    xmlXPathDebugObjCounterRange = 0;
1804
    xmlXPathDebugObjCounterLocset = 0;
1805
    xmlXPathDebugObjCounterUsers = 0;
1806
    xmlXPathDebugObjCounterXSLTTree = 0;
1807
    xmlXPathDebugObjCounterAll = 0;
1808
1809
    xmlXPathDebugObjTotalUndefined = 0;
1810
    xmlXPathDebugObjTotalNodeset = 0;
1811
    xmlXPathDebugObjTotalBool = 0;
1812
    xmlXPathDebugObjTotalNumber = 0;
1813
    xmlXPathDebugObjTotalString = 0;
1814
    xmlXPathDebugObjTotalPoint = 0;
1815
    xmlXPathDebugObjTotalRange = 0;
1816
    xmlXPathDebugObjTotalLocset = 0;
1817
    xmlXPathDebugObjTotalUsers = 0;
1818
    xmlXPathDebugObjTotalXSLTTree = 0;
1819
    xmlXPathDebugObjTotalAll = 0;
1820
1821
    xmlXPathDebugObjMaxUndefined = 0;
1822
    xmlXPathDebugObjMaxNodeset = 0;
1823
    xmlXPathDebugObjMaxBool = 0;
1824
    xmlXPathDebugObjMaxNumber = 0;
1825
    xmlXPathDebugObjMaxString = 0;
1826
    xmlXPathDebugObjMaxPoint = 0;
1827
    xmlXPathDebugObjMaxRange = 0;
1828
    xmlXPathDebugObjMaxLocset = 0;
1829
    xmlXPathDebugObjMaxUsers = 0;
1830
    xmlXPathDebugObjMaxXSLTTree = 0;
1831
    xmlXPathDebugObjMaxAll = 0;
1832
1833
}
1834
1835
static void
1836
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1837
            xmlXPathObjectType objType)
1838
{
1839
    int isCached = 0;
1840
1841
    if (ctxt != NULL) {
1842
  if (ctxt->cache != NULL) {
1843
      xmlXPathContextCachePtr cache =
1844
    (xmlXPathContextCachePtr) ctxt->cache;
1845
1846
      isCached = 1;
1847
1848
      cache->dbgReusedAll++;
1849
      switch (objType) {
1850
    case XPATH_UNDEFINED:
1851
        cache->dbgReusedUndefined++;
1852
        break;
1853
    case XPATH_NODESET:
1854
        cache->dbgReusedNodeset++;
1855
        break;
1856
    case XPATH_BOOLEAN:
1857
        cache->dbgReusedBool++;
1858
        break;
1859
    case XPATH_NUMBER:
1860
        cache->dbgReusedNumber++;
1861
        break;
1862
    case XPATH_STRING:
1863
        cache->dbgReusedString++;
1864
        break;
1865
#ifdef LIBXML_XPTR_LOCS_ENABLED
1866
    case XPATH_POINT:
1867
        cache->dbgReusedPoint++;
1868
        break;
1869
    case XPATH_RANGE:
1870
        cache->dbgReusedRange++;
1871
        break;
1872
    case XPATH_LOCATIONSET:
1873
        cache->dbgReusedLocset++;
1874
        break;
1875
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1876
    case XPATH_USERS:
1877
        cache->dbgReusedUsers++;
1878
        break;
1879
    case XPATH_XSLT_TREE:
1880
        cache->dbgReusedXSLTTree++;
1881
        break;
1882
    default:
1883
        break;
1884
      }
1885
  }
1886
    }
1887
1888
    switch (objType) {
1889
  case XPATH_UNDEFINED:
1890
      if (! isCached)
1891
    xmlXPathDebugObjTotalUndefined++;
1892
      xmlXPathDebugObjCounterUndefined++;
1893
      if (xmlXPathDebugObjCounterUndefined >
1894
    xmlXPathDebugObjMaxUndefined)
1895
    xmlXPathDebugObjMaxUndefined =
1896
        xmlXPathDebugObjCounterUndefined;
1897
      break;
1898
  case XPATH_NODESET:
1899
      if (! isCached)
1900
    xmlXPathDebugObjTotalNodeset++;
1901
      xmlXPathDebugObjCounterNodeset++;
1902
      if (xmlXPathDebugObjCounterNodeset >
1903
    xmlXPathDebugObjMaxNodeset)
1904
    xmlXPathDebugObjMaxNodeset =
1905
        xmlXPathDebugObjCounterNodeset;
1906
      break;
1907
  case XPATH_BOOLEAN:
1908
      if (! isCached)
1909
    xmlXPathDebugObjTotalBool++;
1910
      xmlXPathDebugObjCounterBool++;
1911
      if (xmlXPathDebugObjCounterBool >
1912
    xmlXPathDebugObjMaxBool)
1913
    xmlXPathDebugObjMaxBool =
1914
        xmlXPathDebugObjCounterBool;
1915
      break;
1916
  case XPATH_NUMBER:
1917
      if (! isCached)
1918
    xmlXPathDebugObjTotalNumber++;
1919
      xmlXPathDebugObjCounterNumber++;
1920
      if (xmlXPathDebugObjCounterNumber >
1921
    xmlXPathDebugObjMaxNumber)
1922
    xmlXPathDebugObjMaxNumber =
1923
        xmlXPathDebugObjCounterNumber;
1924
      break;
1925
  case XPATH_STRING:
1926
      if (! isCached)
1927
    xmlXPathDebugObjTotalString++;
1928
      xmlXPathDebugObjCounterString++;
1929
      if (xmlXPathDebugObjCounterString >
1930
    xmlXPathDebugObjMaxString)
1931
    xmlXPathDebugObjMaxString =
1932
        xmlXPathDebugObjCounterString;
1933
      break;
1934
#ifdef LIBXML_XPTR_LOCS_ENABLED
1935
  case XPATH_POINT:
1936
      if (! isCached)
1937
    xmlXPathDebugObjTotalPoint++;
1938
      xmlXPathDebugObjCounterPoint++;
1939
      if (xmlXPathDebugObjCounterPoint >
1940
    xmlXPathDebugObjMaxPoint)
1941
    xmlXPathDebugObjMaxPoint =
1942
        xmlXPathDebugObjCounterPoint;
1943
      break;
1944
  case XPATH_RANGE:
1945
      if (! isCached)
1946
    xmlXPathDebugObjTotalRange++;
1947
      xmlXPathDebugObjCounterRange++;
1948
      if (xmlXPathDebugObjCounterRange >
1949
    xmlXPathDebugObjMaxRange)
1950
    xmlXPathDebugObjMaxRange =
1951
        xmlXPathDebugObjCounterRange;
1952
      break;
1953
  case XPATH_LOCATIONSET:
1954
      if (! isCached)
1955
    xmlXPathDebugObjTotalLocset++;
1956
      xmlXPathDebugObjCounterLocset++;
1957
      if (xmlXPathDebugObjCounterLocset >
1958
    xmlXPathDebugObjMaxLocset)
1959
    xmlXPathDebugObjMaxLocset =
1960
        xmlXPathDebugObjCounterLocset;
1961
      break;
1962
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1963
  case XPATH_USERS:
1964
      if (! isCached)
1965
    xmlXPathDebugObjTotalUsers++;
1966
      xmlXPathDebugObjCounterUsers++;
1967
      if (xmlXPathDebugObjCounterUsers >
1968
    xmlXPathDebugObjMaxUsers)
1969
    xmlXPathDebugObjMaxUsers =
1970
        xmlXPathDebugObjCounterUsers;
1971
      break;
1972
  case XPATH_XSLT_TREE:
1973
      if (! isCached)
1974
    xmlXPathDebugObjTotalXSLTTree++;
1975
      xmlXPathDebugObjCounterXSLTTree++;
1976
      if (xmlXPathDebugObjCounterXSLTTree >
1977
    xmlXPathDebugObjMaxXSLTTree)
1978
    xmlXPathDebugObjMaxXSLTTree =
1979
        xmlXPathDebugObjCounterXSLTTree;
1980
      break;
1981
  default:
1982
      break;
1983
    }
1984
    if (! isCached)
1985
  xmlXPathDebugObjTotalAll++;
1986
    xmlXPathDebugObjCounterAll++;
1987
    if (xmlXPathDebugObjCounterAll >
1988
  xmlXPathDebugObjMaxAll)
1989
  xmlXPathDebugObjMaxAll =
1990
      xmlXPathDebugObjCounterAll;
1991
}
1992
1993
static void
1994
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1995
            xmlXPathObjectType objType)
1996
{
1997
    int isCached = 0;
1998
1999
    if (ctxt != NULL) {
2000
  if (ctxt->cache != NULL) {
2001
      xmlXPathContextCachePtr cache =
2002
    (xmlXPathContextCachePtr) ctxt->cache;
2003
2004
      isCached = 1;
2005
2006
      cache->dbgCachedAll++;
2007
      switch (objType) {
2008
    case XPATH_UNDEFINED:
2009
        cache->dbgCachedUndefined++;
2010
        break;
2011
    case XPATH_NODESET:
2012
        cache->dbgCachedNodeset++;
2013
        break;
2014
    case XPATH_BOOLEAN:
2015
        cache->dbgCachedBool++;
2016
        break;
2017
    case XPATH_NUMBER:
2018
        cache->dbgCachedNumber++;
2019
        break;
2020
    case XPATH_STRING:
2021
        cache->dbgCachedString++;
2022
        break;
2023
#ifdef LIBXML_XPTR_LOCS_ENABLED
2024
    case XPATH_POINT:
2025
        cache->dbgCachedPoint++;
2026
        break;
2027
    case XPATH_RANGE:
2028
        cache->dbgCachedRange++;
2029
        break;
2030
    case XPATH_LOCATIONSET:
2031
        cache->dbgCachedLocset++;
2032
        break;
2033
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2034
    case XPATH_USERS:
2035
        cache->dbgCachedUsers++;
2036
        break;
2037
    case XPATH_XSLT_TREE:
2038
        cache->dbgCachedXSLTTree++;
2039
        break;
2040
    default:
2041
        break;
2042
      }
2043
2044
  }
2045
    }
2046
    switch (objType) {
2047
  case XPATH_UNDEFINED:
2048
      xmlXPathDebugObjCounterUndefined--;
2049
      break;
2050
  case XPATH_NODESET:
2051
      xmlXPathDebugObjCounterNodeset--;
2052
      break;
2053
  case XPATH_BOOLEAN:
2054
      xmlXPathDebugObjCounterBool--;
2055
      break;
2056
  case XPATH_NUMBER:
2057
      xmlXPathDebugObjCounterNumber--;
2058
      break;
2059
  case XPATH_STRING:
2060
      xmlXPathDebugObjCounterString--;
2061
      break;
2062
#ifdef LIBXML_XPTR_LOCS_ENABLED
2063
  case XPATH_POINT:
2064
      xmlXPathDebugObjCounterPoint--;
2065
      break;
2066
  case XPATH_RANGE:
2067
      xmlXPathDebugObjCounterRange--;
2068
      break;
2069
  case XPATH_LOCATIONSET:
2070
      xmlXPathDebugObjCounterLocset--;
2071
      break;
2072
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2073
  case XPATH_USERS:
2074
      xmlXPathDebugObjCounterUsers--;
2075
      break;
2076
  case XPATH_XSLT_TREE:
2077
      xmlXPathDebugObjCounterXSLTTree--;
2078
      break;
2079
  default:
2080
      break;
2081
    }
2082
    xmlXPathDebugObjCounterAll--;
2083
}
2084
2085
static void
2086
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2087
{
2088
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2089
  reqXSLTTree, reqUndefined;
2090
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2091
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2092
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2093
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2094
    int leftObjs = xmlXPathDebugObjCounterAll;
2095
2096
    reqAll = xmlXPathDebugObjTotalAll;
2097
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2098
    reqString = xmlXPathDebugObjTotalString;
2099
    reqBool = xmlXPathDebugObjTotalBool;
2100
    reqNumber = xmlXPathDebugObjTotalNumber;
2101
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2102
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2103
2104
    printf("# XPath object usage:\n");
2105
2106
    if (ctxt != NULL) {
2107
  if (ctxt->cache != NULL) {
2108
      xmlXPathContextCachePtr cache =
2109
    (xmlXPathContextCachePtr) ctxt->cache;
2110
2111
      reAll = cache->dbgReusedAll;
2112
      reqAll += reAll;
2113
      reNodeset = cache->dbgReusedNodeset;
2114
      reqNodeset += reNodeset;
2115
      reString = cache->dbgReusedString;
2116
      reqString += reString;
2117
      reBool = cache->dbgReusedBool;
2118
      reqBool += reBool;
2119
      reNumber = cache->dbgReusedNumber;
2120
      reqNumber += reNumber;
2121
      reXSLTTree = cache->dbgReusedXSLTTree;
2122
      reqXSLTTree += reXSLTTree;
2123
      reUndefined = cache->dbgReusedUndefined;
2124
      reqUndefined += reUndefined;
2125
2126
      caAll = cache->dbgCachedAll;
2127
      caBool = cache->dbgCachedBool;
2128
      caNodeset = cache->dbgCachedNodeset;
2129
      caString = cache->dbgCachedString;
2130
      caNumber = cache->dbgCachedNumber;
2131
      caXSLTTree = cache->dbgCachedXSLTTree;
2132
      caUndefined = cache->dbgCachedUndefined;
2133
2134
      if (cache->nodesetObjs)
2135
    leftObjs -= cache->nodesetObjs->number;
2136
      if (cache->stringObjs)
2137
    leftObjs -= cache->stringObjs->number;
2138
      if (cache->booleanObjs)
2139
    leftObjs -= cache->booleanObjs->number;
2140
      if (cache->numberObjs)
2141
    leftObjs -= cache->numberObjs->number;
2142
      if (cache->miscObjs)
2143
    leftObjs -= cache->miscObjs->number;
2144
  }
2145
    }
2146
2147
    printf("# all\n");
2148
    printf("#   total  : %d\n", reqAll);
2149
    printf("#   left  : %d\n", leftObjs);
2150
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2151
    printf("#   reused : %d\n", reAll);
2152
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2153
2154
    printf("# node-sets\n");
2155
    printf("#   total  : %d\n", reqNodeset);
2156
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2157
    printf("#   reused : %d\n", reNodeset);
2158
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2159
2160
    printf("# strings\n");
2161
    printf("#   total  : %d\n", reqString);
2162
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2163
    printf("#   reused : %d\n", reString);
2164
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2165
2166
    printf("# booleans\n");
2167
    printf("#   total  : %d\n", reqBool);
2168
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2169
    printf("#   reused : %d\n", reBool);
2170
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2171
2172
    printf("# numbers\n");
2173
    printf("#   total  : %d\n", reqNumber);
2174
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2175
    printf("#   reused : %d\n", reNumber);
2176
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2177
2178
    printf("# XSLT result tree fragments\n");
2179
    printf("#   total  : %d\n", reqXSLTTree);
2180
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2181
    printf("#   reused : %d\n", reXSLTTree);
2182
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2183
2184
    printf("# undefined\n");
2185
    printf("#   total  : %d\n", reqUndefined);
2186
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2187
    printf("#   reused : %d\n", reUndefined);
2188
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2189
2190
}
2191
2192
#endif /* XP_DEBUG_OBJ_USAGE */
2193
2194
#endif /* LIBXML_DEBUG_ENABLED */
2195
2196
/************************************************************************
2197
 *                  *
2198
 *      XPath object caching        *
2199
 *                  *
2200
 ************************************************************************/
2201
2202
/**
2203
 * xmlXPathNewCache:
2204
 *
2205
 * Create a new object cache
2206
 *
2207
 * Returns the xmlXPathCache just allocated.
2208
 */
2209
static xmlXPathContextCachePtr
2210
xmlXPathNewCache(void)
2211
12.6k
{
2212
12.6k
    xmlXPathContextCachePtr ret;
2213
2214
12.6k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2215
12.6k
    if (ret == NULL) {
2216
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2217
0
  return(NULL);
2218
0
    }
2219
12.6k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2220
12.6k
    ret->maxNodeset = 100;
2221
12.6k
    ret->maxString = 100;
2222
12.6k
    ret->maxBoolean = 100;
2223
12.6k
    ret->maxNumber = 100;
2224
12.6k
    ret->maxMisc = 100;
2225
12.6k
    return(ret);
2226
12.6k
}
2227
2228
static void
2229
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2230
18.6k
{
2231
18.6k
    int i;
2232
18.6k
    xmlXPathObjectPtr obj;
2233
2234
18.6k
    if (list == NULL)
2235
0
  return;
2236
2237
209k
    for (i = 0; i < list->number; i++) {
2238
190k
  obj = list->items[i];
2239
  /*
2240
  * Note that it is already assured that we don't need to
2241
  * look out for namespace nodes in the node-set.
2242
  */
2243
190k
  if (obj->nodesetval != NULL) {
2244
170k
      if (obj->nodesetval->nodeTab != NULL)
2245
160k
    xmlFree(obj->nodesetval->nodeTab);
2246
170k
      xmlFree(obj->nodesetval);
2247
170k
  }
2248
190k
  xmlFree(obj);
2249
#ifdef XP_DEBUG_OBJ_USAGE
2250
  xmlXPathDebugObjCounterAll--;
2251
#endif
2252
190k
    }
2253
18.6k
    xmlPointerListFree(list);
2254
18.6k
}
2255
2256
static void
2257
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2258
12.4k
{
2259
12.4k
    if (cache == NULL)
2260
0
  return;
2261
12.4k
    if (cache->nodesetObjs)
2262
6.38k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2263
12.4k
    if (cache->stringObjs)
2264
4.25k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2265
12.4k
    if (cache->booleanObjs)
2266
2.31k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2267
12.4k
    if (cache->numberObjs)
2268
2.91k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2269
12.4k
    if (cache->miscObjs)
2270
2.81k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2271
12.4k
    xmlFree(cache);
2272
12.4k
}
2273
2274
/**
2275
 * xmlXPathContextSetCache:
2276
 *
2277
 * @ctxt:  the XPath context
2278
 * @active: enables/disables (creates/frees) the cache
2279
 * @value: a value with semantics dependent on @options
2280
 * @options: options (currently only the value 0 is used)
2281
 *
2282
 * Creates/frees an object cache on the XPath context.
2283
 * If activates XPath objects (xmlXPathObject) will be cached internally
2284
 * to be reused.
2285
 * @options:
2286
 *   0: This will set the XPath object caching:
2287
 *      @value:
2288
 *        This will set the maximum number of XPath objects
2289
 *        to be cached per slot
2290
 *        There are 5 slots for: node-set, string, number, boolean, and
2291
 *        misc objects. Use <0 for the default number (100).
2292
 *   Other values for @options have currently no effect.
2293
 *
2294
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2295
 */
2296
int
2297
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2298
      int active,
2299
      int value,
2300
      int options)
2301
25.1k
{
2302
25.1k
    if (ctxt == NULL)
2303
0
  return(-1);
2304
25.1k
    if (active) {
2305
12.6k
  xmlXPathContextCachePtr cache;
2306
2307
12.6k
  if (ctxt->cache == NULL) {
2308
12.6k
      ctxt->cache = xmlXPathNewCache();
2309
12.6k
      if (ctxt->cache == NULL)
2310
0
    return(-1);
2311
12.6k
  }
2312
12.6k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2313
12.6k
  if (options == 0) {
2314
12.6k
      if (value < 0)
2315
12.6k
    value = 100;
2316
12.6k
      cache->maxNodeset = value;
2317
12.6k
      cache->maxString = value;
2318
12.6k
      cache->maxNumber = value;
2319
12.6k
      cache->maxBoolean = value;
2320
12.6k
      cache->maxMisc = value;
2321
12.6k
  }
2322
12.6k
    } else if (ctxt->cache != NULL) {
2323
12.4k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2324
12.4k
  ctxt->cache = NULL;
2325
12.4k
    }
2326
25.1k
    return(0);
2327
25.1k
}
2328
2329
/**
2330
 * xmlXPathCacheWrapNodeSet:
2331
 * @ctxt: the XPath context
2332
 * @val:  the NodePtr value
2333
 *
2334
 * This is the cached version of xmlXPathWrapNodeSet().
2335
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2336
 *
2337
 * Returns the created or reused object.
2338
 */
2339
static xmlXPathObjectPtr
2340
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2341
739k
{
2342
739k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2343
738k
  xmlXPathContextCachePtr cache =
2344
738k
      (xmlXPathContextCachePtr) ctxt->cache;
2345
2346
738k
  if ((cache->miscObjs != NULL) &&
2347
738k
      (cache->miscObjs->number != 0))
2348
584k
  {
2349
584k
      xmlXPathObjectPtr ret;
2350
2351
584k
      ret = (xmlXPathObjectPtr)
2352
584k
    cache->miscObjs->items[--cache->miscObjs->number];
2353
584k
      ret->type = XPATH_NODESET;
2354
584k
      ret->nodesetval = val;
2355
#ifdef XP_DEBUG_OBJ_USAGE
2356
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2357
#endif
2358
584k
      return(ret);
2359
584k
  }
2360
738k
    }
2361
2362
154k
    return(xmlXPathWrapNodeSet(val));
2363
2364
739k
}
2365
2366
/**
2367
 * xmlXPathCacheWrapString:
2368
 * @ctxt: the XPath context
2369
 * @val:  the xmlChar * value
2370
 *
2371
 * This is the cached version of xmlXPathWrapString().
2372
 * Wraps the @val string into an XPath object.
2373
 *
2374
 * Returns the created or reused object.
2375
 */
2376
static xmlXPathObjectPtr
2377
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2378
897k
{
2379
897k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2380
897k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2381
2382
897k
  if ((cache->stringObjs != NULL) &&
2383
897k
      (cache->stringObjs->number != 0))
2384
1.84k
  {
2385
2386
1.84k
      xmlXPathObjectPtr ret;
2387
2388
1.84k
      ret = (xmlXPathObjectPtr)
2389
1.84k
    cache->stringObjs->items[--cache->stringObjs->number];
2390
1.84k
      ret->type = XPATH_STRING;
2391
1.84k
      ret->stringval = val;
2392
#ifdef XP_DEBUG_OBJ_USAGE
2393
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394
#endif
2395
1.84k
      return(ret);
2396
896k
  } else if ((cache->miscObjs != NULL) &&
2397
896k
      (cache->miscObjs->number != 0))
2398
840k
  {
2399
840k
      xmlXPathObjectPtr ret;
2400
      /*
2401
      * Fallback to misc-cache.
2402
      */
2403
840k
      ret = (xmlXPathObjectPtr)
2404
840k
    cache->miscObjs->items[--cache->miscObjs->number];
2405
2406
840k
      ret->type = XPATH_STRING;
2407
840k
      ret->stringval = val;
2408
#ifdef XP_DEBUG_OBJ_USAGE
2409
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2410
#endif
2411
840k
      return(ret);
2412
840k
  }
2413
897k
    }
2414
55.0k
    return(xmlXPathWrapString(val));
2415
897k
}
2416
2417
/**
2418
 * xmlXPathCacheNewNodeSet:
2419
 * @ctxt: the XPath context
2420
 * @val:  the NodePtr value
2421
 *
2422
 * This is the cached version of xmlXPathNewNodeSet().
2423
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2424
 * it with the single Node @val
2425
 *
2426
 * Returns the created or reused object.
2427
 */
2428
static xmlXPathObjectPtr
2429
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2430
539k
{
2431
539k
    if ((ctxt != NULL) && (ctxt->cache)) {
2432
537k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2433
2434
537k
  if ((cache->nodesetObjs != NULL) &&
2435
537k
      (cache->nodesetObjs->number != 0))
2436
529k
  {
2437
529k
      xmlXPathObjectPtr ret;
2438
      /*
2439
      * Use the nodeset-cache.
2440
      */
2441
529k
      ret = (xmlXPathObjectPtr)
2442
529k
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2443
529k
      ret->type = XPATH_NODESET;
2444
529k
      ret->boolval = 0;
2445
529k
      if (val) {
2446
529k
    if ((ret->nodesetval->nodeMax == 0) ||
2447
529k
        (val->type == XML_NAMESPACE_DECL))
2448
164k
    {
2449
                    /* TODO: Check memory error. */
2450
164k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2451
365k
    } else {
2452
365k
        ret->nodesetval->nodeTab[0] = val;
2453
365k
        ret->nodesetval->nodeNr = 1;
2454
365k
    }
2455
529k
      }
2456
#ifdef XP_DEBUG_OBJ_USAGE
2457
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458
#endif
2459
529k
      return(ret);
2460
529k
  } else if ((cache->miscObjs != NULL) &&
2461
7.65k
      (cache->miscObjs->number != 0))
2462
41
  {
2463
41
      xmlXPathObjectPtr ret;
2464
      /*
2465
      * Fallback to misc-cache.
2466
      */
2467
2468
41
      ret = (xmlXPathObjectPtr)
2469
41
    cache->miscObjs->items[--cache->miscObjs->number];
2470
2471
41
      ret->type = XPATH_NODESET;
2472
41
      ret->boolval = 0;
2473
41
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2474
41
      if (ret->nodesetval == NULL) {
2475
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2476
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2477
0
    return(NULL);
2478
0
      }
2479
#ifdef XP_DEBUG_OBJ_USAGE
2480
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2481
#endif
2482
41
      return(ret);
2483
41
  }
2484
537k
    }
2485
10.1k
    return(xmlXPathNewNodeSet(val));
2486
539k
}
2487
2488
/**
2489
 * xmlXPathCacheNewCString:
2490
 * @ctxt: the XPath context
2491
 * @val:  the char * value
2492
 *
2493
 * This is the cached version of xmlXPathNewCString().
2494
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2495
 *
2496
 * Returns the created or reused object.
2497
 */
2498
static xmlXPathObjectPtr
2499
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2500
278
{
2501
278
    if ((ctxt != NULL) && (ctxt->cache)) {
2502
278
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504
278
  if ((cache->stringObjs != NULL) &&
2505
278
      (cache->stringObjs->number != 0))
2506
238
  {
2507
238
      xmlXPathObjectPtr ret;
2508
2509
238
      ret = (xmlXPathObjectPtr)
2510
238
    cache->stringObjs->items[--cache->stringObjs->number];
2511
2512
238
      ret->type = XPATH_STRING;
2513
238
      ret->stringval = xmlStrdup(BAD_CAST val);
2514
#ifdef XP_DEBUG_OBJ_USAGE
2515
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516
#endif
2517
238
      return(ret);
2518
238
  } else if ((cache->miscObjs != NULL) &&
2519
40
      (cache->miscObjs->number != 0))
2520
4
  {
2521
4
      xmlXPathObjectPtr ret;
2522
2523
4
      ret = (xmlXPathObjectPtr)
2524
4
    cache->miscObjs->items[--cache->miscObjs->number];
2525
2526
4
      ret->type = XPATH_STRING;
2527
4
      ret->stringval = xmlStrdup(BAD_CAST val);
2528
#ifdef XP_DEBUG_OBJ_USAGE
2529
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2530
#endif
2531
4
      return(ret);
2532
4
  }
2533
278
    }
2534
36
    return(xmlXPathNewCString(val));
2535
278
}
2536
2537
/**
2538
 * xmlXPathCacheNewString:
2539
 * @ctxt: the XPath context
2540
 * @val:  the xmlChar * value
2541
 *
2542
 * This is the cached version of xmlXPathNewString().
2543
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2544
 *
2545
 * Returns the created or reused object.
2546
 */
2547
static xmlXPathObjectPtr
2548
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2549
198k
{
2550
198k
    if ((ctxt != NULL) && (ctxt->cache)) {
2551
198k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2552
2553
198k
  if ((cache->stringObjs != NULL) &&
2554
198k
      (cache->stringObjs->number != 0))
2555
167k
  {
2556
167k
      xmlXPathObjectPtr ret;
2557
2558
167k
      ret = (xmlXPathObjectPtr)
2559
167k
    cache->stringObjs->items[--cache->stringObjs->number];
2560
167k
      ret->type = XPATH_STRING;
2561
167k
      if (val != NULL)
2562
167k
    ret->stringval = xmlStrdup(val);
2563
0
      else
2564
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2565
#ifdef XP_DEBUG_OBJ_USAGE
2566
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2567
#endif
2568
167k
      return(ret);
2569
167k
  } else if ((cache->miscObjs != NULL) &&
2570
31.6k
      (cache->miscObjs->number != 0))
2571
49
  {
2572
49
      xmlXPathObjectPtr ret;
2573
2574
49
      ret = (xmlXPathObjectPtr)
2575
49
    cache->miscObjs->items[--cache->miscObjs->number];
2576
2577
49
      ret->type = XPATH_STRING;
2578
49
      if (val != NULL)
2579
49
    ret->stringval = xmlStrdup(val);
2580
0
      else
2581
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2582
#ifdef XP_DEBUG_OBJ_USAGE
2583
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2584
#endif
2585
49
      return(ret);
2586
49
  }
2587
198k
    }
2588
31.6k
    return(xmlXPathNewString(val));
2589
198k
}
2590
2591
/**
2592
 * xmlXPathCacheNewBoolean:
2593
 * @ctxt: the XPath context
2594
 * @val:  the boolean value
2595
 *
2596
 * This is the cached version of xmlXPathNewBoolean().
2597
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2598
 *
2599
 * Returns the created or reused object.
2600
 */
2601
static xmlXPathObjectPtr
2602
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2603
357k
{
2604
357k
    if ((ctxt != NULL) && (ctxt->cache)) {
2605
357k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607
357k
  if ((cache->booleanObjs != NULL) &&
2608
357k
      (cache->booleanObjs->number != 0))
2609
353k
  {
2610
353k
      xmlXPathObjectPtr ret;
2611
2612
353k
      ret = (xmlXPathObjectPtr)
2613
353k
    cache->booleanObjs->items[--cache->booleanObjs->number];
2614
353k
      ret->type = XPATH_BOOLEAN;
2615
353k
      ret->boolval = (val != 0);
2616
#ifdef XP_DEBUG_OBJ_USAGE
2617
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2618
#endif
2619
353k
      return(ret);
2620
353k
  } else if ((cache->miscObjs != NULL) &&
2621
3.88k
      (cache->miscObjs->number != 0))
2622
289
  {
2623
289
      xmlXPathObjectPtr ret;
2624
2625
289
      ret = (xmlXPathObjectPtr)
2626
289
    cache->miscObjs->items[--cache->miscObjs->number];
2627
2628
289
      ret->type = XPATH_BOOLEAN;
2629
289
      ret->boolval = (val != 0);
2630
#ifdef XP_DEBUG_OBJ_USAGE
2631
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2632
#endif
2633
289
      return(ret);
2634
289
  }
2635
357k
    }
2636
3.59k
    return(xmlXPathNewBoolean(val));
2637
357k
}
2638
2639
/**
2640
 * xmlXPathCacheNewFloat:
2641
 * @ctxt: the XPath context
2642
 * @val:  the double value
2643
 *
2644
 * This is the cached version of xmlXPathNewFloat().
2645
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2646
 *
2647
 * Returns the created or reused object.
2648
 */
2649
static xmlXPathObjectPtr
2650
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2651
660k
{
2652
660k
     if ((ctxt != NULL) && (ctxt->cache)) {
2653
660k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2654
2655
660k
  if ((cache->numberObjs != NULL) &&
2656
660k
      (cache->numberObjs->number != 0))
2657
632k
  {
2658
632k
      xmlXPathObjectPtr ret;
2659
2660
632k
      ret = (xmlXPathObjectPtr)
2661
632k
    cache->numberObjs->items[--cache->numberObjs->number];
2662
632k
      ret->type = XPATH_NUMBER;
2663
632k
      ret->floatval = val;
2664
#ifdef XP_DEBUG_OBJ_USAGE
2665
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2666
#endif
2667
632k
      return(ret);
2668
632k
  } else if ((cache->miscObjs != NULL) &&
2669
27.9k
      (cache->miscObjs->number != 0))
2670
283
  {
2671
283
      xmlXPathObjectPtr ret;
2672
2673
283
      ret = (xmlXPathObjectPtr)
2674
283
    cache->miscObjs->items[--cache->miscObjs->number];
2675
2676
283
      ret->type = XPATH_NUMBER;
2677
283
      ret->floatval = val;
2678
#ifdef XP_DEBUG_OBJ_USAGE
2679
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2680
#endif
2681
283
      return(ret);
2682
283
  }
2683
660k
    }
2684
27.6k
    return(xmlXPathNewFloat(val));
2685
660k
}
2686
2687
/**
2688
 * xmlXPathCacheConvertString:
2689
 * @ctxt: the XPath context
2690
 * @val:  an XPath object
2691
 *
2692
 * This is the cached version of xmlXPathConvertString().
2693
 * Converts an existing object to its string() equivalent
2694
 *
2695
 * Returns a created or reused object, the old one is freed (cached)
2696
 *         (or the operation is done directly on @val)
2697
 */
2698
2699
static xmlXPathObjectPtr
2700
1.79M
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2701
1.79M
    xmlChar *res = NULL;
2702
2703
1.79M
    if (val == NULL)
2704
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2705
2706
1.79M
    switch (val->type) {
2707
0
    case XPATH_UNDEFINED:
2708
#ifdef DEBUG_EXPR
2709
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2710
#endif
2711
0
  break;
2712
897k
    case XPATH_NODESET:
2713
897k
    case XPATH_XSLT_TREE:
2714
897k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2715
897k
  break;
2716
901k
    case XPATH_STRING:
2717
901k
  return(val);
2718
97
    case XPATH_BOOLEAN:
2719
97
  res = xmlXPathCastBooleanToString(val->boolval);
2720
97
  break;
2721
281
    case XPATH_NUMBER:
2722
281
  res = xmlXPathCastNumberToString(val->floatval);
2723
281
  break;
2724
0
    case XPATH_USERS:
2725
#ifdef LIBXML_XPTR_LOCS_ENABLED
2726
    case XPATH_POINT:
2727
    case XPATH_RANGE:
2728
    case XPATH_LOCATIONSET:
2729
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2730
0
  TODO;
2731
0
  break;
2732
1.79M
    }
2733
897k
    xmlXPathReleaseObject(ctxt, val);
2734
897k
    if (res == NULL)
2735
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2736
897k
    return(xmlXPathCacheWrapString(ctxt, res));
2737
897k
}
2738
2739
/**
2740
 * xmlXPathCacheObjectCopy:
2741
 * @ctxt: the XPath context
2742
 * @val:  the original object
2743
 *
2744
 * This is the cached version of xmlXPathObjectCopy().
2745
 * Acquire a copy of a given object
2746
 *
2747
 * Returns a created or reused created object.
2748
 */
2749
static xmlXPathObjectPtr
2750
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2751
464k
{
2752
464k
    if (val == NULL)
2753
5
  return(NULL);
2754
2755
464k
    if (XP_HAS_CACHE(ctxt)) {
2756
464k
  switch (val->type) {
2757
0
      case XPATH_NODESET:
2758
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2759
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2760
106k
      case XPATH_STRING:
2761
106k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2762
0
      case XPATH_BOOLEAN:
2763
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2764
358k
      case XPATH_NUMBER:
2765
358k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2766
0
      default:
2767
0
    break;
2768
464k
  }
2769
464k
    }
2770
0
    return(xmlXPathObjectCopy(val));
2771
464k
}
2772
2773
/**
2774
 * xmlXPathCacheConvertBoolean:
2775
 * @ctxt: the XPath context
2776
 * @val:  an XPath object
2777
 *
2778
 * This is the cached version of xmlXPathConvertBoolean().
2779
 * Converts an existing object to its boolean() equivalent
2780
 *
2781
 * Returns a created or reused object, the old one is freed (or the operation
2782
 *         is done directly on @val)
2783
 */
2784
static xmlXPathObjectPtr
2785
54.6k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2786
54.6k
    xmlXPathObjectPtr ret;
2787
2788
54.6k
    if (val == NULL)
2789
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2790
54.6k
    if (val->type == XPATH_BOOLEAN)
2791
8.03k
  return(val);
2792
46.6k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2793
46.6k
    xmlXPathReleaseObject(ctxt, val);
2794
46.6k
    return(ret);
2795
54.6k
}
2796
2797
/**
2798
 * xmlXPathCacheConvertNumber:
2799
 * @ctxt: the XPath context
2800
 * @val:  an XPath object
2801
 *
2802
 * This is the cached version of xmlXPathConvertNumber().
2803
 * Converts an existing object to its number() equivalent
2804
 *
2805
 * Returns a created or reused object, the old one is freed (or the operation
2806
 *         is done directly on @val)
2807
 */
2808
static xmlXPathObjectPtr
2809
276k
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2810
276k
    xmlXPathObjectPtr ret;
2811
2812
276k
    if (val == NULL)
2813
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2814
276k
    if (val->type == XPATH_NUMBER)
2815
2
  return(val);
2816
276k
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2817
276k
    xmlXPathReleaseObject(ctxt, val);
2818
276k
    return(ret);
2819
276k
}
2820
2821
/************************************************************************
2822
 *                  *
2823
 *    Parser stacks related functions and macros    *
2824
 *                  *
2825
 ************************************************************************/
2826
2827
/**
2828
 * xmlXPathSetFrame:
2829
 * @ctxt: an XPath parser context
2830
 *
2831
 * Set the callee evaluation frame
2832
 *
2833
 * Returns the previous frame value to be restored once done
2834
 */
2835
static int
2836
15.6k
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2837
15.6k
    int ret;
2838
2839
15.6k
    if (ctxt == NULL)
2840
0
        return(0);
2841
15.6k
    ret = ctxt->valueFrame;
2842
15.6k
    ctxt->valueFrame = ctxt->valueNr;
2843
15.6k
    return(ret);
2844
15.6k
}
2845
2846
/**
2847
 * xmlXPathPopFrame:
2848
 * @ctxt: an XPath parser context
2849
 * @frame: the previous frame value
2850
 *
2851
 * Remove the callee evaluation frame
2852
 */
2853
static void
2854
15.2k
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2855
15.2k
    if (ctxt == NULL)
2856
0
        return;
2857
15.2k
    if (ctxt->valueNr < ctxt->valueFrame) {
2858
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859
0
    }
2860
15.2k
    ctxt->valueFrame = frame;
2861
15.2k
}
2862
2863
/**
2864
 * valuePop:
2865
 * @ctxt: an XPath evaluation context
2866
 *
2867
 * Pops the top XPath object from the value stack
2868
 *
2869
 * Returns the XPath object just removed
2870
 */
2871
xmlXPathObjectPtr
2872
valuePop(xmlXPathParserContextPtr ctxt)
2873
7.93M
{
2874
7.93M
    xmlXPathObjectPtr ret;
2875
2876
7.93M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2877
691k
        return (NULL);
2878
2879
7.24M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2880
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2881
0
        return (NULL);
2882
0
    }
2883
2884
7.24M
    ctxt->valueNr--;
2885
7.24M
    if (ctxt->valueNr > 0)
2886
3.15M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2887
4.09M
    else
2888
4.09M
        ctxt->value = NULL;
2889
7.24M
    ret = ctxt->valueTab[ctxt->valueNr];
2890
7.24M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2891
7.24M
    return (ret);
2892
7.24M
}
2893
/**
2894
 * valuePush:
2895
 * @ctxt:  an XPath evaluation context
2896
 * @value:  the XPath object
2897
 *
2898
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2899
 * a memory error is recorded in the parser context.
2900
 *
2901
 * Returns the number of items on the value stack, or -1 in case of error.
2902
 */
2903
int
2904
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2905
7.25M
{
2906
7.25M
    if (ctxt == NULL) return(-1);
2907
7.25M
    if (value == NULL) {
2908
        /*
2909
         * A NULL value typically indicates that a memory allocation failed,
2910
         * so we set ctxt->error here to propagate the error.
2911
         */
2912
1
  ctxt->error = XPATH_MEMORY_ERROR;
2913
1
        return(-1);
2914
1
    }
2915
7.25M
    if (ctxt->valueNr >= ctxt->valueMax) {
2916
134
        xmlXPathObjectPtr *tmp;
2917
2918
134
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2919
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2920
0
            return (-1);
2921
0
        }
2922
134
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2923
134
                                             2 * ctxt->valueMax *
2924
134
                                             sizeof(ctxt->valueTab[0]));
2925
134
        if (tmp == NULL) {
2926
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2927
0
            return (-1);
2928
0
        }
2929
134
        ctxt->valueMax *= 2;
2930
134
  ctxt->valueTab = tmp;
2931
134
    }
2932
7.25M
    ctxt->valueTab[ctxt->valueNr] = value;
2933
7.25M
    ctxt->value = value;
2934
7.25M
    return (ctxt->valueNr++);
2935
7.25M
}
2936
2937
/**
2938
 * xmlXPathPopBoolean:
2939
 * @ctxt:  an XPath parser context
2940
 *
2941
 * Pops a boolean from the stack, handling conversion if needed.
2942
 * Check error with #xmlXPathCheckError.
2943
 *
2944
 * Returns the boolean
2945
 */
2946
int
2947
179
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2948
179
    xmlXPathObjectPtr obj;
2949
179
    int ret;
2950
2951
179
    obj = valuePop(ctxt);
2952
179
    if (obj == NULL) {
2953
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2954
0
  return(0);
2955
0
    }
2956
179
    if (obj->type != XPATH_BOOLEAN)
2957
88
  ret = xmlXPathCastToBoolean(obj);
2958
91
    else
2959
91
        ret = obj->boolval;
2960
179
    xmlXPathReleaseObject(ctxt->context, obj);
2961
179
    return(ret);
2962
179
}
2963
2964
/**
2965
 * xmlXPathPopNumber:
2966
 * @ctxt:  an XPath parser context
2967
 *
2968
 * Pops a number from the stack, handling conversion if needed.
2969
 * Check error with #xmlXPathCheckError.
2970
 *
2971
 * Returns the number
2972
 */
2973
double
2974
66
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2975
66
    xmlXPathObjectPtr obj;
2976
66
    double ret;
2977
2978
66
    obj = valuePop(ctxt);
2979
66
    if (obj == NULL) {
2980
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2981
0
  return(0);
2982
0
    }
2983
66
    if (obj->type != XPATH_NUMBER)
2984
24
  ret = xmlXPathCastToNumber(obj);
2985
42
    else
2986
42
        ret = obj->floatval;
2987
66
    xmlXPathReleaseObject(ctxt->context, obj);
2988
66
    return(ret);
2989
66
}
2990
2991
/**
2992
 * xmlXPathPopString:
2993
 * @ctxt:  an XPath parser context
2994
 *
2995
 * Pops a string from the stack, handling conversion if needed.
2996
 * Check error with #xmlXPathCheckError.
2997
 *
2998
 * Returns the string
2999
 */
3000
xmlChar *
3001
6.42k
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
3002
6.42k
    xmlXPathObjectPtr obj;
3003
6.42k
    xmlChar * ret;
3004
3005
6.42k
    obj = valuePop(ctxt);
3006
6.42k
    if (obj == NULL) {
3007
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3008
0
  return(NULL);
3009
0
    }
3010
6.42k
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3011
    /* TODO: needs refactoring somewhere else */
3012
6.42k
    if (obj->stringval == ret)
3013
0
  obj->stringval = NULL;
3014
6.42k
    xmlXPathReleaseObject(ctxt->context, obj);
3015
6.42k
    return(ret);
3016
6.42k
}
3017
3018
/**
3019
 * xmlXPathPopNodeSet:
3020
 * @ctxt:  an XPath parser context
3021
 *
3022
 * Pops a node-set from the stack, handling conversion if needed.
3023
 * Check error with #xmlXPathCheckError.
3024
 *
3025
 * Returns the node-set
3026
 */
3027
xmlNodeSetPtr
3028
733
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3029
733
    xmlXPathObjectPtr obj;
3030
733
    xmlNodeSetPtr ret;
3031
3032
733
    if (ctxt == NULL) return(NULL);
3033
733
    if (ctxt->value == NULL) {
3034
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3035
0
  return(NULL);
3036
0
    }
3037
733
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3038
85
  xmlXPathSetTypeError(ctxt);
3039
85
  return(NULL);
3040
85
    }
3041
648
    obj = valuePop(ctxt);
3042
648
    ret = obj->nodesetval;
3043
#if 0
3044
    /* to fix memory leak of not clearing obj->user */
3045
    if (obj->boolval && obj->user != NULL)
3046
        xmlFreeNodeList((xmlNodePtr) obj->user);
3047
#endif
3048
648
    obj->nodesetval = NULL;
3049
648
    xmlXPathReleaseObject(ctxt->context, obj);
3050
648
    return(ret);
3051
733
}
3052
3053
/**
3054
 * xmlXPathPopExternal:
3055
 * @ctxt:  an XPath parser context
3056
 *
3057
 * Pops an external object from the stack, handling conversion if needed.
3058
 * Check error with #xmlXPathCheckError.
3059
 *
3060
 * Returns the object
3061
 */
3062
void *
3063
4
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3064
4
    xmlXPathObjectPtr obj;
3065
4
    void * ret;
3066
3067
4
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3068
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3069
0
  return(NULL);
3070
0
    }
3071
4
    if (ctxt->value->type != XPATH_USERS) {
3072
0
  xmlXPathSetTypeError(ctxt);
3073
0
  return(NULL);
3074
0
    }
3075
4
    obj = valuePop(ctxt);
3076
4
    ret = obj->user;
3077
4
    obj->user = NULL;
3078
4
    xmlXPathReleaseObject(ctxt->context, obj);
3079
4
    return(ret);
3080
4
}
3081
3082
/*
3083
 * Macros for accessing the content. Those should be used only by the parser,
3084
 * and not exported.
3085
 *
3086
 * Dirty macros, i.e. one need to make assumption on the context to use them
3087
 *
3088
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3089
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3090
 *           in ISO-Latin or UTF-8.
3091
 *           This should be used internally by the parser
3092
 *           only to compare to ASCII values otherwise it would break when
3093
 *           running with UTF-8 encoding.
3094
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3095
 *           to compare on ASCII based substring.
3096
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3097
 *           strings within the parser.
3098
 *   CURRENT Returns the current char value, with the full decoding of
3099
 *           UTF-8 if we are using this mode. It returns an int.
3100
 *   NEXT    Skip to the next character, this does the proper decoding
3101
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3102
 *           It returns the pointer to the current xmlChar.
3103
 */
3104
3105
32.1M
#define CUR (*ctxt->cur)
3106
79.6k
#define SKIP(val) ctxt->cur += (val)
3107
592k
#define NXT(val) ctxt->cur[(val)]
3108
33.9k
#define CUR_PTR ctxt->cur
3109
3.48M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3110
3111
#define COPY_BUF(l,b,i,v)                                              \
3112
914k
    if (l == 1) b[i++] = v;                                            \
3113
914k
    else i += xmlCopyChar(l,&b[i],v)
3114
3115
1.62M
#define NEXTL(l)  ctxt->cur += l
3116
3117
#define SKIP_BLANKS             \
3118
11.1M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3119
3120
#define CURRENT (*ctxt->cur)
3121
15.5M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3122
3123
3124
#ifndef DBL_DIG
3125
#define DBL_DIG 16
3126
#endif
3127
#ifndef DBL_EPSILON
3128
#define DBL_EPSILON 1E-9
3129
#endif
3130
3131
166
#define UPPER_DOUBLE 1E9
3132
156
#define LOWER_DOUBLE 1E-5
3133
#define LOWER_DOUBLE_EXP 5
3134
3135
#define INTEGER_DIGITS DBL_DIG
3136
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3137
12
#define EXPONENT_DIGITS (3 + 2)
3138
3139
/**
3140
 * xmlXPathFormatNumber:
3141
 * @number:     number to format
3142
 * @buffer:     output buffer
3143
 * @buffersize: size of output buffer
3144
 *
3145
 * Convert the number into a string representation.
3146
 */
3147
static void
3148
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3149
205
{
3150
205
    switch (xmlXPathIsInf(number)) {
3151
0
    case 1:
3152
0
  if (buffersize > (int)sizeof("Infinity"))
3153
0
      snprintf(buffer, buffersize, "Infinity");
3154
0
  break;
3155
0
    case -1:
3156
0
  if (buffersize > (int)sizeof("-Infinity"))
3157
0
      snprintf(buffer, buffersize, "-Infinity");
3158
0
  break;
3159
205
    default:
3160
205
  if (xmlXPathIsNaN(number)) {
3161
0
      if (buffersize > (int)sizeof("NaN"))
3162
0
    snprintf(buffer, buffersize, "NaN");
3163
205
  } else if (number == 0) {
3164
            /* Omit sign for negative zero. */
3165
0
      snprintf(buffer, buffersize, "0");
3166
205
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3167
205
                   (number == (int) number)) {
3168
39
      char work[30];
3169
39
      char *ptr, *cur;
3170
39
      int value = (int) number;
3171
3172
39
            ptr = &buffer[0];
3173
39
      if (value == 0) {
3174
0
    *ptr++ = '0';
3175
39
      } else {
3176
39
    snprintf(work, 29, "%d", value);
3177
39
    cur = &work[0];
3178
134
    while ((*cur) && (ptr - buffer < buffersize)) {
3179
95
        *ptr++ = *cur++;
3180
95
    }
3181
39
      }
3182
39
      if (ptr - buffer < buffersize) {
3183
39
    *ptr = 0;
3184
39
      } else if (buffersize > 0) {
3185
0
    ptr--;
3186
0
    *ptr = 0;
3187
0
      }
3188
166
  } else {
3189
      /*
3190
        For the dimension of work,
3191
            DBL_DIG is number of significant digits
3192
      EXPONENT is only needed for "scientific notation"
3193
            3 is sign, decimal point, and terminating zero
3194
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3195
        Note that this dimension is slightly (a few characters)
3196
        larger than actually necessary.
3197
      */
3198
166
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3199
166
      int integer_place, fraction_place;
3200
166
      char *ptr;
3201
166
      char *after_fraction;
3202
166
      double absolute_value;
3203
166
      int size;
3204
3205
166
      absolute_value = fabs(number);
3206
3207
      /*
3208
       * First choose format - scientific or regular floating point.
3209
       * In either case, result is in work, and after_fraction points
3210
       * just past the fractional part.
3211
      */
3212
166
      if ( ((absolute_value > UPPER_DOUBLE) ||
3213
166
      (absolute_value < LOWER_DOUBLE)) &&
3214
166
     (absolute_value != 0.0) ) {
3215
    /* Use scientific notation */
3216
12
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3217
12
    fraction_place = DBL_DIG - 1;
3218
12
    size = snprintf(work, sizeof(work),"%*.*e",
3219
12
       integer_place, fraction_place, number);
3220
63
    while ((size > 0) && (work[size] != 'e')) size--;
3221
3222
12
      }
3223
154
      else {
3224
    /* Use regular notation */
3225
154
    if (absolute_value > 0.0) {
3226
154
        integer_place = (int)log10(absolute_value);
3227
154
        if (integer_place > 0)
3228
7
            fraction_place = DBL_DIG - integer_place - 1;
3229
147
        else
3230
147
            fraction_place = DBL_DIG - integer_place;
3231
154
    } else {
3232
0
        fraction_place = 1;
3233
0
    }
3234
154
    size = snprintf(work, sizeof(work), "%0.*f",
3235
154
        fraction_place, number);
3236
154
      }
3237
3238
      /* Remove leading spaces sometimes inserted by snprintf */
3239
174
      while (work[0] == ' ') {
3240
168
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3241
8
    size--;
3242
8
      }
3243
3244
      /* Remove fractional trailing zeroes */
3245
166
      after_fraction = work + size;
3246
166
      ptr = after_fraction;
3247
2.29k
      while (*(--ptr) == '0')
3248
2.12k
    ;
3249
166
      if (*ptr != '.')
3250
166
          ptr++;
3251
217
      while ((*ptr++ = *after_fraction++) != 0);
3252
3253
      /* Finally copy result back to caller */
3254
166
      size = strlen(work) + 1;
3255
166
      if (size > buffersize) {
3256
0
    work[buffersize - 1] = 0;
3257
0
    size = buffersize;
3258
0
      }
3259
166
      memmove(buffer, work, size);
3260
166
  }
3261
205
  break;
3262
205
    }
3263
205
}
3264
3265
3266
/************************************************************************
3267
 *                  *
3268
 *      Routines to handle NodeSets     *
3269
 *                  *
3270
 ************************************************************************/
3271
3272
/**
3273
 * xmlXPathOrderDocElems:
3274
 * @doc:  an input document
3275
 *
3276
 * Call this routine to speed up XPath computation on static documents.
3277
 * This stamps all the element nodes with the document order
3278
 * Like for line information, the order is kept in the element->content
3279
 * field, the value stored is actually - the node number (starting at -1)
3280
 * to be able to differentiate from line numbers.
3281
 *
3282
 * Returns the number of elements found in the document or -1 in case
3283
 *    of error.
3284
 */
3285
long
3286
88
xmlXPathOrderDocElems(xmlDocPtr doc) {
3287
88
    ptrdiff_t count = 0;
3288
88
    xmlNodePtr cur;
3289
3290
88
    if (doc == NULL)
3291
0
  return(-1);
3292
88
    cur = doc->children;
3293
3.52k
    while (cur != NULL) {
3294
3.43k
  if (cur->type == XML_ELEMENT_NODE) {
3295
1.05k
      cur->content = (void *) (-(++count));
3296
1.05k
      if (cur->children != NULL) {
3297
792
    cur = cur->children;
3298
792
    continue;
3299
792
      }
3300
1.05k
  }
3301
2.64k
  if (cur->next != NULL) {
3302
1.84k
      cur = cur->next;
3303
1.84k
      continue;
3304
1.84k
  }
3305
880
  do {
3306
880
      cur = cur->parent;
3307
880
      if (cur == NULL)
3308
0
    break;
3309
880
      if (cur == (xmlNodePtr) doc) {
3310
88
    cur = NULL;
3311
88
    break;
3312
88
      }
3313
792
      if (cur->next != NULL) {
3314
704
    cur = cur->next;
3315
704
    break;
3316
704
      }
3317
792
  } while (cur != NULL);
3318
792
    }
3319
88
    return(count);
3320
88
}
3321
3322
/**
3323
 * xmlXPathCmpNodes:
3324
 * @node1:  the first node
3325
 * @node2:  the second node
3326
 *
3327
 * Compare two nodes w.r.t document order
3328
 *
3329
 * Returns -2 in case of error 1 if first point < second point, 0 if
3330
 *         it's the same node, -1 otherwise
3331
 */
3332
int
3333
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3334
0
    int depth1, depth2;
3335
0
    int attr1 = 0, attr2 = 0;
3336
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3337
0
    xmlNodePtr cur, root;
3338
3339
0
    if ((node1 == NULL) || (node2 == NULL))
3340
0
  return(-2);
3341
    /*
3342
     * a couple of optimizations which will avoid computations in most cases
3343
     */
3344
0
    if (node1 == node2)   /* trivial case */
3345
0
  return(0);
3346
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3347
0
  attr1 = 1;
3348
0
  attrNode1 = node1;
3349
0
  node1 = node1->parent;
3350
0
    }
3351
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3352
0
  attr2 = 1;
3353
0
  attrNode2 = node2;
3354
0
  node2 = node2->parent;
3355
0
    }
3356
0
    if (node1 == node2) {
3357
0
  if (attr1 == attr2) {
3358
      /* not required, but we keep attributes in order */
3359
0
      if (attr1 != 0) {
3360
0
          cur = attrNode2->prev;
3361
0
    while (cur != NULL) {
3362
0
        if (cur == attrNode1)
3363
0
            return (1);
3364
0
        cur = cur->prev;
3365
0
    }
3366
0
    return (-1);
3367
0
      }
3368
0
      return(0);
3369
0
  }
3370
0
  if (attr2 == 1)
3371
0
      return(1);
3372
0
  return(-1);
3373
0
    }
3374
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3375
0
        (node2->type == XML_NAMESPACE_DECL))
3376
0
  return(1);
3377
0
    if (node1 == node2->prev)
3378
0
  return(1);
3379
0
    if (node1 == node2->next)
3380
0
  return(-1);
3381
3382
    /*
3383
     * Speedup using document order if available.
3384
     */
3385
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3386
0
  (node2->type == XML_ELEMENT_NODE) &&
3387
0
  (0 > (ptrdiff_t) node1->content) &&
3388
0
  (0 > (ptrdiff_t) node2->content) &&
3389
0
  (node1->doc == node2->doc)) {
3390
0
  ptrdiff_t l1, l2;
3391
3392
0
  l1 = -((ptrdiff_t) node1->content);
3393
0
  l2 = -((ptrdiff_t) node2->content);
3394
0
  if (l1 < l2)
3395
0
      return(1);
3396
0
  if (l1 > l2)
3397
0
      return(-1);
3398
0
    }
3399
3400
    /*
3401
     * compute depth to root
3402
     */
3403
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3404
0
  if (cur->parent == node1)
3405
0
      return(1);
3406
0
  depth2++;
3407
0
    }
3408
0
    root = cur;
3409
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3410
0
  if (cur->parent == node2)
3411
0
      return(-1);
3412
0
  depth1++;
3413
0
    }
3414
    /*
3415
     * Distinct document (or distinct entities :-( ) case.
3416
     */
3417
0
    if (root != cur) {
3418
0
  return(-2);
3419
0
    }
3420
    /*
3421
     * get the nearest common ancestor.
3422
     */
3423
0
    while (depth1 > depth2) {
3424
0
  depth1--;
3425
0
  node1 = node1->parent;
3426
0
    }
3427
0
    while (depth2 > depth1) {
3428
0
  depth2--;
3429
0
  node2 = node2->parent;
3430
0
    }
3431
0
    while (node1->parent != node2->parent) {
3432
0
  node1 = node1->parent;
3433
0
  node2 = node2->parent;
3434
  /* should not happen but just in case ... */
3435
0
  if ((node1 == NULL) || (node2 == NULL))
3436
0
      return(-2);
3437
0
    }
3438
    /*
3439
     * Find who's first.
3440
     */
3441
0
    if (node1 == node2->prev)
3442
0
  return(1);
3443
0
    if (node1 == node2->next)
3444
0
  return(-1);
3445
    /*
3446
     * Speedup using document order if available.
3447
     */
3448
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3449
0
  (node2->type == XML_ELEMENT_NODE) &&
3450
0
  (0 > (ptrdiff_t) node1->content) &&
3451
0
  (0 > (ptrdiff_t) node2->content) &&
3452
0
  (node1->doc == node2->doc)) {
3453
0
  ptrdiff_t l1, l2;
3454
3455
0
  l1 = -((ptrdiff_t) node1->content);
3456
0
  l2 = -((ptrdiff_t) node2->content);
3457
0
  if (l1 < l2)
3458
0
      return(1);
3459
0
  if (l1 > l2)
3460
0
      return(-1);
3461
0
    }
3462
3463
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3464
0
  if (cur == node2)
3465
0
      return(1);
3466
0
    return(-1); /* assume there is no sibling list corruption */
3467
0
}
3468
3469
/**
3470
 * xmlXPathNodeSetSort:
3471
 * @set:  the node set
3472
 *
3473
 * Sort the node set in document order
3474
 */
3475
void
3476
46.7k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3477
#ifndef WITH_TIM_SORT
3478
    int i, j, incr, len;
3479
    xmlNodePtr tmp;
3480
#endif
3481
3482
46.7k
    if (set == NULL)
3483
0
  return;
3484
3485
#ifndef WITH_TIM_SORT
3486
    /*
3487
     * Use the old Shell's sort implementation to sort the node-set
3488
     * Timsort ought to be quite faster
3489
     */
3490
    len = set->nodeNr;
3491
    for (incr = len / 2; incr > 0; incr /= 2) {
3492
  for (i = incr; i < len; i++) {
3493
      j = i - incr;
3494
      while (j >= 0) {
3495
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3496
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3497
      set->nodeTab[j + incr]) == -1)
3498
#else
3499
    if (xmlXPathCmpNodes(set->nodeTab[j],
3500
      set->nodeTab[j + incr]) == -1)
3501
#endif
3502
    {
3503
        tmp = set->nodeTab[j];
3504
        set->nodeTab[j] = set->nodeTab[j + incr];
3505
        set->nodeTab[j + incr] = tmp;
3506
        j -= incr;
3507
    } else
3508
        break;
3509
      }
3510
  }
3511
    }
3512
#else /* WITH_TIM_SORT */
3513
46.7k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3514
46.7k
#endif /* WITH_TIM_SORT */
3515
46.7k
}
3516
3517
6.61M
#define XML_NODESET_DEFAULT 10
3518
/**
3519
 * xmlXPathNodeSetDupNs:
3520
 * @node:  the parent node of the namespace XPath node
3521
 * @ns:  the libxml namespace declaration node.
3522
 *
3523
 * Namespace node in libxml don't match the XPath semantic. In a node set
3524
 * the namespace nodes are duplicated and the next pointer is set to the
3525
 * parent node in the XPath semantic.
3526
 *
3527
 * Returns the newly created object.
3528
 */
3529
static xmlNodePtr
3530
315k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3531
315k
    xmlNsPtr cur;
3532
3533
315k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3534
0
  return(NULL);
3535
315k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3536
0
  return((xmlNodePtr) ns);
3537
3538
    /*
3539
     * Allocate a new Namespace and fill the fields.
3540
     */
3541
315k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3542
315k
    if (cur == NULL) {
3543
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3544
0
  return(NULL);
3545
0
    }
3546
315k
    memset(cur, 0, sizeof(xmlNs));
3547
315k
    cur->type = XML_NAMESPACE_DECL;
3548
315k
    if (ns->href != NULL)
3549
315k
  cur->href = xmlStrdup(ns->href);
3550
315k
    if (ns->prefix != NULL)
3551
315k
  cur->prefix = xmlStrdup(ns->prefix);
3552
315k
    cur->next = (xmlNsPtr) node;
3553
315k
    return((xmlNodePtr) cur);
3554
315k
}
3555
3556
/**
3557
 * xmlXPathNodeSetFreeNs:
3558
 * @ns:  the XPath namespace node found in a nodeset.
3559
 *
3560
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3561
 * the namespace nodes are duplicated and the next pointer is set to the
3562
 * parent node in the XPath semantic. Check if such a node needs to be freed
3563
 */
3564
void
3565
314k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3566
314k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3567
0
  return;
3568
3569
314k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3570
314k
  if (ns->href != NULL)
3571
314k
      xmlFree((xmlChar *)ns->href);
3572
314k
  if (ns->prefix != NULL)
3573
314k
      xmlFree((xmlChar *)ns->prefix);
3574
314k
  xmlFree(ns);
3575
314k
    }
3576
314k
}
3577
3578
/**
3579
 * xmlXPathNodeSetCreate:
3580
 * @val:  an initial xmlNodePtr, or NULL
3581
 *
3582
 * Create a new xmlNodeSetPtr of type double and of value @val
3583
 *
3584
 * Returns the newly created object.
3585
 */
3586
xmlNodeSetPtr
3587
3.42M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3588
3.42M
    xmlNodeSetPtr ret;
3589
3590
3.42M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3591
3.42M
    if (ret == NULL) {
3592
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
  return(NULL);
3594
0
    }
3595
3.42M
    memset(ret, 0 , sizeof(xmlNodeSet));
3596
3.42M
    if (val != NULL) {
3597
1.72M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3598
1.72M
               sizeof(xmlNodePtr));
3599
1.72M
  if (ret->nodeTab == NULL) {
3600
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3601
0
      xmlFree(ret);
3602
0
      return(NULL);
3603
0
  }
3604
1.72M
  memset(ret->nodeTab, 0 ,
3605
1.72M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3606
1.72M
        ret->nodeMax = XML_NODESET_DEFAULT;
3607
1.72M
  if (val->type == XML_NAMESPACE_DECL) {
3608
141
      xmlNsPtr ns = (xmlNsPtr) val;
3609
3610
            /* TODO: Check memory error. */
3611
141
      ret->nodeTab[ret->nodeNr++] =
3612
141
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3613
141
  } else
3614
1.72M
      ret->nodeTab[ret->nodeNr++] = val;
3615
1.72M
    }
3616
3.42M
    return(ret);
3617
3.42M
}
3618
3619
/**
3620
 * xmlXPathNodeSetContains:
3621
 * @cur:  the node-set
3622
 * @val:  the node
3623
 *
3624
 * checks whether @cur contains @val
3625
 *
3626
 * Returns true (1) if @cur contains @val, false (0) otherwise
3627
 */
3628
int
3629
103
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3630
103
    int i;
3631
3632
103
    if ((cur == NULL) || (val == NULL)) return(0);
3633
103
    if (val->type == XML_NAMESPACE_DECL) {
3634
0
  for (i = 0; i < cur->nodeNr; i++) {
3635
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3636
0
    xmlNsPtr ns1, ns2;
3637
3638
0
    ns1 = (xmlNsPtr) val;
3639
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3640
0
    if (ns1 == ns2)
3641
0
        return(1);
3642
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3643
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3644
0
        return(1);
3645
0
      }
3646
0
  }
3647
103
    } else {
3648
426
  for (i = 0; i < cur->nodeNr; i++) {
3649
358
      if (cur->nodeTab[i] == val)
3650
35
    return(1);
3651
358
  }
3652
103
    }
3653
68
    return(0);
3654
103
}
3655
3656
/**
3657
 * xmlXPathNodeSetAddNs:
3658
 * @cur:  the initial node set
3659
 * @node:  the hosting node
3660
 * @ns:  a the namespace node
3661
 *
3662
 * add a new namespace node to an existing NodeSet
3663
 *
3664
 * Returns 0 in case of success and -1 in case of error
3665
 */
3666
int
3667
110k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3668
110k
    int i;
3669
3670
3671
110k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3672
110k
        (ns->type != XML_NAMESPACE_DECL) ||
3673
110k
  (node->type != XML_ELEMENT_NODE))
3674
0
  return(-1);
3675
3676
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3677
    /*
3678
     * prevent duplicates
3679
     */
3680
145k
    for (i = 0;i < cur->nodeNr;i++) {
3681
35.5k
        if ((cur->nodeTab[i] != NULL) &&
3682
35.5k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3683
35.5k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3684
35.5k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3685
0
      return(0);
3686
35.5k
    }
3687
3688
    /*
3689
     * grow the nodeTab if needed
3690
     */
3691
110k
    if (cur->nodeMax == 0) {
3692
5.64k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3693
5.64k
               sizeof(xmlNodePtr));
3694
5.64k
  if (cur->nodeTab == NULL) {
3695
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3696
0
      return(-1);
3697
0
  }
3698
5.64k
  memset(cur->nodeTab, 0 ,
3699
5.64k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3700
5.64k
        cur->nodeMax = XML_NODESET_DEFAULT;
3701
104k
    } else if (cur->nodeNr == cur->nodeMax) {
3702
0
        xmlNodePtr *temp;
3703
3704
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3705
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3706
0
            return(-1);
3707
0
        }
3708
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3709
0
              sizeof(xmlNodePtr));
3710
0
  if (temp == NULL) {
3711
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3712
0
      return(-1);
3713
0
  }
3714
0
        cur->nodeMax *= 2;
3715
0
  cur->nodeTab = temp;
3716
0
    }
3717
    /* TODO: Check memory error. */
3718
110k
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3719
110k
    return(0);
3720
110k
}
3721
3722
/**
3723
 * xmlXPathNodeSetAdd:
3724
 * @cur:  the initial node set
3725
 * @val:  a new xmlNodePtr
3726
 *
3727
 * add a new xmlNodePtr to an existing NodeSet
3728
 *
3729
 * Returns 0 in case of success, and -1 in case of error
3730
 */
3731
int
3732
37
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3733
37
    int i;
3734
3735
37
    if ((cur == NULL) || (val == NULL)) return(-1);
3736
3737
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3738
    /*
3739
     * prevent duplicates
3740
     */
3741
235
    for (i = 0;i < cur->nodeNr;i++)
3742
198
        if (cur->nodeTab[i] == val) return(0);
3743
3744
    /*
3745
     * grow the nodeTab if needed
3746
     */
3747
37
    if (cur->nodeMax == 0) {
3748
4
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3749
4
               sizeof(xmlNodePtr));
3750
4
  if (cur->nodeTab == NULL) {
3751
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3752
0
      return(-1);
3753
0
  }
3754
4
  memset(cur->nodeTab, 0 ,
3755
4
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3756
4
        cur->nodeMax = XML_NODESET_DEFAULT;
3757
33
    } else if (cur->nodeNr == cur->nodeMax) {
3758
3
        xmlNodePtr *temp;
3759
3760
3
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3761
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3762
0
            return(-1);
3763
0
        }
3764
3
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3765
3
              sizeof(xmlNodePtr));
3766
3
  if (temp == NULL) {
3767
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3768
0
      return(-1);
3769
0
  }
3770
3
        cur->nodeMax *= 2;
3771
3
  cur->nodeTab = temp;
3772
3
    }
3773
37
    if (val->type == XML_NAMESPACE_DECL) {
3774
0
  xmlNsPtr ns = (xmlNsPtr) val;
3775
3776
        /* TODO: Check memory error. */
3777
0
  cur->nodeTab[cur->nodeNr++] =
3778
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3779
0
    } else
3780
37
  cur->nodeTab[cur->nodeNr++] = val;
3781
37
    return(0);
3782
37
}
3783
3784
/**
3785
 * xmlXPathNodeSetAddUnique:
3786
 * @cur:  the initial node set
3787
 * @val:  a new xmlNodePtr
3788
 *
3789
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3790
 * when we are sure the node is not already in the set.
3791
 *
3792
 * Returns 0 in case of success and -1 in case of failure
3793
 */
3794
int
3795
15.0M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3796
15.0M
    if ((cur == NULL) || (val == NULL)) return(-1);
3797
3798
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3799
    /*
3800
     * grow the nodeTab if needed
3801
     */
3802
15.0M
    if (cur->nodeMax == 0) {
3803
338k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3804
338k
               sizeof(xmlNodePtr));
3805
338k
  if (cur->nodeTab == NULL) {
3806
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3807
0
      return(-1);
3808
0
  }
3809
338k
  memset(cur->nodeTab, 0 ,
3810
338k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3811
338k
        cur->nodeMax = XML_NODESET_DEFAULT;
3812
14.7M
    } else if (cur->nodeNr == cur->nodeMax) {
3813
146k
        xmlNodePtr *temp;
3814
3815
146k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3816
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3817
0
            return(-1);
3818
0
        }
3819
146k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3820
146k
              sizeof(xmlNodePtr));
3821
146k
  if (temp == NULL) {
3822
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3823
0
      return(-1);
3824
0
  }
3825
146k
  cur->nodeTab = temp;
3826
146k
        cur->nodeMax *= 2;
3827
146k
    }
3828
15.0M
    if (val->type == XML_NAMESPACE_DECL) {
3829
191k
  xmlNsPtr ns = (xmlNsPtr) val;
3830
3831
        /* TODO: Check memory error. */
3832
191k
  cur->nodeTab[cur->nodeNr++] =
3833
191k
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3834
191k
    } else
3835
14.8M
  cur->nodeTab[cur->nodeNr++] = val;
3836
15.0M
    return(0);
3837
15.0M
}
3838
3839
/**
3840
 * xmlXPathNodeSetMerge:
3841
 * @val1:  the first NodeSet or NULL
3842
 * @val2:  the second NodeSet
3843
 *
3844
 * Merges two nodesets, all nodes from @val2 are added to @val1
3845
 * if @val1 is NULL, a new set is created and copied from @val2
3846
 *
3847
 * Returns @val1 once extended or NULL in case of error.
3848
 */
3849
xmlNodeSetPtr
3850
998k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3851
998k
    int i, j, initNr, skip;
3852
998k
    xmlNodePtr n1, n2;
3853
3854
998k
    if (val2 == NULL) return(val1);
3855
996k
    if (val1 == NULL) {
3856
83.7k
  val1 = xmlXPathNodeSetCreate(NULL);
3857
83.7k
    if (val1 == NULL)
3858
0
        return (NULL);
3859
#if 0
3860
  /*
3861
  * TODO: The optimization won't work in every case, since
3862
  *  those nasty namespace nodes need to be added with
3863
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3864
  *  memcpy is not possible.
3865
  *  If there was a flag on the nodesetval, indicating that
3866
  *  some temporary nodes are in, that would be helpful.
3867
  */
3868
  /*
3869
  * Optimization: Create an equally sized node-set
3870
  * and memcpy the content.
3871
  */
3872
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3873
  if (val1 == NULL)
3874
      return(NULL);
3875
  if (val2->nodeNr != 0) {
3876
      if (val2->nodeNr == 1)
3877
    *(val1->nodeTab) = *(val2->nodeTab);
3878
      else {
3879
    memcpy(val1->nodeTab, val2->nodeTab,
3880
        val2->nodeNr * sizeof(xmlNodePtr));
3881
      }
3882
      val1->nodeNr = val2->nodeNr;
3883
  }
3884
  return(val1);
3885
#endif
3886
83.7k
    }
3887
3888
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3889
996k
    initNr = val1->nodeNr;
3890
3891
1.23M
    for (i = 0;i < val2->nodeNr;i++) {
3892
242k
  n2 = val2->nodeTab[i];
3893
  /*
3894
   * check against duplicates
3895
   */
3896
242k
  skip = 0;
3897
597k
  for (j = 0; j < initNr; j++) {
3898
362k
      n1 = val1->nodeTab[j];
3899
362k
      if (n1 == n2) {
3900
7.49k
    skip = 1;
3901
7.49k
    break;
3902
355k
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3903
355k
           (n2->type == XML_NAMESPACE_DECL)) {
3904
3.82k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3905
3.82k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3906
464
      ((xmlNsPtr) n2)->prefix)))
3907
258
    {
3908
258
        skip = 1;
3909
258
        break;
3910
258
    }
3911
3.82k
      }
3912
362k
  }
3913
242k
  if (skip)
3914
7.74k
      continue;
3915
3916
  /*
3917
   * grow the nodeTab if needed
3918
   */
3919
234k
  if (val1->nodeMax == 0) {
3920
79.4k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3921
79.4k
                sizeof(xmlNodePtr));
3922
79.4k
      if (val1->nodeTab == NULL) {
3923
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3924
0
    return(NULL);
3925
0
      }
3926
79.4k
      memset(val1->nodeTab, 0 ,
3927
79.4k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3928
79.4k
      val1->nodeMax = XML_NODESET_DEFAULT;
3929
155k
  } else if (val1->nodeNr == val1->nodeMax) {
3930
5.72k
      xmlNodePtr *temp;
3931
3932
5.72k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3933
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3934
0
                return(NULL);
3935
0
            }
3936
5.72k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3937
5.72k
               sizeof(xmlNodePtr));
3938
5.72k
      if (temp == NULL) {
3939
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3940
0
    return(NULL);
3941
0
      }
3942
5.72k
      val1->nodeTab = temp;
3943
5.72k
      val1->nodeMax *= 2;
3944
5.72k
  }
3945
234k
  if (n2->type == XML_NAMESPACE_DECL) {
3946
13.3k
      xmlNsPtr ns = (xmlNsPtr) n2;
3947
3948
            /* TODO: Check memory error. */
3949
13.3k
      val1->nodeTab[val1->nodeNr++] =
3950
13.3k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3951
13.3k
  } else
3952
221k
      val1->nodeTab[val1->nodeNr++] = n2;
3953
234k
    }
3954
3955
996k
    return(val1);
3956
996k
}
3957
3958
3959
/**
3960
 * xmlXPathNodeSetMergeAndClear:
3961
 * @set1:  the first NodeSet or NULL
3962
 * @set2:  the second NodeSet
3963
 *
3964
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3965
 * Checks for duplicate nodes. Clears set2.
3966
 *
3967
 * Returns @set1 once extended or NULL in case of error.
3968
 */
3969
static xmlNodeSetPtr
3970
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3971
719k
{
3972
719k
    {
3973
719k
  int i, j, initNbSet1;
3974
719k
  xmlNodePtr n1, n2;
3975
3976
719k
  initNbSet1 = set1->nodeNr;
3977
11.4M
  for (i = 0;i < set2->nodeNr;i++) {
3978
10.7M
      n2 = set2->nodeTab[i];
3979
      /*
3980
      * Skip duplicates.
3981
      */
3982
12.9G
      for (j = 0; j < initNbSet1; j++) {
3983
12.9G
    n1 = set1->nodeTab[j];
3984
12.9G
    if (n1 == n2) {
3985
9.88M
        goto skip_node;
3986
12.9G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987
12.9G
        (n2->type == XML_NAMESPACE_DECL))
3988
711M
    {
3989
711M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990
711M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991
801
      ((xmlNsPtr) n2)->prefix)))
3992
0
        {
3993
      /*
3994
      * Free the namespace node.
3995
      */
3996
0
      set2->nodeTab[i] = NULL;
3997
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3998
0
      goto skip_node;
3999
0
        }
4000
711M
    }
4001
12.9G
      }
4002
      /*
4003
      * grow the nodeTab if needed
4004
      */
4005
835k
      if (set1->nodeMax == 0) {
4006
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008
0
    if (set1->nodeTab == NULL) {
4009
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4010
0
        return(NULL);
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
835k
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
8.28k
    xmlNodePtr *temp;
4017
4018
8.28k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    return(NULL);
4021
0
                }
4022
8.28k
    temp = (xmlNodePtr *) xmlRealloc(
4023
8.28k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
8.28k
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        return(NULL);
4027
0
    }
4028
8.28k
    set1->nodeTab = temp;
4029
8.28k
    set1->nodeMax *= 2;
4030
8.28k
      }
4031
835k
      set1->nodeTab[set1->nodeNr++] = n2;
4032
10.7M
skip_node:
4033
10.7M
      {}
4034
10.7M
  }
4035
719k
    }
4036
719k
    set2->nodeNr = 0;
4037
719k
    return(set1);
4038
719k
}
4039
4040
/**
4041
 * xmlXPathNodeSetMergeAndClearNoDupls:
4042
 * @set1:  the first NodeSet or NULL
4043
 * @set2:  the second NodeSet
4044
 *
4045
 * Merges two nodesets, all nodes from @set2 are added to @set1.
4046
 * Doesn't check for duplicate nodes. Clears set2.
4047
 *
4048
 * Returns @set1 once extended or NULL in case of error.
4049
 */
4050
static xmlNodeSetPtr
4051
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4052
143k
{
4053
143k
    {
4054
143k
  int i;
4055
143k
  xmlNodePtr n2;
4056
4057
334k
  for (i = 0;i < set2->nodeNr;i++) {
4058
191k
      n2 = set2->nodeTab[i];
4059
191k
      if (set1->nodeMax == 0) {
4060
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4061
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4062
0
    if (set1->nodeTab == NULL) {
4063
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4064
0
        return(NULL);
4065
0
    }
4066
0
    memset(set1->nodeTab, 0,
4067
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4068
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4069
191k
      } else if (set1->nodeNr >= set1->nodeMax) {
4070
6.00k
    xmlNodePtr *temp;
4071
4072
6.00k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4073
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4074
0
                    return(NULL);
4075
0
                }
4076
6.00k
    temp = (xmlNodePtr *) xmlRealloc(
4077
6.00k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4078
6.00k
    if (temp == NULL) {
4079
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4080
0
        return(NULL);
4081
0
    }
4082
6.00k
    set1->nodeTab = temp;
4083
6.00k
    set1->nodeMax *= 2;
4084
6.00k
      }
4085
191k
      set1->nodeTab[set1->nodeNr++] = n2;
4086
191k
  }
4087
143k
    }
4088
143k
    set2->nodeNr = 0;
4089
143k
    return(set1);
4090
143k
}
4091
4092
/**
4093
 * xmlXPathNodeSetDel:
4094
 * @cur:  the initial node set
4095
 * @val:  an xmlNodePtr
4096
 *
4097
 * Removes an xmlNodePtr from an existing NodeSet
4098
 */
4099
void
4100
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4101
0
    int i;
4102
4103
0
    if (cur == NULL) return;
4104
0
    if (val == NULL) return;
4105
4106
    /*
4107
     * find node in nodeTab
4108
     */
4109
0
    for (i = 0;i < cur->nodeNr;i++)
4110
0
        if (cur->nodeTab[i] == val) break;
4111
4112
0
    if (i >= cur->nodeNr) { /* not found */
4113
#ifdef DEBUG
4114
        xmlGenericError(xmlGenericErrorContext,
4115
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4116
    val->name);
4117
#endif
4118
0
        return;
4119
0
    }
4120
0
    if ((cur->nodeTab[i] != NULL) &&
4121
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4122
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4123
0
    cur->nodeNr--;
4124
0
    for (;i < cur->nodeNr;i++)
4125
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4126
0
    cur->nodeTab[cur->nodeNr] = NULL;
4127
0
}
4128
4129
/**
4130
 * xmlXPathNodeSetRemove:
4131
 * @cur:  the initial node set
4132
 * @val:  the index to remove
4133
 *
4134
 * Removes an entry from an existing NodeSet list.
4135
 */
4136
void
4137
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4138
0
    if (cur == NULL) return;
4139
0
    if (val >= cur->nodeNr) return;
4140
0
    if ((cur->nodeTab[val] != NULL) &&
4141
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4142
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4143
0
    cur->nodeNr--;
4144
0
    for (;val < cur->nodeNr;val++)
4145
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4146
0
    cur->nodeTab[cur->nodeNr] = NULL;
4147
0
}
4148
4149
/**
4150
 * xmlXPathFreeNodeSet:
4151
 * @obj:  the xmlNodeSetPtr to free
4152
 *
4153
 * Free the NodeSet compound (not the actual nodes !).
4154
 */
4155
void
4156
3.25M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4157
3.25M
    if (obj == NULL) return;
4158
3.25M
    if (obj->nodeTab != NULL) {
4159
1.98M
  int i;
4160
4161
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4162
8.22M
  for (i = 0;i < obj->nodeNr;i++)
4163
6.23M
      if ((obj->nodeTab[i] != NULL) &&
4164
6.23M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4165
165k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4166
1.98M
  xmlFree(obj->nodeTab);
4167
1.98M
    }
4168
3.25M
    xmlFree(obj);
4169
3.25M
}
4170
4171
/**
4172
 * xmlXPathNodeSetClearFromPos:
4173
 * @set: the node set to be cleared
4174
 * @pos: the start position to clear from
4175
 *
4176
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4177
 * are feed) starting with the entry at @pos, but does *not* free the list
4178
 * itself. Sets the length of the list to @pos.
4179
 */
4180
static void
4181
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4182
445
{
4183
445
    if ((set == NULL) || (pos >= set->nodeNr))
4184
0
  return;
4185
445
    else if ((hasNsNodes)) {
4186
57
  int i;
4187
57
  xmlNodePtr node;
4188
4189
270
  for (i = pos; i < set->nodeNr; i++) {
4190
213
      node = set->nodeTab[i];
4191
213
      if ((node != NULL) &&
4192
213
    (node->type == XML_NAMESPACE_DECL))
4193
55
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4194
213
  }
4195
57
    }
4196
445
    set->nodeNr = pos;
4197
445
}
4198
4199
/**
4200
 * xmlXPathNodeSetClear:
4201
 * @set:  the node set to clear
4202
 *
4203
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4204
 * are feed), but does *not* free the list itself. Sets the length of the
4205
 * list to 0.
4206
 */
4207
static void
4208
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4209
411
{
4210
411
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4211
411
}
4212
4213
/**
4214
 * xmlXPathNodeSetKeepLast:
4215
 * @set: the node set to be cleared
4216
 *
4217
 * Move the last node to the first position and clear temporary XPath objects
4218
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4219
 * to 1.
4220
 */
4221
static void
4222
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4223
52
{
4224
52
    int i;
4225
52
    xmlNodePtr node;
4226
4227
52
    if ((set == NULL) || (set->nodeNr <= 1))
4228
0
  return;
4229
1.69k
    for (i = 0; i < set->nodeNr - 1; i++) {
4230
1.64k
        node = set->nodeTab[i];
4231
1.64k
        if ((node != NULL) &&
4232
1.64k
            (node->type == XML_NAMESPACE_DECL))
4233
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4234
1.64k
    }
4235
52
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4236
52
    set->nodeNr = 1;
4237
52
}
4238
4239
/**
4240
 * xmlXPathFreeValueTree:
4241
 * @obj:  the xmlNodeSetPtr to free
4242
 *
4243
 * Free the NodeSet compound and the actual tree, this is different
4244
 * from xmlXPathFreeNodeSet()
4245
 */
4246
static void
4247
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4248
0
    int i;
4249
4250
0
    if (obj == NULL) return;
4251
4252
0
    if (obj->nodeTab != NULL) {
4253
0
  for (i = 0;i < obj->nodeNr;i++) {
4254
0
      if (obj->nodeTab[i] != NULL) {
4255
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4256
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4257
0
    } else {
4258
0
        xmlFreeNodeList(obj->nodeTab[i]);
4259
0
    }
4260
0
      }
4261
0
  }
4262
0
  xmlFree(obj->nodeTab);
4263
0
    }
4264
0
    xmlFree(obj);
4265
0
}
4266
4267
#if defined(DEBUG) || defined(DEBUG_STEP)
4268
/**
4269
 * xmlGenericErrorContextNodeSet:
4270
 * @output:  a FILE * for the output
4271
 * @obj:  the xmlNodeSetPtr to display
4272
 *
4273
 * Quick display of a NodeSet
4274
 */
4275
void
4276
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4277
    int i;
4278
4279
    if (output == NULL) output = xmlGenericErrorContext;
4280
    if (obj == NULL)  {
4281
        fprintf(output, "NodeSet == NULL !\n");
4282
  return;
4283
    }
4284
    if (obj->nodeNr == 0) {
4285
        fprintf(output, "NodeSet is empty\n");
4286
  return;
4287
    }
4288
    if (obj->nodeTab == NULL) {
4289
  fprintf(output, " nodeTab == NULL !\n");
4290
  return;
4291
    }
4292
    for (i = 0; i < obj->nodeNr; i++) {
4293
        if (obj->nodeTab[i] == NULL) {
4294
      fprintf(output, " NULL !\n");
4295
      return;
4296
        }
4297
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4298
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4299
      fprintf(output, " /");
4300
  else if (obj->nodeTab[i]->name == NULL)
4301
      fprintf(output, " noname!");
4302
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4303
    }
4304
    fprintf(output, "\n");
4305
}
4306
#endif
4307
4308
/**
4309
 * xmlXPathNewNodeSet:
4310
 * @val:  the NodePtr value
4311
 *
4312
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4313
 * it with the single Node @val
4314
 *
4315
 * Returns the newly created object.
4316
 */
4317
xmlXPathObjectPtr
4318
2.64M
xmlXPathNewNodeSet(xmlNodePtr val) {
4319
2.64M
    xmlXPathObjectPtr ret;
4320
4321
2.64M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4322
2.64M
    if (ret == NULL) {
4323
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4324
0
  return(NULL);
4325
0
    }
4326
2.64M
    memset(ret, 0 , sizeof(xmlXPathObject));
4327
2.64M
    ret->type = XPATH_NODESET;
4328
2.64M
    ret->boolval = 0;
4329
    /* TODO: Check memory error. */
4330
2.64M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4331
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4332
#ifdef XP_DEBUG_OBJ_USAGE
4333
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4334
#endif
4335
2.64M
    return(ret);
4336
2.64M
}
4337
4338
/**
4339
 * xmlXPathNewValueTree:
4340
 * @val:  the NodePtr value
4341
 *
4342
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4343
 * it with the tree root @val
4344
 *
4345
 * Returns the newly created object.
4346
 */
4347
xmlXPathObjectPtr
4348
0
xmlXPathNewValueTree(xmlNodePtr val) {
4349
0
    xmlXPathObjectPtr ret;
4350
4351
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4352
0
    if (ret == NULL) {
4353
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4354
0
  return(NULL);
4355
0
    }
4356
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4357
0
    ret->type = XPATH_XSLT_TREE;
4358
0
    ret->boolval = 1;
4359
0
    ret->user = (void *) val;
4360
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4361
#ifdef XP_DEBUG_OBJ_USAGE
4362
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4363
#endif
4364
0
    return(ret);
4365
0
}
4366
4367
/**
4368
 * xmlXPathNewNodeSetList:
4369
 * @val:  an existing NodeSet
4370
 *
4371
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4372
 * it with the Nodeset @val
4373
 *
4374
 * Returns the newly created object.
4375
 */
4376
xmlXPathObjectPtr
4377
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4378
0
{
4379
0
    xmlXPathObjectPtr ret;
4380
0
    int i;
4381
4382
0
    if (val == NULL)
4383
0
        ret = NULL;
4384
0
    else if (val->nodeTab == NULL)
4385
0
        ret = xmlXPathNewNodeSet(NULL);
4386
0
    else {
4387
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4388
0
        if (ret) {
4389
0
            for (i = 1; i < val->nodeNr; ++i) {
4390
                /* TODO: Propagate memory error. */
4391
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4392
0
        < 0) break;
4393
0
      }
4394
0
  }
4395
0
    }
4396
4397
0
    return (ret);
4398
0
}
4399
4400
/**
4401
 * xmlXPathWrapNodeSet:
4402
 * @val:  the NodePtr value
4403
 *
4404
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4405
 *
4406
 * Returns the newly created object.
4407
 */
4408
xmlXPathObjectPtr
4409
155k
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4410
155k
    xmlXPathObjectPtr ret;
4411
4412
155k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4413
155k
    if (ret == NULL) {
4414
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4415
0
  return(NULL);
4416
0
    }
4417
155k
    memset(ret, 0 , sizeof(xmlXPathObject));
4418
155k
    ret->type = XPATH_NODESET;
4419
155k
    ret->nodesetval = val;
4420
#ifdef XP_DEBUG_OBJ_USAGE
4421
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4422
#endif
4423
155k
    return(ret);
4424
155k
}
4425
4426
/**
4427
 * xmlXPathFreeNodeSetList:
4428
 * @obj:  an existing NodeSetList object
4429
 *
4430
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4431
 * the list contrary to xmlXPathFreeObject().
4432
 */
4433
void
4434
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4435
0
    if (obj == NULL) return;
4436
#ifdef XP_DEBUG_OBJ_USAGE
4437
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4438
#endif
4439
0
    xmlFree(obj);
4440
0
}
4441
4442
/**
4443
 * xmlXPathDifference:
4444
 * @nodes1:  a node-set
4445
 * @nodes2:  a node-set
4446
 *
4447
 * Implements the EXSLT - Sets difference() function:
4448
 *    node-set set:difference (node-set, node-set)
4449
 *
4450
 * Returns the difference between the two node sets, or nodes1 if
4451
 *         nodes2 is empty
4452
 */
4453
xmlNodeSetPtr
4454
10
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4455
10
    xmlNodeSetPtr ret;
4456
10
    int i, l1;
4457
10
    xmlNodePtr cur;
4458
4459
10
    if (xmlXPathNodeSetIsEmpty(nodes2))
4460
2
  return(nodes1);
4461
4462
    /* TODO: Check memory error. */
4463
8
    ret = xmlXPathNodeSetCreate(NULL);
4464
8
    if (xmlXPathNodeSetIsEmpty(nodes1))
4465
3
  return(ret);
4466
4467
5
    l1 = xmlXPathNodeSetGetLength(nodes1);
4468
4469
62
    for (i = 0; i < l1; i++) {
4470
57
  cur = xmlXPathNodeSetItem(nodes1, i);
4471
57
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4472
            /* TODO: Propagate memory error. */
4473
40
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4474
0
          break;
4475
40
  }
4476
57
    }
4477
5
    return(ret);
4478
8
}
4479
4480
/**
4481
 * xmlXPathIntersection:
4482
 * @nodes1:  a node-set
4483
 * @nodes2:  a node-set
4484
 *
4485
 * Implements the EXSLT - Sets intersection() function:
4486
 *    node-set set:intersection (node-set, node-set)
4487
 *
4488
 * Returns a node set comprising the nodes that are within both the
4489
 *         node sets passed as arguments
4490
 */
4491
xmlNodeSetPtr
4492
5
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4493
5
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4494
5
    int i, l1;
4495
5
    xmlNodePtr cur;
4496
4497
5
    if (ret == NULL)
4498
0
        return(ret);
4499
5
    if (xmlXPathNodeSetIsEmpty(nodes1))
4500
2
  return(ret);
4501
3
    if (xmlXPathNodeSetIsEmpty(nodes2))
4502
1
  return(ret);
4503
4504
2
    l1 = xmlXPathNodeSetGetLength(nodes1);
4505
4506
26
    for (i = 0; i < l1; i++) {
4507
24
  cur = xmlXPathNodeSetItem(nodes1, i);
4508
24
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4509
            /* TODO: Propagate memory error. */
4510
8
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4511
0
          break;
4512
8
  }
4513
24
    }
4514
2
    return(ret);
4515
3
}
4516
4517
/**
4518
 * xmlXPathDistinctSorted:
4519
 * @nodes:  a node-set, sorted by document order
4520
 *
4521
 * Implements the EXSLT - Sets distinct() function:
4522
 *    node-set set:distinct (node-set)
4523
 *
4524
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4525
 *         it is empty
4526
 */
4527
xmlNodeSetPtr
4528
4
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4529
4
    xmlNodeSetPtr ret;
4530
4
    xmlHashTablePtr hash;
4531
4
    int i, l;
4532
4
    xmlChar * strval;
4533
4
    xmlNodePtr cur;
4534
4535
4
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
2
  return(nodes);
4537
4538
2
    ret = xmlXPathNodeSetCreate(NULL);
4539
2
    if (ret == NULL)
4540
0
        return(ret);
4541
2
    l = xmlXPathNodeSetGetLength(nodes);
4542
2
    hash = xmlHashCreate (l);
4543
26
    for (i = 0; i < l; i++) {
4544
24
  cur = xmlXPathNodeSetItem(nodes, i);
4545
24
  strval = xmlXPathCastNodeToString(cur);
4546
24
  if (xmlHashLookup(hash, strval) == NULL) {
4547
18
      xmlHashAddEntry(hash, strval, strval);
4548
            /* TODO: Propagate memory error. */
4549
18
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4550
0
          break;
4551
18
  } else {
4552
6
      xmlFree(strval);
4553
6
  }
4554
24
    }
4555
2
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4556
2
    return(ret);
4557
2
}
4558
4559
/**
4560
 * xmlXPathDistinct:
4561
 * @nodes:  a node-set
4562
 *
4563
 * Implements the EXSLT - Sets distinct() function:
4564
 *    node-set set:distinct (node-set)
4565
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4566
 * is called with the sorted node-set
4567
 *
4568
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4569
 *         it is empty
4570
 */
4571
xmlNodeSetPtr
4572
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4573
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4574
0
  return(nodes);
4575
4576
0
    xmlXPathNodeSetSort(nodes);
4577
0
    return(xmlXPathDistinctSorted(nodes));
4578
0
}
4579
4580
/**
4581
 * xmlXPathHasSameNodes:
4582
 * @nodes1:  a node-set
4583
 * @nodes2:  a node-set
4584
 *
4585
 * Implements the EXSLT - Sets has-same-nodes function:
4586
 *    boolean set:has-same-node(node-set, node-set)
4587
 *
4588
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4589
 *         otherwise
4590
 */
4591
int
4592
2
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4593
2
    int i, l;
4594
2
    xmlNodePtr cur;
4595
4596
2
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4597
2
  xmlXPathNodeSetIsEmpty(nodes2))
4598
0
  return(0);
4599
4600
2
    l = xmlXPathNodeSetGetLength(nodes1);
4601
10
    for (i = 0; i < l; i++) {
4602
10
  cur = xmlXPathNodeSetItem(nodes1, i);
4603
10
  if (xmlXPathNodeSetContains(nodes2, cur))
4604
2
      return(1);
4605
10
    }
4606
0
    return(0);
4607
2
}
4608
4609
/**
4610
 * xmlXPathNodeLeadingSorted:
4611
 * @nodes: a node-set, sorted by document order
4612
 * @node: a node
4613
 *
4614
 * Implements the EXSLT - Sets leading() function:
4615
 *    node-set set:leading (node-set, node-set)
4616
 *
4617
 * Returns the nodes in @nodes that precede @node in document order,
4618
 *         @nodes if @node is NULL or an empty node-set if @nodes
4619
 *         doesn't contain @node
4620
 */
4621
xmlNodeSetPtr
4622
8
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4623
8
    int i, l;
4624
8
    xmlNodePtr cur;
4625
8
    xmlNodeSetPtr ret;
4626
4627
8
    if (node == NULL)
4628
0
  return(nodes);
4629
4630
8
    ret = xmlXPathNodeSetCreate(NULL);
4631
8
    if (ret == NULL)
4632
0
        return(ret);
4633
8
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4634
8
  (!xmlXPathNodeSetContains(nodes, node)))
4635
2
  return(ret);
4636
4637
6
    l = xmlXPathNodeSetGetLength(nodes);
4638
27
    for (i = 0; i < l; i++) {
4639
27
  cur = xmlXPathNodeSetItem(nodes, i);
4640
27
  if (cur == node)
4641
6
      break;
4642
        /* TODO: Propagate memory error. */
4643
21
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4644
0
      break;
4645
21
    }
4646
6
    return(ret);
4647
8
}
4648
4649
/**
4650
 * xmlXPathNodeLeading:
4651
 * @nodes:  a node-set
4652
 * @node:  a node
4653
 *
4654
 * Implements the EXSLT - Sets leading() function:
4655
 *    node-set set:leading (node-set, node-set)
4656
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4657
 * is called.
4658
 *
4659
 * Returns the nodes in @nodes that precede @node in document order,
4660
 *         @nodes if @node is NULL or an empty node-set if @nodes
4661
 *         doesn't contain @node
4662
 */
4663
xmlNodeSetPtr
4664
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4665
0
    xmlXPathNodeSetSort(nodes);
4666
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4667
0
}
4668
4669
/**
4670
 * xmlXPathLeadingSorted:
4671
 * @nodes1:  a node-set, sorted by document order
4672
 * @nodes2:  a node-set, sorted by document order
4673
 *
4674
 * Implements the EXSLT - Sets leading() function:
4675
 *    node-set set:leading (node-set, node-set)
4676
 *
4677
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4678
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4679
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4680
 */
4681
xmlNodeSetPtr
4682
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4684
0
  return(nodes1);
4685
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4686
0
             xmlXPathNodeSetItem(nodes2, 1)));
4687
0
}
4688
4689
/**
4690
 * xmlXPathLeading:
4691
 * @nodes1:  a node-set
4692
 * @nodes2:  a node-set
4693
 *
4694
 * Implements the EXSLT - Sets leading() function:
4695
 *    node-set set:leading (node-set, node-set)
4696
 * @nodes1 and @nodes2 are sorted by document order, then
4697
 * #exslSetsLeadingSorted is called.
4698
 *
4699
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4700
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4701
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4702
 */
4703
xmlNodeSetPtr
4704
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4705
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4706
0
  return(nodes1);
4707
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4708
0
  return(xmlXPathNodeSetCreate(NULL));
4709
0
    xmlXPathNodeSetSort(nodes1);
4710
0
    xmlXPathNodeSetSort(nodes2);
4711
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4712
0
             xmlXPathNodeSetItem(nodes2, 1)));
4713
0
}
4714
4715
/**
4716
 * xmlXPathNodeTrailingSorted:
4717
 * @nodes: a node-set, sorted by document order
4718
 * @node: a node
4719
 *
4720
 * Implements the EXSLT - Sets trailing() function:
4721
 *    node-set set:trailing (node-set, node-set)
4722
 *
4723
 * Returns the nodes in @nodes that follow @node in document order,
4724
 *         @nodes if @node is NULL or an empty node-set if @nodes
4725
 *         doesn't contain @node
4726
 */
4727
xmlNodeSetPtr
4728
8
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4729
8
    int i, l;
4730
8
    xmlNodePtr cur;
4731
8
    xmlNodeSetPtr ret;
4732
4733
8
    if (node == NULL)
4734
0
  return(nodes);
4735
4736
8
    ret = xmlXPathNodeSetCreate(NULL);
4737
8
    if (ret == NULL)
4738
0
        return(ret);
4739
8
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4740
8
  (!xmlXPathNodeSetContains(nodes, node)))
4741
6
  return(ret);
4742
4743
2
    l = xmlXPathNodeSetGetLength(nodes);
4744
12
    for (i = l - 1; i >= 0; i--) {
4745
12
  cur = xmlXPathNodeSetItem(nodes, i);
4746
12
  if (cur == node)
4747
2
      break;
4748
        /* TODO: Propagate memory error. */
4749
10
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4750
0
      break;
4751
10
    }
4752
2
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4753
2
    return(ret);
4754
8
}
4755
4756
/**
4757
 * xmlXPathNodeTrailing:
4758
 * @nodes:  a node-set
4759
 * @node:  a node
4760
 *
4761
 * Implements the EXSLT - Sets trailing() function:
4762
 *    node-set set:trailing (node-set, node-set)
4763
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4764
 * is called.
4765
 *
4766
 * Returns the nodes in @nodes that follow @node in document order,
4767
 *         @nodes if @node is NULL or an empty node-set if @nodes
4768
 *         doesn't contain @node
4769
 */
4770
xmlNodeSetPtr
4771
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4772
0
    xmlXPathNodeSetSort(nodes);
4773
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4774
0
}
4775
4776
/**
4777
 * xmlXPathTrailingSorted:
4778
 * @nodes1:  a node-set, sorted by document order
4779
 * @nodes2:  a node-set, sorted by document order
4780
 *
4781
 * Implements the EXSLT - Sets trailing() function:
4782
 *    node-set set:trailing (node-set, node-set)
4783
 *
4784
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4785
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4786
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4787
 */
4788
xmlNodeSetPtr
4789
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4790
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4791
0
  return(nodes1);
4792
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4793
0
              xmlXPathNodeSetItem(nodes2, 0)));
4794
0
}
4795
4796
/**
4797
 * xmlXPathTrailing:
4798
 * @nodes1:  a node-set
4799
 * @nodes2:  a node-set
4800
 *
4801
 * Implements the EXSLT - Sets trailing() function:
4802
 *    node-set set:trailing (node-set, node-set)
4803
 * @nodes1 and @nodes2 are sorted by document order, then
4804
 * #xmlXPathTrailingSorted is called.
4805
 *
4806
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4807
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4808
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4809
 */
4810
xmlNodeSetPtr
4811
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4812
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4813
0
  return(nodes1);
4814
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4815
0
  return(xmlXPathNodeSetCreate(NULL));
4816
0
    xmlXPathNodeSetSort(nodes1);
4817
0
    xmlXPathNodeSetSort(nodes2);
4818
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4819
0
              xmlXPathNodeSetItem(nodes2, 0)));
4820
0
}
4821
4822
/************************************************************************
4823
 *                  *
4824
 *    Routines to handle extra functions      *
4825
 *                  *
4826
 ************************************************************************/
4827
4828
/**
4829
 * xmlXPathRegisterFunc:
4830
 * @ctxt:  the XPath context
4831
 * @name:  the function name
4832
 * @f:  the function implementation or NULL
4833
 *
4834
 * Register a new function. If @f is NULL it unregisters the function
4835
 *
4836
 * Returns 0 in case of success, -1 in case of error
4837
 */
4838
int
4839
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4840
9.37M
         xmlXPathFunction f) {
4841
9.37M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4842
9.37M
}
4843
4844
/**
4845
 * xmlXPathRegisterFuncNS:
4846
 * @ctxt:  the XPath context
4847
 * @name:  the function name
4848
 * @ns_uri:  the function namespace URI
4849
 * @f:  the function implementation or NULL
4850
 *
4851
 * Register a new function. If @f is NULL it unregisters the function
4852
 *
4853
 * Returns 0 in case of success, -1 in case of error
4854
 */
4855
int
4856
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4857
9.72M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4858
9.72M
    if (ctxt == NULL)
4859
0
  return(-1);
4860
9.72M
    if (name == NULL)
4861
0
  return(-1);
4862
4863
9.72M
    if (ctxt->funcHash == NULL)
4864
0
  ctxt->funcHash = xmlHashCreate(0);
4865
9.72M
    if (ctxt->funcHash == NULL)
4866
0
  return(-1);
4867
9.72M
    if (f == NULL)
4868
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4869
9.72M
XML_IGNORE_FPTR_CAST_WARNINGS
4870
9.72M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4871
9.72M
XML_POP_WARNINGS
4872
9.72M
}
4873
4874
/**
4875
 * xmlXPathRegisterFuncLookup:
4876
 * @ctxt:  the XPath context
4877
 * @f:  the lookup function
4878
 * @funcCtxt:  the lookup data
4879
 *
4880
 * Registers an external mechanism to do function lookup.
4881
 */
4882
void
4883
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4884
          xmlXPathFuncLookupFunc f,
4885
88
          void *funcCtxt) {
4886
88
    if (ctxt == NULL)
4887
0
  return;
4888
88
    ctxt->funcLookupFunc = f;
4889
88
    ctxt->funcLookupData = funcCtxt;
4890
88
}
4891
4892
/**
4893
 * xmlXPathFunctionLookup:
4894
 * @ctxt:  the XPath context
4895
 * @name:  the function name
4896
 *
4897
 * Search in the Function array of the context for the given
4898
 * function.
4899
 *
4900
 * Returns the xmlXPathFunction or NULL if not found
4901
 */
4902
xmlXPathFunction
4903
6.31k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4904
6.31k
    if (ctxt == NULL)
4905
0
  return (NULL);
4906
4907
6.31k
    if (ctxt->funcLookupFunc != NULL) {
4908
6.31k
  xmlXPathFunction ret;
4909
6.31k
  xmlXPathFuncLookupFunc f;
4910
4911
6.31k
  f = ctxt->funcLookupFunc;
4912
6.31k
  ret = f(ctxt->funcLookupData, name, NULL);
4913
6.31k
  if (ret != NULL)
4914
0
      return(ret);
4915
6.31k
    }
4916
6.31k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4917
6.31k
}
4918
4919
/**
4920
 * xmlXPathFunctionLookupNS:
4921
 * @ctxt:  the XPath context
4922
 * @name:  the function name
4923
 * @ns_uri:  the function namespace URI
4924
 *
4925
 * Search in the Function array of the context for the given
4926
 * function.
4927
 *
4928
 * Returns the xmlXPathFunction or NULL if not found
4929
 */
4930
xmlXPathFunction
4931
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4932
10.4k
       const xmlChar *ns_uri) {
4933
10.4k
    xmlXPathFunction ret;
4934
4935
10.4k
    if (ctxt == NULL)
4936
0
  return(NULL);
4937
10.4k
    if (name == NULL)
4938
0
  return(NULL);
4939
4940
10.4k
    if (ctxt->funcLookupFunc != NULL) {
4941
10.4k
  xmlXPathFuncLookupFunc f;
4942
4943
10.4k
  f = ctxt->funcLookupFunc;
4944
10.4k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4945
10.4k
  if (ret != NULL)
4946
3.99k
      return(ret);
4947
10.4k
    }
4948
4949
6.45k
    if (ctxt->funcHash == NULL)
4950
0
  return(NULL);
4951
4952
6.45k
XML_IGNORE_FPTR_CAST_WARNINGS
4953
6.45k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4954
6.45k
XML_POP_WARNINGS
4955
6.45k
    return(ret);
4956
6.45k
}
4957
4958
/**
4959
 * xmlXPathRegisteredFuncsCleanup:
4960
 * @ctxt:  the XPath context
4961
 *
4962
 * Cleanup the XPath context data associated to registered functions
4963
 */
4964
void
4965
347k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4966
347k
    if (ctxt == NULL)
4967
0
  return;
4968
4969
347k
    xmlHashFree(ctxt->funcHash, NULL);
4970
347k
    ctxt->funcHash = NULL;
4971
347k
}
4972
4973
/************************************************************************
4974
 *                  *
4975
 *      Routines to handle Variables      *
4976
 *                  *
4977
 ************************************************************************/
4978
4979
/**
4980
 * xmlXPathRegisterVariable:
4981
 * @ctxt:  the XPath context
4982
 * @name:  the variable name
4983
 * @value:  the variable value or NULL
4984
 *
4985
 * Register a new variable value. If @value is NULL it unregisters
4986
 * the variable
4987
 *
4988
 * Returns 0 in case of success, -1 in case of error
4989
 */
4990
int
4991
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4992
352
       xmlXPathObjectPtr value) {
4993
352
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4994
352
}
4995
4996
/**
4997
 * xmlXPathRegisterVariableNS:
4998
 * @ctxt:  the XPath context
4999
 * @name:  the variable name
5000
 * @ns_uri:  the variable namespace URI
5001
 * @value:  the variable value or NULL
5002
 *
5003
 * Register a new variable value. If @value is NULL it unregisters
5004
 * the variable
5005
 *
5006
 * Returns 0 in case of success, -1 in case of error
5007
 */
5008
int
5009
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5010
         const xmlChar *ns_uri,
5011
352
         xmlXPathObjectPtr value) {
5012
352
    if (ctxt == NULL)
5013
0
  return(-1);
5014
352
    if (name == NULL)
5015
0
  return(-1);
5016
5017
352
    if (ctxt->varHash == NULL)
5018
88
  ctxt->varHash = xmlHashCreate(0);
5019
352
    if (ctxt->varHash == NULL)
5020
0
  return(-1);
5021
352
    if (value == NULL)
5022
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5023
0
                             xmlXPathFreeObjectEntry));
5024
352
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5025
352
             (void *) value, xmlXPathFreeObjectEntry));
5026
352
}
5027
5028
/**
5029
 * xmlXPathRegisterVariableLookup:
5030
 * @ctxt:  the XPath context
5031
 * @f:  the lookup function
5032
 * @data:  the lookup data
5033
 *
5034
 * register an external mechanism to do variable lookup
5035
 */
5036
void
5037
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5038
88
   xmlXPathVariableLookupFunc f, void *data) {
5039
88
    if (ctxt == NULL)
5040
0
  return;
5041
88
    ctxt->varLookupFunc = f;
5042
88
    ctxt->varLookupData = data;
5043
88
}
5044
5045
/**
5046
 * xmlXPathVariableLookup:
5047
 * @ctxt:  the XPath context
5048
 * @name:  the variable name
5049
 *
5050
 * Search in the Variable array of the context for the given
5051
 * variable value.
5052
 *
5053
 * Returns a copy of the value or NULL if not found
5054
 */
5055
xmlXPathObjectPtr
5056
183
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5057
183
    if (ctxt == NULL)
5058
0
  return(NULL);
5059
5060
183
    if (ctxt->varLookupFunc != NULL) {
5061
183
  xmlXPathObjectPtr ret;
5062
5063
183
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5064
183
          (ctxt->varLookupData, name, NULL);
5065
183
  return(ret);
5066
183
    }
5067
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5068
183
}
5069
5070
/**
5071
 * xmlXPathVariableLookupNS:
5072
 * @ctxt:  the XPath context
5073
 * @name:  the variable name
5074
 * @ns_uri:  the variable namespace URI
5075
 *
5076
 * Search in the Variable array of the context for the given
5077
 * variable value.
5078
 *
5079
 * Returns the a copy of the value or NULL if not found
5080
 */
5081
xmlXPathObjectPtr
5082
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5083
5
       const xmlChar *ns_uri) {
5084
5
    if (ctxt == NULL)
5085
0
  return(NULL);
5086
5087
5
    if (ctxt->varLookupFunc != NULL) {
5088
5
  xmlXPathObjectPtr ret;
5089
5090
5
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5091
5
          (ctxt->varLookupData, name, ns_uri);
5092
5
  if (ret != NULL) return(ret);
5093
5
    }
5094
5095
5
    if (ctxt->varHash == NULL)
5096
0
  return(NULL);
5097
5
    if (name == NULL)
5098
0
  return(NULL);
5099
5100
5
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5101
5
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5102
5
}
5103
5104
/**
5105
 * xmlXPathRegisteredVariablesCleanup:
5106
 * @ctxt:  the XPath context
5107
 *
5108
 * Cleanup the XPath context data associated to registered variables
5109
 */
5110
void
5111
347k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5112
347k
    if (ctxt == NULL)
5113
0
  return;
5114
5115
347k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5116
347k
    ctxt->varHash = NULL;
5117
347k
}
5118
5119
/**
5120
 * xmlXPathRegisterNs:
5121
 * @ctxt:  the XPath context
5122
 * @prefix:  the namespace prefix cannot be NULL or empty string
5123
 * @ns_uri:  the namespace name
5124
 *
5125
 * Register a new namespace. If @ns_uri is NULL it unregisters
5126
 * the namespace
5127
 *
5128
 * Returns 0 in case of success, -1 in case of error
5129
 */
5130
int
5131
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5132
968
         const xmlChar *ns_uri) {
5133
968
    if (ctxt == NULL)
5134
0
  return(-1);
5135
968
    if (prefix == NULL)
5136
0
  return(-1);
5137
968
    if (prefix[0] == 0)
5138
0
  return(-1);
5139
5140
968
    if (ctxt->nsHash == NULL)
5141
88
  ctxt->nsHash = xmlHashCreate(10);
5142
968
    if (ctxt->nsHash == NULL)
5143
0
  return(-1);
5144
968
    if (ns_uri == NULL)
5145
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5146
0
                            xmlHashDefaultDeallocator));
5147
968
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5148
968
            xmlHashDefaultDeallocator));
5149
968
}
5150
5151
/**
5152
 * xmlXPathNsLookup:
5153
 * @ctxt:  the XPath context
5154
 * @prefix:  the namespace prefix value
5155
 *
5156
 * Search in the namespace declaration array of the context for the given
5157
 * namespace name associated to the given prefix
5158
 *
5159
 * Returns the value or NULL if not found
5160
 */
5161
const xmlChar *
5162
25.8k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5163
25.8k
    if (ctxt == NULL)
5164
0
  return(NULL);
5165
25.8k
    if (prefix == NULL)
5166
0
  return(NULL);
5167
5168
25.8k
#ifdef XML_XML_NAMESPACE
5169
25.8k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5170
1
  return(XML_XML_NAMESPACE);
5171
25.8k
#endif
5172
5173
25.8k
    if (ctxt->namespaces != NULL) {
5174
0
  int i;
5175
5176
0
  for (i = 0;i < ctxt->nsNr;i++) {
5177
0
      if ((ctxt->namespaces[i] != NULL) &&
5178
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5179
0
    return(ctxt->namespaces[i]->href);
5180
0
  }
5181
0
    }
5182
5183
25.8k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5184
25.8k
}
5185
5186
/**
5187
 * xmlXPathRegisteredNsCleanup:
5188
 * @ctxt:  the XPath context
5189
 *
5190
 * Cleanup the XPath context data associated to registered variables
5191
 */
5192
void
5193
347k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5194
347k
    if (ctxt == NULL)
5195
0
  return;
5196
5197
347k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5198
347k
    ctxt->nsHash = NULL;
5199
347k
}
5200
5201
/************************************************************************
5202
 *                  *
5203
 *      Routines to handle Values     *
5204
 *                  *
5205
 ************************************************************************/
5206
5207
/* Allocations are terrible, one needs to optimize all this !!! */
5208
5209
/**
5210
 * xmlXPathNewFloat:
5211
 * @val:  the double value
5212
 *
5213
 * Create a new xmlXPathObjectPtr of type double and of value @val
5214
 *
5215
 * Returns the newly created object.
5216
 */
5217
xmlXPathObjectPtr
5218
28.1k
xmlXPathNewFloat(double val) {
5219
28.1k
    xmlXPathObjectPtr ret;
5220
5221
28.1k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5222
28.1k
    if (ret == NULL) {
5223
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5224
0
  return(NULL);
5225
0
    }
5226
28.1k
    memset(ret, 0 , sizeof(xmlXPathObject));
5227
28.1k
    ret->type = XPATH_NUMBER;
5228
28.1k
    ret->floatval = val;
5229
#ifdef XP_DEBUG_OBJ_USAGE
5230
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5231
#endif
5232
28.1k
    return(ret);
5233
28.1k
}
5234
5235
/**
5236
 * xmlXPathNewBoolean:
5237
 * @val:  the boolean value
5238
 *
5239
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5240
 *
5241
 * Returns the newly created object.
5242
 */
5243
xmlXPathObjectPtr
5244
3.72k
xmlXPathNewBoolean(int val) {
5245
3.72k
    xmlXPathObjectPtr ret;
5246
5247
3.72k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248
3.72k
    if (ret == NULL) {
5249
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5250
0
  return(NULL);
5251
0
    }
5252
3.72k
    memset(ret, 0 , sizeof(xmlXPathObject));
5253
3.72k
    ret->type = XPATH_BOOLEAN;
5254
3.72k
    ret->boolval = (val != 0);
5255
#ifdef XP_DEBUG_OBJ_USAGE
5256
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5257
#endif
5258
3.72k
    return(ret);
5259
3.72k
}
5260
5261
/**
5262
 * xmlXPathNewString:
5263
 * @val:  the xmlChar * value
5264
 *
5265
 * Create a new xmlXPathObjectPtr of type string and of value @val
5266
 *
5267
 * Returns the newly created object.
5268
 */
5269
xmlXPathObjectPtr
5270
32.4k
xmlXPathNewString(const xmlChar *val) {
5271
32.4k
    xmlXPathObjectPtr ret;
5272
5273
32.4k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5274
32.4k
    if (ret == NULL) {
5275
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5276
0
  return(NULL);
5277
0
    }
5278
32.4k
    memset(ret, 0 , sizeof(xmlXPathObject));
5279
32.4k
    ret->type = XPATH_STRING;
5280
32.4k
    if (val != NULL)
5281
32.4k
  ret->stringval = xmlStrdup(val);
5282
2
    else
5283
2
  ret->stringval = xmlStrdup((const xmlChar *)"");
5284
#ifdef XP_DEBUG_OBJ_USAGE
5285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5286
#endif
5287
32.4k
    return(ret);
5288
32.4k
}
5289
5290
/**
5291
 * xmlXPathWrapString:
5292
 * @val:  the xmlChar * value
5293
 *
5294
 * Wraps the @val string into an XPath object.
5295
 *
5296
 * Returns the newly created object.
5297
 */
5298
xmlXPathObjectPtr
5299
55.4k
xmlXPathWrapString (xmlChar *val) {
5300
55.4k
    xmlXPathObjectPtr ret;
5301
5302
55.4k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5303
55.4k
    if (ret == NULL) {
5304
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5305
0
  return(NULL);
5306
0
    }
5307
55.4k
    memset(ret, 0 , sizeof(xmlXPathObject));
5308
55.4k
    ret->type = XPATH_STRING;
5309
55.4k
    ret->stringval = val;
5310
#ifdef XP_DEBUG_OBJ_USAGE
5311
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5312
#endif
5313
55.4k
    return(ret);
5314
55.4k
}
5315
5316
/**
5317
 * xmlXPathNewCString:
5318
 * @val:  the char * value
5319
 *
5320
 * Create a new xmlXPathObjectPtr of type string and of value @val
5321
 *
5322
 * Returns the newly created object.
5323
 */
5324
xmlXPathObjectPtr
5325
243
xmlXPathNewCString(const char *val) {
5326
243
    xmlXPathObjectPtr ret;
5327
5328
243
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5329
243
    if (ret == NULL) {
5330
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5331
0
  return(NULL);
5332
0
    }
5333
243
    memset(ret, 0 , sizeof(xmlXPathObject));
5334
243
    ret->type = XPATH_STRING;
5335
243
    ret->stringval = xmlStrdup(BAD_CAST val);
5336
#ifdef XP_DEBUG_OBJ_USAGE
5337
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5338
#endif
5339
243
    return(ret);
5340
243
}
5341
5342
/**
5343
 * xmlXPathWrapCString:
5344
 * @val:  the char * value
5345
 *
5346
 * Wraps a string into an XPath object.
5347
 *
5348
 * Returns the newly created object.
5349
 */
5350
xmlXPathObjectPtr
5351
0
xmlXPathWrapCString (char * val) {
5352
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5353
0
}
5354
5355
/**
5356
 * xmlXPathWrapExternal:
5357
 * @val:  the user data
5358
 *
5359
 * Wraps the @val data into an XPath object.
5360
 *
5361
 * Returns the newly created object.
5362
 */
5363
xmlXPathObjectPtr
5364
25
xmlXPathWrapExternal (void *val) {
5365
25
    xmlXPathObjectPtr ret;
5366
5367
25
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5368
25
    if (ret == NULL) {
5369
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5370
0
  return(NULL);
5371
0
    }
5372
25
    memset(ret, 0 , sizeof(xmlXPathObject));
5373
25
    ret->type = XPATH_USERS;
5374
25
    ret->user = val;
5375
#ifdef XP_DEBUG_OBJ_USAGE
5376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5377
#endif
5378
25
    return(ret);
5379
25
}
5380
5381
/**
5382
 * xmlXPathObjectCopy:
5383
 * @val:  the original object
5384
 *
5385
 * allocate a new copy of a given object
5386
 *
5387
 * Returns the newly created object.
5388
 */
5389
xmlXPathObjectPtr
5390
75.3k
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5391
75.3k
    xmlXPathObjectPtr ret;
5392
5393
75.3k
    if (val == NULL)
5394
0
  return(NULL);
5395
5396
75.3k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5397
75.3k
    if (ret == NULL) {
5398
0
        xmlXPathErrMemory(NULL, "copying object\n");
5399
0
  return(NULL);
5400
0
    }
5401
75.3k
    memcpy(ret, val , sizeof(xmlXPathObject));
5402
#ifdef XP_DEBUG_OBJ_USAGE
5403
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5404
#endif
5405
75.3k
    switch (val->type) {
5406
0
  case XPATH_BOOLEAN:
5407
0
  case XPATH_NUMBER:
5408
#ifdef LIBXML_XPTR_LOCS_ENABLED
5409
  case XPATH_POINT:
5410
  case XPATH_RANGE:
5411
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5412
0
      break;
5413
0
  case XPATH_STRING:
5414
0
      ret->stringval = xmlStrdup(val->stringval);
5415
0
      break;
5416
0
  case XPATH_XSLT_TREE:
5417
#if 0
5418
/*
5419
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5420
  this previous handling is no longer correct, and can cause some serious
5421
  problems (ref. bug 145547)
5422
*/
5423
      if ((val->nodesetval != NULL) &&
5424
    (val->nodesetval->nodeTab != NULL)) {
5425
    xmlNodePtr cur, tmp;
5426
    xmlDocPtr top;
5427
5428
    ret->boolval = 1;
5429
    top =  xmlNewDoc(NULL);
5430
    top->name = (char *)
5431
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5432
    ret->user = top;
5433
    if (top != NULL) {
5434
        top->doc = top;
5435
        cur = val->nodesetval->nodeTab[0]->children;
5436
        while (cur != NULL) {
5437
      tmp = xmlDocCopyNode(cur, top, 1);
5438
      xmlAddChild((xmlNodePtr) top, tmp);
5439
      cur = cur->next;
5440
        }
5441
    }
5442
5443
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5444
      } else
5445
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5446
      /* Deallocate the copied tree value */
5447
      break;
5448
#endif
5449
75.3k
  case XPATH_NODESET:
5450
            /* TODO: Check memory error. */
5451
75.3k
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452
      /* Do not deallocate the copied tree value */
5453
75.3k
      ret->boolval = 0;
5454
75.3k
      break;
5455
#ifdef LIBXML_XPTR_LOCS_ENABLED
5456
  case XPATH_LOCATIONSET:
5457
  {
5458
      xmlLocationSetPtr loc = val->user;
5459
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460
      break;
5461
  }
5462
#endif
5463
0
        case XPATH_USERS:
5464
0
      ret->user = val->user;
5465
0
      break;
5466
0
        case XPATH_UNDEFINED:
5467
0
      xmlGenericError(xmlGenericErrorContext,
5468
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5469
0
        val->type);
5470
0
      break;
5471
75.3k
    }
5472
75.3k
    return(ret);
5473
75.3k
}
5474
5475
/**
5476
 * xmlXPathFreeObject:
5477
 * @obj:  the object to free
5478
 *
5479
 * Free up an xmlXPathObjectPtr object.
5480
 */
5481
void
5482
3.15M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483
3.15M
    if (obj == NULL) return;
5484
2.80M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485
1.85M
  if (obj->boolval) {
5486
#if 0
5487
      if (obj->user != NULL) {
5488
                xmlXPathFreeNodeSet(obj->nodesetval);
5489
    xmlFreeNodeList((xmlNodePtr) obj->user);
5490
      } else
5491
#endif
5492
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5493
0
      if (obj->nodesetval != NULL)
5494
0
    xmlXPathFreeValueTree(obj->nodesetval);
5495
1.85M
  } else {
5496
1.85M
      if (obj->nodesetval != NULL)
5497
1.85M
    xmlXPathFreeNodeSet(obj->nodesetval);
5498
1.85M
  }
5499
#ifdef LIBXML_XPTR_LOCS_ENABLED
5500
    } else if (obj->type == XPATH_LOCATIONSET) {
5501
  if (obj->user != NULL)
5502
      xmlXPtrFreeLocationSet(obj->user);
5503
#endif
5504
1.85M
    } else if (obj->type == XPATH_STRING) {
5505
919k
  if (obj->stringval != NULL)
5506
919k
      xmlFree(obj->stringval);
5507
919k
    }
5508
#ifdef XP_DEBUG_OBJ_USAGE
5509
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510
#endif
5511
2.80M
    xmlFree(obj);
5512
2.80M
}
5513
5514
static void
5515
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5516
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5517
0
}
5518
5519
/**
5520
 * xmlXPathReleaseObject:
5521
 * @obj:  the xmlXPathObjectPtr to free or to cache
5522
 *
5523
 * Depending on the state of the cache this frees the given
5524
 * XPath object or stores it in the cache.
5525
 */
5526
static void
5527
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5528
3.30M
{
5529
3.30M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5530
18.7k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5531
3.30M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5532
5533
4.63M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5534
5535
3.30M
    if (obj == NULL)
5536
0
  return;
5537
3.30M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5538
321
   xmlXPathFreeObject(obj);
5539
3.30M
    } else {
5540
3.30M
  xmlXPathContextCachePtr cache =
5541
3.30M
      (xmlXPathContextCachePtr) ctxt->cache;
5542
5543
3.30M
  switch (obj->type) {
5544
2.12M
      case XPATH_NODESET:
5545
2.12M
      case XPATH_XSLT_TREE:
5546
2.12M
    if (obj->nodesetval != NULL) {
5547
2.03M
        if (obj->boolval) {
5548
      /*
5549
      * It looks like the @boolval is used for
5550
      * evaluation if this an XSLT Result Tree Fragment.
5551
      * TODO: Check if this assumption is correct.
5552
      */
5553
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5554
0
      xmlXPathFreeValueTree(obj->nodesetval);
5555
0
      obj->nodesetval = NULL;
5556
2.03M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5557
2.03M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5558
2.03M
          cache->maxNodeset)))
5559
700k
        {
5560
700k
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5561
700k
      goto obj_cached;
5562
1.33M
        } else {
5563
1.33M
      xmlXPathFreeNodeSet(obj->nodesetval);
5564
1.33M
      obj->nodesetval = NULL;
5565
1.33M
        }
5566
2.03M
    }
5567
1.42M
    break;
5568
1.42M
      case XPATH_STRING:
5569
178k
    if (obj->stringval != NULL)
5570
178k
        xmlFree(obj->stringval);
5571
5572
178k
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5573
177k
        XP_CACHE_ADD(cache->stringObjs, obj);
5574
177k
        goto obj_cached;
5575
177k
    }
5576
1.51k
    break;
5577
355k
      case XPATH_BOOLEAN:
5578
355k
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5579
355k
        XP_CACHE_ADD(cache->booleanObjs, obj);
5580
355k
        goto obj_cached;
5581
355k
    }
5582
0
    break;
5583
637k
      case XPATH_NUMBER:
5584
637k
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5585
637k
        XP_CACHE_ADD(cache->numberObjs, obj);
5586
637k
        goto obj_cached;
5587
637k
    }
5588
0
    break;
5589
#ifdef LIBXML_XPTR_LOCS_ENABLED
5590
      case XPATH_LOCATIONSET:
5591
    if (obj->user != NULL) {
5592
        xmlXPtrFreeLocationSet(obj->user);
5593
    }
5594
    goto free_obj;
5595
#endif
5596
25
      default:
5597
25
    goto free_obj;
5598
3.30M
  }
5599
5600
  /*
5601
  * Fallback to adding to the misc-objects slot.
5602
  */
5603
1.42M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5604
1.42M
      XP_CACHE_ADD(cache->miscObjs, obj);
5605
1.42M
  } else
5606
347
      goto free_obj;
5607
5608
3.30M
obj_cached:
5609
5610
#ifdef XP_DEBUG_OBJ_USAGE
5611
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5612
#endif
5613
5614
3.30M
  if (obj->nodesetval != NULL) {
5615
700k
      xmlNodeSetPtr tmpset = obj->nodesetval;
5616
5617
      /*
5618
      * TODO: Due to those nasty ns-nodes, we need to traverse
5619
      *  the list and free the ns-nodes.
5620
      * URGENT TODO: Check if it's actually slowing things down.
5621
      *  Maybe we shouldn't try to preserve the list.
5622
      */
5623
700k
      if (tmpset->nodeNr > 1) {
5624
40.5k
    int i;
5625
40.5k
    xmlNodePtr node;
5626
5627
634k
    for (i = 0; i < tmpset->nodeNr; i++) {
5628
593k
        node = tmpset->nodeTab[i];
5629
593k
        if ((node != NULL) &&
5630
593k
      (node->type == XML_NAMESPACE_DECL))
5631
12.5k
        {
5632
12.5k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5633
12.5k
        }
5634
593k
    }
5635
660k
      } else if (tmpset->nodeNr == 1) {
5636
600k
    if ((tmpset->nodeTab[0] != NULL) &&
5637
600k
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5638
123k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5639
600k
      }
5640
700k
      tmpset->nodeNr = 0;
5641
700k
      memset(obj, 0, sizeof(xmlXPathObject));
5642
700k
      obj->nodesetval = tmpset;
5643
700k
  } else
5644
2.60M
      memset(obj, 0, sizeof(xmlXPathObject));
5645
5646
3.30M
  return;
5647
5648
372
free_obj:
5649
  /*
5650
  * Cache is full; free the object.
5651
  */
5652
372
  if (obj->nodesetval != NULL)
5653
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5654
#ifdef XP_DEBUG_OBJ_USAGE
5655
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5656
#endif
5657
372
  xmlFree(obj);
5658
372
    }
5659
693
    return;
5660
3.30M
}
5661
5662
5663
/************************************************************************
5664
 *                  *
5665
 *      Type Casting Routines       *
5666
 *                  *
5667
 ************************************************************************/
5668
5669
/**
5670
 * xmlXPathCastBooleanToString:
5671
 * @val:  a boolean
5672
 *
5673
 * Converts a boolean to its string value.
5674
 *
5675
 * Returns a newly allocated string.
5676
 */
5677
xmlChar *
5678
230
xmlXPathCastBooleanToString (int val) {
5679
230
    xmlChar *ret;
5680
230
    if (val)
5681
54
  ret = xmlStrdup((const xmlChar *) "true");
5682
176
    else
5683
176
  ret = xmlStrdup((const xmlChar *) "false");
5684
230
    return(ret);
5685
230
}
5686
5687
/**
5688
 * xmlXPathCastNumberToString:
5689
 * @val:  a number
5690
 *
5691
 * Converts a number to its string value.
5692
 *
5693
 * Returns a newly allocated string.
5694
 */
5695
xmlChar *
5696
412
xmlXPathCastNumberToString (double val) {
5697
412
    xmlChar *ret;
5698
412
    switch (xmlXPathIsInf(val)) {
5699
2
    case 1:
5700
2
  ret = xmlStrdup((const xmlChar *) "Infinity");
5701
2
  break;
5702
2
    case -1:
5703
2
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5704
2
  break;
5705
408
    default:
5706
408
  if (xmlXPathIsNaN(val)) {
5707
172
      ret = xmlStrdup((const xmlChar *) "NaN");
5708
236
  } else if (val == 0) {
5709
            /* Omit sign for negative zero. */
5710
31
      ret = xmlStrdup((const xmlChar *) "0");
5711
205
  } else {
5712
      /* could be improved */
5713
205
      char buf[100];
5714
205
      xmlXPathFormatNumber(val, buf, 99);
5715
205
      buf[99] = 0;
5716
205
      ret = xmlStrdup((const xmlChar *) buf);
5717
205
  }
5718
412
    }
5719
412
    return(ret);
5720
412
}
5721
5722
/**
5723
 * xmlXPathCastNodeToString:
5724
 * @node:  a node
5725
 *
5726
 * Converts a node to its string value.
5727
 *
5728
 * Returns a newly allocated string.
5729
 */
5730
xmlChar *
5731
1.16M
xmlXPathCastNodeToString (xmlNodePtr node) {
5732
1.16M
xmlChar *ret;
5733
1.16M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5734
0
  ret = xmlStrdup((const xmlChar *) "");
5735
1.16M
    return(ret);
5736
1.16M
}
5737
5738
/**
5739
 * xmlXPathCastNodeSetToString:
5740
 * @ns:  a node-set
5741
 *
5742
 * Converts a node-set to its string value.
5743
 *
5744
 * Returns a newly allocated string.
5745
 */
5746
xmlChar *
5747
1.16M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5748
1.16M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5749
200k
  return(xmlStrdup((const xmlChar *) ""));
5750
5751
959k
    if (ns->nodeNr > 1)
5752
41.2k
  xmlXPathNodeSetSort(ns);
5753
959k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5754
1.16M
}
5755
5756
/**
5757
 * xmlXPathCastToString:
5758
 * @val:  an XPath object
5759
 *
5760
 * Converts an existing object to its string() equivalent
5761
 *
5762
 * Returns the allocated string value of the object, NULL in case of error.
5763
 *         It's up to the caller to free the string memory with xmlFree().
5764
 */
5765
xmlChar *
5766
6.42k
xmlXPathCastToString(xmlXPathObjectPtr val) {
5767
6.42k
    xmlChar *ret = NULL;
5768
5769
6.42k
    if (val == NULL)
5770
0
  return(xmlStrdup((const xmlChar *) ""));
5771
6.42k
    switch (val->type) {
5772
0
  case XPATH_UNDEFINED:
5773
#ifdef DEBUG_EXPR
5774
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5775
#endif
5776
0
      ret = xmlStrdup((const xmlChar *) "");
5777
0
      break;
5778
367
        case XPATH_NODESET:
5779
367
        case XPATH_XSLT_TREE:
5780
367
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5781
367
      break;
5782
5.81k
  case XPATH_STRING:
5783
5.81k
      return(xmlStrdup(val->stringval));
5784
132
        case XPATH_BOOLEAN:
5785
132
      ret = xmlXPathCastBooleanToString(val->boolval);
5786
132
      break;
5787
117
  case XPATH_NUMBER: {
5788
117
      ret = xmlXPathCastNumberToString(val->floatval);
5789
117
      break;
5790
367
  }
5791
0
  case XPATH_USERS:
5792
#ifdef LIBXML_XPTR_LOCS_ENABLED
5793
  case XPATH_POINT:
5794
  case XPATH_RANGE:
5795
  case XPATH_LOCATIONSET:
5796
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5797
0
      TODO
5798
0
      ret = xmlStrdup((const xmlChar *) "");
5799
0
      break;
5800
6.42k
    }
5801
616
    return(ret);
5802
6.42k
}
5803
5804
/**
5805
 * xmlXPathConvertString:
5806
 * @val:  an XPath object
5807
 *
5808
 * Converts an existing object to its string() equivalent
5809
 *
5810
 * Returns the new object, the old one is freed (or the operation
5811
 *         is done directly on @val)
5812
 */
5813
xmlXPathObjectPtr
5814
2
xmlXPathConvertString(xmlXPathObjectPtr val) {
5815
2
    xmlChar *res = NULL;
5816
5817
2
    if (val == NULL)
5818
0
  return(xmlXPathNewCString(""));
5819
5820
2
    switch (val->type) {
5821
0
    case XPATH_UNDEFINED:
5822
#ifdef DEBUG_EXPR
5823
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5824
#endif
5825
0
  break;
5826
0
    case XPATH_NODESET:
5827
0
    case XPATH_XSLT_TREE:
5828
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5829
0
  break;
5830
0
    case XPATH_STRING:
5831
0
  return(val);
5832
1
    case XPATH_BOOLEAN:
5833
1
  res = xmlXPathCastBooleanToString(val->boolval);
5834
1
  break;
5835
1
    case XPATH_NUMBER:
5836
1
  res = xmlXPathCastNumberToString(val->floatval);
5837
1
  break;
5838
0
    case XPATH_USERS:
5839
#ifdef LIBXML_XPTR_LOCS_ENABLED
5840
    case XPATH_POINT:
5841
    case XPATH_RANGE:
5842
    case XPATH_LOCATIONSET:
5843
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5844
0
  TODO;
5845
0
  break;
5846
2
    }
5847
2
    xmlXPathFreeObject(val);
5848
2
    if (res == NULL)
5849
0
  return(xmlXPathNewCString(""));
5850
2
    return(xmlXPathWrapString(res));
5851
2
}
5852
5853
/**
5854
 * xmlXPathCastBooleanToNumber:
5855
 * @val:  a boolean
5856
 *
5857
 * Converts a boolean to its number value
5858
 *
5859
 * Returns the number value
5860
 */
5861
double
5862
90.5k
xmlXPathCastBooleanToNumber(int val) {
5863
90.5k
    if (val)
5864
15.9k
  return(1.0);
5865
74.6k
    return(0.0);
5866
90.5k
}
5867
5868
/**
5869
 * xmlXPathCastStringToNumber:
5870
 * @val:  a string
5871
 *
5872
 * Converts a string to its number value
5873
 *
5874
 * Returns the number value
5875
 */
5876
double
5877
522k
xmlXPathCastStringToNumber(const xmlChar * val) {
5878
522k
    return(xmlXPathStringEvalNumber(val));
5879
522k
}
5880
5881
/**
5882
 * xmlXPathCastNodeToNumber:
5883
 * @node:  a node
5884
 *
5885
 * Converts a node to its number value
5886
 *
5887
 * Returns the number value
5888
 */
5889
double
5890
125k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5891
125k
    xmlChar *strval;
5892
125k
    double ret;
5893
5894
125k
    if (node == NULL)
5895
0
  return(xmlXPathNAN);
5896
125k
    strval = xmlXPathCastNodeToString(node);
5897
125k
    if (strval == NULL)
5898
0
  return(xmlXPathNAN);
5899
125k
    ret = xmlXPathCastStringToNumber(strval);
5900
125k
    xmlFree(strval);
5901
5902
125k
    return(ret);
5903
125k
}
5904
5905
/**
5906
 * xmlXPathCastNodeSetToNumber:
5907
 * @ns:  a node-set
5908
 *
5909
 * Converts a node-set to its number value
5910
 *
5911
 * Returns the number value
5912
 */
5913
double
5914
275k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5915
275k
    xmlChar *str;
5916
275k
    double ret;
5917
5918
275k
    if (ns == NULL)
5919
12.7k
  return(xmlXPathNAN);
5920
262k
    str = xmlXPathCastNodeSetToString(ns);
5921
262k
    ret = xmlXPathCastStringToNumber(str);
5922
262k
    xmlFree(str);
5923
262k
    return(ret);
5924
275k
}
5925
5926
/**
5927
 * xmlXPathCastToNumber:
5928
 * @val:  an XPath object
5929
 *
5930
 * Converts an XPath object to its number value
5931
 *
5932
 * Returns the number value
5933
 */
5934
double
5935
542k
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5936
542k
    double ret = 0.0;
5937
5938
542k
    if (val == NULL)
5939
0
  return(xmlXPathNAN);
5940
542k
    switch (val->type) {
5941
0
    case XPATH_UNDEFINED:
5942
#ifdef DEBUG_EXPR
5943
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5944
#endif
5945
0
  ret = xmlXPathNAN;
5946
0
  break;
5947
275k
    case XPATH_NODESET:
5948
275k
    case XPATH_XSLT_TREE:
5949
275k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5950
275k
  break;
5951
133k
    case XPATH_STRING:
5952
133k
  ret = xmlXPathCastStringToNumber(val->stringval);
5953
133k
  break;
5954
42.4k
    case XPATH_NUMBER:
5955
42.4k
  ret = val->floatval;
5956
42.4k
  break;
5957
90.5k
    case XPATH_BOOLEAN:
5958
90.5k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5959
90.5k
  break;
5960
18
    case XPATH_USERS:
5961
#ifdef LIBXML_XPTR_LOCS_ENABLED
5962
    case XPATH_POINT:
5963
    case XPATH_RANGE:
5964
    case XPATH_LOCATIONSET:
5965
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5966
18
  TODO;
5967
18
  ret = xmlXPathNAN;
5968
18
  break;
5969
542k
    }
5970
542k
    return(ret);
5971
542k
}
5972
5973
/**
5974
 * xmlXPathConvertNumber:
5975
 * @val:  an XPath object
5976
 *
5977
 * Converts an existing object to its number() equivalent
5978
 *
5979
 * Returns the new object, the old one is freed (or the operation
5980
 *         is done directly on @val)
5981
 */
5982
xmlXPathObjectPtr
5983
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5984
0
    xmlXPathObjectPtr ret;
5985
5986
0
    if (val == NULL)
5987
0
  return(xmlXPathNewFloat(0.0));
5988
0
    if (val->type == XPATH_NUMBER)
5989
0
  return(val);
5990
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5991
0
    xmlXPathFreeObject(val);
5992
0
    return(ret);
5993
0
}
5994
5995
/**
5996
 * xmlXPathCastNumberToBoolean:
5997
 * @val:  a number
5998
 *
5999
 * Converts a number to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
20.7k
xmlXPathCastNumberToBoolean (double val) {
6005
20.7k
     if (xmlXPathIsNaN(val) || (val == 0.0))
6006
10.9k
   return(0);
6007
9.74k
     return(1);
6008
20.7k
}
6009
6010
/**
6011
 * xmlXPathCastStringToBoolean:
6012
 * @val:  a string
6013
 *
6014
 * Converts a string to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
6.46k
xmlXPathCastStringToBoolean (const xmlChar *val) {
6020
6.46k
    if ((val == NULL) || (xmlStrlen(val) == 0))
6021
3
  return(0);
6022
6.45k
    return(1);
6023
6.46k
}
6024
6025
/**
6026
 * xmlXPathCastNodeSetToBoolean:
6027
 * @ns:  a node-set
6028
 *
6029
 * Converts a node-set to its boolean value
6030
 *
6031
 * Returns the boolean value
6032
 */
6033
int
6034
35.7k
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6035
35.7k
    if ((ns == NULL) || (ns->nodeNr == 0))
6036
28.1k
  return(0);
6037
7.66k
    return(1);
6038
35.7k
}
6039
6040
/**
6041
 * xmlXPathCastToBoolean:
6042
 * @val:  an XPath object
6043
 *
6044
 * Converts an XPath object to its boolean value
6045
 *
6046
 * Returns the boolean value
6047
 */
6048
int
6049
46.6k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6050
46.6k
    int ret = 0;
6051
6052
46.6k
    if (val == NULL)
6053
0
  return(0);
6054
46.6k
    switch (val->type) {
6055
0
    case XPATH_UNDEFINED:
6056
#ifdef DEBUG_EXPR
6057
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6058
#endif
6059
0
  ret = 0;
6060
0
  break;
6061
35.7k
    case XPATH_NODESET:
6062
35.7k
    case XPATH_XSLT_TREE:
6063
35.7k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6064
35.7k
  break;
6065
6.46k
    case XPATH_STRING:
6066
6.46k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6067
6.46k
  break;
6068
4.44k
    case XPATH_NUMBER:
6069
4.44k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6070
4.44k
  break;
6071
0
    case XPATH_BOOLEAN:
6072
0
  ret = val->boolval;
6073
0
  break;
6074
0
    case XPATH_USERS:
6075
#ifdef LIBXML_XPTR_LOCS_ENABLED
6076
    case XPATH_POINT:
6077
    case XPATH_RANGE:
6078
    case XPATH_LOCATIONSET:
6079
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6080
0
  TODO;
6081
0
  ret = 0;
6082
0
  break;
6083
46.6k
    }
6084
46.6k
    return(ret);
6085
46.6k
}
6086
6087
6088
/**
6089
 * xmlXPathConvertBoolean:
6090
 * @val:  an XPath object
6091
 *
6092
 * Converts an existing object to its boolean() equivalent
6093
 *
6094
 * Returns the new object, the old one is freed (or the operation
6095
 *         is done directly on @val)
6096
 */
6097
xmlXPathObjectPtr
6098
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6099
0
    xmlXPathObjectPtr ret;
6100
6101
0
    if (val == NULL)
6102
0
  return(xmlXPathNewBoolean(0));
6103
0
    if (val->type == XPATH_BOOLEAN)
6104
0
  return(val);
6105
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6106
0
    xmlXPathFreeObject(val);
6107
0
    return(ret);
6108
0
}
6109
6110
/************************************************************************
6111
 *                  *
6112
 *    Routines to handle XPath contexts     *
6113
 *                  *
6114
 ************************************************************************/
6115
6116
/**
6117
 * xmlXPathNewContext:
6118
 * @doc:  the XML document
6119
 *
6120
 * Create a new xmlXPathContext
6121
 *
6122
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6123
 */
6124
xmlXPathContextPtr
6125
347k
xmlXPathNewContext(xmlDocPtr doc) {
6126
347k
    xmlXPathContextPtr ret;
6127
6128
347k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6129
347k
    if (ret == NULL) {
6130
0
        xmlXPathErrMemory(NULL, "creating context\n");
6131
0
  return(NULL);
6132
0
    }
6133
347k
    memset(ret, 0 , sizeof(xmlXPathContext));
6134
347k
    ret->doc = doc;
6135
347k
    ret->node = NULL;
6136
6137
347k
    ret->varHash = NULL;
6138
6139
347k
    ret->nb_types = 0;
6140
347k
    ret->max_types = 0;
6141
347k
    ret->types = NULL;
6142
6143
347k
    ret->funcHash = xmlHashCreate(0);
6144
6145
347k
    ret->nb_axis = 0;
6146
347k
    ret->max_axis = 0;
6147
347k
    ret->axis = NULL;
6148
6149
347k
    ret->nsHash = NULL;
6150
347k
    ret->user = NULL;
6151
6152
347k
    ret->contextSize = -1;
6153
347k
    ret->proximityPosition = -1;
6154
6155
#ifdef XP_DEFAULT_CACHE_ON
6156
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6157
  xmlXPathFreeContext(ret);
6158
  return(NULL);
6159
    }
6160
#endif
6161
6162
347k
    xmlXPathRegisterAllFunctions(ret);
6163
6164
347k
    return(ret);
6165
347k
}
6166
6167
/**
6168
 * xmlXPathFreeContext:
6169
 * @ctxt:  the context to free
6170
 *
6171
 * Free up an xmlXPathContext
6172
 */
6173
void
6174
347k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175
347k
    if (ctxt == NULL) return;
6176
6177
347k
    if (ctxt->cache != NULL)
6178
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179
347k
    xmlXPathRegisteredNsCleanup(ctxt);
6180
347k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6181
347k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6182
347k
    xmlResetError(&ctxt->lastError);
6183
347k
    xmlFree(ctxt);
6184
347k
}
6185
6186
/************************************************************************
6187
 *                  *
6188
 *    Routines to handle XPath parser contexts    *
6189
 *                  *
6190
 ************************************************************************/
6191
6192
#define CHECK_CTXT(ctxt)            \
6193
95
    if (ctxt == NULL) {           \
6194
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6195
0
    NULL, NULL, XML_FROM_XPATH,       \
6196
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6197
0
    __FILE__, __LINE__,         \
6198
0
    NULL, NULL, NULL, 0, 0,         \
6199
0
    "NULL context pointer\n");        \
6200
0
  return(NULL);             \
6201
0
    }                  \
6202
6203
#define CHECK_CTXT_NEG(ctxt)            \
6204
12.5k
    if (ctxt == NULL) {           \
6205
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6206
0
    NULL, NULL, XML_FROM_XPATH,       \
6207
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6208
0
    __FILE__, __LINE__,         \
6209
0
    NULL, NULL, NULL, 0, 0,         \
6210
0
    "NULL context pointer\n");        \
6211
0
  return(-1);             \
6212
0
    }                  \
6213
6214
6215
#define CHECK_CONTEXT(ctxt)           \
6216
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6217
        (ctxt->doc->children == NULL)) {        \
6218
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6219
  return(NULL);             \
6220
    }
6221
6222
6223
/**
6224
 * xmlXPathNewParserContext:
6225
 * @str:  the XPath expression
6226
 * @ctxt:  the XPath context
6227
 *
6228
 * Create a new xmlXPathParserContext
6229
 *
6230
 * Returns the xmlXPathParserContext just allocated.
6231
 */
6232
xmlXPathParserContextPtr
6233
365k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234
365k
    xmlXPathParserContextPtr ret;
6235
6236
365k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6237
365k
    if (ret == NULL) {
6238
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6239
0
  return(NULL);
6240
0
    }
6241
365k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6242
365k
    ret->cur = ret->base = str;
6243
365k
    ret->context = ctxt;
6244
6245
365k
    ret->comp = xmlXPathNewCompExpr();
6246
365k
    if (ret->comp == NULL) {
6247
0
  xmlFree(ret->valueTab);
6248
0
  xmlFree(ret);
6249
0
  return(NULL);
6250
0
    }
6251
365k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252
0
        ret->comp->dict = ctxt->dict;
6253
0
  xmlDictReference(ret->comp->dict);
6254
0
    }
6255
6256
365k
    return(ret);
6257
365k
}
6258
6259
/**
6260
 * xmlXPathCompParserContext:
6261
 * @comp:  the XPath compiled expression
6262
 * @ctxt:  the XPath context
6263
 *
6264
 * Create a new xmlXPathParserContext when processing a compiled expression
6265
 *
6266
 * Returns the xmlXPathParserContext just allocated.
6267
 */
6268
static xmlXPathParserContextPtr
6269
12.5k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270
12.5k
    xmlXPathParserContextPtr ret;
6271
6272
12.5k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6273
12.5k
    if (ret == NULL) {
6274
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6275
0
  return(NULL);
6276
0
    }
6277
12.5k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6278
6279
    /* Allocate the value stack */
6280
12.5k
    ret->valueTab = (xmlXPathObjectPtr *)
6281
12.5k
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282
12.5k
    if (ret->valueTab == NULL) {
6283
0
  xmlFree(ret);
6284
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285
0
  return(NULL);
6286
0
    }
6287
12.5k
    ret->valueNr = 0;
6288
12.5k
    ret->valueMax = 10;
6289
12.5k
    ret->value = NULL;
6290
12.5k
    ret->valueFrame = 0;
6291
6292
12.5k
    ret->context = ctxt;
6293
12.5k
    ret->comp = comp;
6294
6295
12.5k
    return(ret);
6296
12.5k
}
6297
6298
/**
6299
 * xmlXPathFreeParserContext:
6300
 * @ctxt:  the context to free
6301
 *
6302
 * Free up an xmlXPathParserContext
6303
 */
6304
void
6305
378k
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6306
378k
    int i;
6307
6308
378k
    if (ctxt->valueTab != NULL) {
6309
366k
        for (i = 0; i < ctxt->valueNr; i++) {
6310
6.54k
            if (ctxt->context)
6311
6.54k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6312
0
            else
6313
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6314
6.54k
        }
6315
359k
        xmlFree(ctxt->valueTab);
6316
359k
    }
6317
378k
    if (ctxt->comp != NULL) {
6318
353k
#ifdef XPATH_STREAMING
6319
353k
  if (ctxt->comp->stream != NULL) {
6320
0
      xmlFreePatternList(ctxt->comp->stream);
6321
0
      ctxt->comp->stream = NULL;
6322
0
  }
6323
353k
#endif
6324
353k
  xmlXPathFreeCompExpr(ctxt->comp);
6325
353k
    }
6326
378k
    xmlFree(ctxt);
6327
378k
}
6328
6329
/************************************************************************
6330
 *                  *
6331
 *    The implicit core function library      *
6332
 *                  *
6333
 ************************************************************************/
6334
6335
/**
6336
 * xmlXPathNodeValHash:
6337
 * @node:  a node pointer
6338
 *
6339
 * Function computing the beginning of the string value of the node,
6340
 * used to speed up comparisons
6341
 *
6342
 * Returns an int usable as a hash
6343
 */
6344
static unsigned int
6345
18.2k
xmlXPathNodeValHash(xmlNodePtr node) {
6346
18.2k
    int len = 2;
6347
18.2k
    const xmlChar * string = NULL;
6348
18.2k
    xmlNodePtr tmp = NULL;
6349
18.2k
    unsigned int ret = 0;
6350
6351
18.2k
    if (node == NULL)
6352
0
  return(0);
6353
6354
18.2k
    if (node->type == XML_DOCUMENT_NODE) {
6355
1.51k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6356
1.51k
  if (tmp == NULL)
6357
0
      node = node->children;
6358
1.51k
  else
6359
1.51k
      node = tmp;
6360
6361
1.51k
  if (node == NULL)
6362
0
      return(0);
6363
1.51k
    }
6364
6365
18.2k
    switch (node->type) {
6366
265
  case XML_COMMENT_NODE:
6367
351
  case XML_PI_NODE:
6368
594
  case XML_CDATA_SECTION_NODE:
6369
3.48k
  case XML_TEXT_NODE:
6370
3.48k
      string = node->content;
6371
3.48k
      if (string == NULL)
6372
0
    return(0);
6373
3.48k
      if (string[0] == 0)
6374
0
    return(0);
6375
3.48k
      return(string[0] + (string[1] << 8));
6376
626
  case XML_NAMESPACE_DECL:
6377
626
      string = ((xmlNsPtr)node)->href;
6378
626
      if (string == NULL)
6379
0
    return(0);
6380
626
      if (string[0] == 0)
6381
0
    return(0);
6382
626
      return(string[0] + (string[1] << 8));
6383
204
  case XML_ATTRIBUTE_NODE:
6384
204
      tmp = ((xmlAttrPtr) node)->children;
6385
204
      break;
6386
13.8k
  case XML_ELEMENT_NODE:
6387
13.8k
      tmp = node->children;
6388
13.8k
      break;
6389
0
  default:
6390
0
      return(0);
6391
18.2k
    }
6392
18.1k
    while (tmp != NULL) {
6393
12.7k
  switch (tmp->type) {
6394
898
      case XML_CDATA_SECTION_NODE:
6395
12.7k
      case XML_TEXT_NODE:
6396
12.7k
    string = tmp->content;
6397
12.7k
    break;
6398
0
      default:
6399
0
                string = NULL;
6400
0
    break;
6401
12.7k
  }
6402
12.7k
  if ((string != NULL) && (string[0] != 0)) {
6403
12.7k
      if (len == 1) {
6404
0
    return(ret + (string[0] << 8));
6405
0
      }
6406
12.7k
      if (string[1] == 0) {
6407
4.04k
    len = 1;
6408
4.04k
    ret = string[0];
6409
8.69k
      } else {
6410
8.69k
    return(string[0] + (string[1] << 8));
6411
8.69k
      }
6412
12.7k
  }
6413
  /*
6414
   * Skip to next node
6415
   */
6416
4.04k
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6417
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6418
0
    tmp = tmp->children;
6419
0
    continue;
6420
0
      }
6421
0
  }
6422
4.04k
  if (tmp == node)
6423
0
      break;
6424
6425
4.04k
  if (tmp->next != NULL) {
6426
0
      tmp = tmp->next;
6427
0
      continue;
6428
0
  }
6429
6430
4.04k
  do {
6431
4.04k
      tmp = tmp->parent;
6432
4.04k
      if (tmp == NULL)
6433
0
    break;
6434
4.04k
      if (tmp == node) {
6435
4.04k
    tmp = NULL;
6436
4.04k
    break;
6437
4.04k
      }
6438
0
      if (tmp->next != NULL) {
6439
0
    tmp = tmp->next;
6440
0
    break;
6441
0
      }
6442
0
  } while (tmp != NULL);
6443
4.04k
    }
6444
5.40k
    return(ret);
6445
14.1k
}
6446
6447
/**
6448
 * xmlXPathStringHash:
6449
 * @string:  a string
6450
 *
6451
 * Function computing the beginning of the string value of the node,
6452
 * used to speed up comparisons
6453
 *
6454
 * Returns an int usable as a hash
6455
 */
6456
static unsigned int
6457
849
xmlXPathStringHash(const xmlChar * string) {
6458
849
    if (string == NULL)
6459
0
  return(0);
6460
849
    if (string[0] == 0)
6461
18
  return(0);
6462
831
    return(string[0] + (string[1] << 8));
6463
849
}
6464
6465
/**
6466
 * xmlXPathCompareNodeSetFloat:
6467
 * @ctxt:  the XPath Parser context
6468
 * @inf:  less than (1) or greater than (0)
6469
 * @strict:  is the comparison strict
6470
 * @arg:  the node set
6471
 * @f:  the value
6472
 *
6473
 * Implement the compare operation between a nodeset and a number
6474
 *     @ns < @val    (1, 1, ...
6475
 *     @ns <= @val   (1, 0, ...
6476
 *     @ns > @val    (0, 1, ...
6477
 *     @ns >= @val   (0, 0, ...
6478
 *
6479
 * If one object to be compared is a node-set and the other is a number,
6480
 * then the comparison will be true if and only if there is a node in the
6481
 * node-set such that the result of performing the comparison on the number
6482
 * to be compared and on the result of converting the string-value of that
6483
 * node to a number using the number function is true.
6484
 *
6485
 * Returns 0 or 1 depending on the results of the test.
6486
 */
6487
static int
6488
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6489
6.45k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6490
6.45k
    int i, ret = 0;
6491
6.45k
    xmlNodeSetPtr ns;
6492
6.45k
    xmlChar *str2;
6493
6494
6.45k
    if ((f == NULL) || (arg == NULL) ||
6495
6.45k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6496
0
  xmlXPathReleaseObject(ctxt->context, arg);
6497
0
  xmlXPathReleaseObject(ctxt->context, f);
6498
0
        return(0);
6499
0
    }
6500
6.45k
    ns = arg->nodesetval;
6501
6.45k
    if (ns != NULL) {
6502
40.5k
  for (i = 0;i < ns->nodeNr;i++) {
6503
35.9k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6504
35.9k
       if (str2 != NULL) {
6505
35.9k
     valuePush(ctxt,
6506
35.9k
         xmlXPathCacheNewString(ctxt->context, str2));
6507
35.9k
     xmlFree(str2);
6508
35.9k
     xmlXPathNumberFunction(ctxt, 1);
6509
35.9k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6510
35.9k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6511
35.9k
     if (ret)
6512
1.07k
         break;
6513
35.9k
       }
6514
35.9k
  }
6515
5.67k
    }
6516
6.45k
    xmlXPathReleaseObject(ctxt->context, arg);
6517
6.45k
    xmlXPathReleaseObject(ctxt->context, f);
6518
6.45k
    return(ret);
6519
6.45k
}
6520
6521
/**
6522
 * xmlXPathCompareNodeSetString:
6523
 * @ctxt:  the XPath Parser context
6524
 * @inf:  less than (1) or greater than (0)
6525
 * @strict:  is the comparison strict
6526
 * @arg:  the node set
6527
 * @s:  the value
6528
 *
6529
 * Implement the compare operation between a nodeset and a string
6530
 *     @ns < @val    (1, 1, ...
6531
 *     @ns <= @val   (1, 0, ...
6532
 *     @ns > @val    (0, 1, ...
6533
 *     @ns >= @val   (0, 0, ...
6534
 *
6535
 * If one object to be compared is a node-set and the other is a string,
6536
 * then the comparison will be true if and only if there is a node in
6537
 * the node-set such that the result of performing the comparison on the
6538
 * string-value of the node and the other string is true.
6539
 *
6540
 * Returns 0 or 1 depending on the results of the test.
6541
 */
6542
static int
6543
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6544
8.69k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6545
8.69k
    int i, ret = 0;
6546
8.69k
    xmlNodeSetPtr ns;
6547
8.69k
    xmlChar *str2;
6548
6549
8.69k
    if ((s == NULL) || (arg == NULL) ||
6550
8.69k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6551
0
  xmlXPathReleaseObject(ctxt->context, arg);
6552
0
  xmlXPathReleaseObject(ctxt->context, s);
6553
0
        return(0);
6554
0
    }
6555
8.69k
    ns = arg->nodesetval;
6556
8.69k
    if (ns != NULL) {
6557
40.6k
  for (i = 0;i < ns->nodeNr;i++) {
6558
32.1k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6559
32.1k
       if (str2 != NULL) {
6560
32.1k
     valuePush(ctxt,
6561
32.1k
         xmlXPathCacheNewString(ctxt->context, str2));
6562
32.1k
     xmlFree(str2);
6563
32.1k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6564
32.1k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6565
32.1k
     if (ret)
6566
0
         break;
6567
32.1k
       }
6568
32.1k
  }
6569
8.43k
    }
6570
8.69k
    xmlXPathReleaseObject(ctxt->context, arg);
6571
8.69k
    xmlXPathReleaseObject(ctxt->context, s);
6572
8.69k
    return(ret);
6573
8.69k
}
6574
6575
/**
6576
 * xmlXPathCompareNodeSets:
6577
 * @inf:  less than (1) or greater than (0)
6578
 * @strict:  is the comparison strict
6579
 * @arg1:  the first node set object
6580
 * @arg2:  the second node set object
6581
 *
6582
 * Implement the compare operation on nodesets:
6583
 *
6584
 * If both objects to be compared are node-sets, then the comparison
6585
 * will be true if and only if there is a node in the first node-set
6586
 * and a node in the second node-set such that the result of performing
6587
 * the comparison on the string-values of the two nodes is true.
6588
 * ....
6589
 * When neither object to be compared is a node-set and the operator
6590
 * is <=, <, >= or >, then the objects are compared by converting both
6591
 * objects to numbers and comparing the numbers according to IEEE 754.
6592
 * ....
6593
 * The number function converts its argument to a number as follows:
6594
 *  - a string that consists of optional whitespace followed by an
6595
 *    optional minus sign followed by a Number followed by whitespace
6596
 *    is converted to the IEEE 754 number that is nearest (according
6597
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6598
 *    represented by the string; any other string is converted to NaN
6599
 *
6600
 * Conclusion all nodes need to be converted first to their string value
6601
 * and then the comparison must be done when possible
6602
 */
6603
static int
6604
xmlXPathCompareNodeSets(int inf, int strict,
6605
21.3k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6606
21.3k
    int i, j, init = 0;
6607
21.3k
    double val1;
6608
21.3k
    double *values2;
6609
21.3k
    int ret = 0;
6610
21.3k
    xmlNodeSetPtr ns1;
6611
21.3k
    xmlNodeSetPtr ns2;
6612
6613
21.3k
    if ((arg1 == NULL) ||
6614
21.3k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6615
0
  xmlXPathFreeObject(arg2);
6616
0
        return(0);
6617
0
    }
6618
21.3k
    if ((arg2 == NULL) ||
6619
21.3k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6620
0
  xmlXPathFreeObject(arg1);
6621
0
  xmlXPathFreeObject(arg2);
6622
0
        return(0);
6623
0
    }
6624
6625
21.3k
    ns1 = arg1->nodesetval;
6626
21.3k
    ns2 = arg2->nodesetval;
6627
6628
21.3k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6629
14.0k
  xmlXPathFreeObject(arg1);
6630
14.0k
  xmlXPathFreeObject(arg2);
6631
14.0k
  return(0);
6632
14.0k
    }
6633
7.32k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6634
2.04k
  xmlXPathFreeObject(arg1);
6635
2.04k
  xmlXPathFreeObject(arg2);
6636
2.04k
  return(0);
6637
2.04k
    }
6638
6639
5.28k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6640
5.28k
    if (values2 == NULL) {
6641
        /* TODO: Propagate memory error. */
6642
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6643
0
  xmlXPathFreeObject(arg1);
6644
0
  xmlXPathFreeObject(arg2);
6645
0
  return(0);
6646
0
    }
6647
57.5k
    for (i = 0;i < ns1->nodeNr;i++) {
6648
52.4k
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6649
52.4k
  if (xmlXPathIsNaN(val1))
6650
48.5k
      continue;
6651
34.9k
  for (j = 0;j < ns2->nodeNr;j++) {
6652
31.2k
      if (init == 0) {
6653
15.5k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6654
15.5k
      }
6655
31.2k
      if (xmlXPathIsNaN(values2[j]))
6656
27.9k
    continue;
6657
3.33k
      if (inf && strict)
6658
2.03k
    ret = (val1 < values2[j]);
6659
1.30k
      else if (inf && !strict)
6660
866
    ret = (val1 <= values2[j]);
6661
440
      else if (!inf && strict)
6662
411
    ret = (val1 > values2[j]);
6663
29
      else if (!inf && !strict)
6664
29
    ret = (val1 >= values2[j]);
6665
3.33k
      if (ret)
6666
170
    break;
6667
3.33k
  }
6668
3.86k
  if (ret)
6669
170
      break;
6670
3.69k
  init = 1;
6671
3.69k
    }
6672
5.28k
    xmlFree(values2);
6673
5.28k
    xmlXPathFreeObject(arg1);
6674
5.28k
    xmlXPathFreeObject(arg2);
6675
5.28k
    return(ret);
6676
5.28k
}
6677
6678
/**
6679
 * xmlXPathCompareNodeSetValue:
6680
 * @ctxt:  the XPath Parser context
6681
 * @inf:  less than (1) or greater than (0)
6682
 * @strict:  is the comparison strict
6683
 * @arg:  the node set
6684
 * @val:  the value
6685
 *
6686
 * Implement the compare operation between a nodeset and a value
6687
 *     @ns < @val    (1, 1, ...
6688
 *     @ns <= @val   (1, 0, ...
6689
 *     @ns > @val    (0, 1, ...
6690
 *     @ns >= @val   (0, 0, ...
6691
 *
6692
 * If one object to be compared is a node-set and the other is a boolean,
6693
 * then the comparison will be true if and only if the result of performing
6694
 * the comparison on the boolean and on the result of converting
6695
 * the node-set to a boolean using the boolean function is true.
6696
 *
6697
 * Returns 0 or 1 depending on the results of the test.
6698
 */
6699
static int
6700
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6701
49.4k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6702
49.4k
    if ((val == NULL) || (arg == NULL) ||
6703
49.4k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6704
0
        return(0);
6705
6706
49.4k
    switch(val->type) {
6707
6.45k
        case XPATH_NUMBER:
6708
6.45k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6709
0
        case XPATH_NODESET:
6710
0
        case XPATH_XSLT_TREE:
6711
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6712
8.69k
        case XPATH_STRING:
6713
8.69k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6714
34.3k
        case XPATH_BOOLEAN:
6715
34.3k
      valuePush(ctxt, arg);
6716
34.3k
      xmlXPathBooleanFunction(ctxt, 1);
6717
34.3k
      valuePush(ctxt, val);
6718
34.3k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6719
0
  default:
6720
0
            xmlGenericError(xmlGenericErrorContext,
6721
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6722
0
                    "and object of type %d\n",
6723
0
                    val->type);
6724
0
            xmlXPathReleaseObject(ctxt->context, arg);
6725
0
            xmlXPathReleaseObject(ctxt->context, val);
6726
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6727
49.4k
    }
6728
0
    return(0);
6729
49.4k
}
6730
6731
/**
6732
 * xmlXPathEqualNodeSetString:
6733
 * @arg:  the nodeset object argument
6734
 * @str:  the string to compare to.
6735
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6736
 *
6737
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6738
 * If one object to be compared is a node-set and the other is a string,
6739
 * then the comparison will be true if and only if there is a node in
6740
 * the node-set such that the result of performing the comparison on the
6741
 * string-value of the node and the other string is true.
6742
 *
6743
 * Returns 0 or 1 depending on the results of the test.
6744
 */
6745
static int
6746
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6747
3.12k
{
6748
3.12k
    int i;
6749
3.12k
    xmlNodeSetPtr ns;
6750
3.12k
    xmlChar *str2;
6751
3.12k
    unsigned int hash;
6752
6753
3.12k
    if ((str == NULL) || (arg == NULL) ||
6754
3.12k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6755
0
        return (0);
6756
3.12k
    ns = arg->nodesetval;
6757
    /*
6758
     * A NULL nodeset compared with a string is always false
6759
     * (since there is no node equal, and no node not equal)
6760
     */
6761
3.12k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6762
2.27k
        return (0);
6763
849
    hash = xmlXPathStringHash(str);
6764
7.45k
    for (i = 0; i < ns->nodeNr; i++) {
6765
6.61k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6766
39
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6767
39
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6768
15
                xmlFree(str2);
6769
15
    if (neq)
6770
0
        continue;
6771
15
                return (1);
6772
24
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6773
0
    if (neq)
6774
0
        continue;
6775
0
                return (1);
6776
24
            } else if (neq) {
6777
0
    if (str2 != NULL)
6778
0
        xmlFree(str2);
6779
0
    return (1);
6780
0
      }
6781
24
            if (str2 != NULL)
6782
24
                xmlFree(str2);
6783
6.58k
        } else if (neq)
6784
2
      return (1);
6785
6.61k
    }
6786
832
    return (0);
6787
849
}
6788
6789
/**
6790
 * xmlXPathEqualNodeSetFloat:
6791
 * @arg:  the nodeset object argument
6792
 * @f:  the float to compare to
6793
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6794
 *
6795
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6796
 * If one object to be compared is a node-set and the other is a number,
6797
 * then the comparison will be true if and only if there is a node in
6798
 * the node-set such that the result of performing the comparison on the
6799
 * number to be compared and on the result of converting the string-value
6800
 * of that node to a number using the number function is true.
6801
 *
6802
 * Returns 0 or 1 depending on the results of the test.
6803
 */
6804
static int
6805
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6806
7.38k
    xmlXPathObjectPtr arg, double f, int neq) {
6807
7.38k
  int i, ret=0;
6808
7.38k
  xmlNodeSetPtr ns;
6809
7.38k
  xmlChar *str2;
6810
7.38k
  xmlXPathObjectPtr val;
6811
7.38k
  double v;
6812
6813
7.38k
    if ((arg == NULL) ||
6814
7.38k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6815
0
        return(0);
6816
6817
7.38k
    ns = arg->nodesetval;
6818
7.38k
    if (ns != NULL) {
6819
14.1k
  for (i=0;i<ns->nodeNr;i++) {
6820
7.24k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6821
7.24k
      if (str2 != NULL) {
6822
7.24k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6823
7.24k
    xmlFree(str2);
6824
7.24k
    xmlXPathNumberFunction(ctxt, 1);
6825
7.24k
    val = valuePop(ctxt);
6826
7.24k
    v = val->floatval;
6827
7.24k
    xmlXPathReleaseObject(ctxt->context, val);
6828
7.24k
    if (!xmlXPathIsNaN(v)) {
6829
737
        if ((!neq) && (v==f)) {
6830
11
      ret = 1;
6831
11
      break;
6832
726
        } else if ((neq) && (v!=f)) {
6833
135
      ret = 1;
6834
135
      break;
6835
135
        }
6836
6.50k
    } else { /* NaN is unequal to any value */
6837
6.50k
        if (neq)
6838
1.54k
      ret = 1;
6839
6.50k
    }
6840
7.24k
      }
6841
7.24k
  }
6842
7.05k
    }
6843
6844
7.38k
    return(ret);
6845
7.38k
}
6846
6847
6848
/**
6849
 * xmlXPathEqualNodeSets:
6850
 * @arg1:  first nodeset object argument
6851
 * @arg2:  second nodeset object argument
6852
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6853
 *
6854
 * Implement the equal / not equal operation on XPath nodesets:
6855
 * @arg1 == @arg2  or  @arg1 != @arg2
6856
 * If both objects to be compared are node-sets, then the comparison
6857
 * will be true if and only if there is a node in the first node-set and
6858
 * a node in the second node-set such that the result of performing the
6859
 * comparison on the string-values of the two nodes is true.
6860
 *
6861
 * (needless to say, this is a costly operation)
6862
 *
6863
 * Returns 0 or 1 depending on the results of the test.
6864
 */
6865
static int
6866
6.61k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6867
6.61k
    int i, j;
6868
6.61k
    unsigned int *hashs1;
6869
6.61k
    unsigned int *hashs2;
6870
6.61k
    xmlChar **values1;
6871
6.61k
    xmlChar **values2;
6872
6.61k
    int ret = 0;
6873
6.61k
    xmlNodeSetPtr ns1;
6874
6.61k
    xmlNodeSetPtr ns2;
6875
6876
6.61k
    if ((arg1 == NULL) ||
6877
6.61k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6878
0
        return(0);
6879
6.61k
    if ((arg2 == NULL) ||
6880
6.61k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6881
0
        return(0);
6882
6883
6.61k
    ns1 = arg1->nodesetval;
6884
6.61k
    ns2 = arg2->nodesetval;
6885
6886
6.61k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6887
1.22k
  return(0);
6888
5.38k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6889
2.93k
  return(0);
6890
6891
    /*
6892
     * for equal, check if there is a node pertaining to both sets
6893
     */
6894
2.45k
    if (neq == 0)
6895
10.0k
  for (i = 0;i < ns1->nodeNr;i++)
6896
30.5k
      for (j = 0;j < ns2->nodeNr;j++)
6897
22.8k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6898
1.04k
        return(1);
6899
6900
1.40k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6901
1.40k
    if (values1 == NULL) {
6902
        /* TODO: Propagate memory error. */
6903
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6904
0
  return(0);
6905
0
    }
6906
1.40k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6907
1.40k
    if (hashs1 == NULL) {
6908
        /* TODO: Propagate memory error. */
6909
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910
0
  xmlFree(values1);
6911
0
  return(0);
6912
0
    }
6913
1.40k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6914
1.40k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6915
1.40k
    if (values2 == NULL) {
6916
        /* TODO: Propagate memory error. */
6917
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918
0
  xmlFree(hashs1);
6919
0
  xmlFree(values1);
6920
0
  return(0);
6921
0
    }
6922
1.40k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6923
1.40k
    if (hashs2 == NULL) {
6924
        /* TODO: Propagate memory error. */
6925
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926
0
  xmlFree(hashs1);
6927
0
  xmlFree(values1);
6928
0
  xmlFree(values2);
6929
0
  return(0);
6930
0
    }
6931
1.40k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932
7.71k
    for (i = 0;i < ns1->nodeNr;i++) {
6933
6.52k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934
19.3k
  for (j = 0;j < ns2->nodeNr;j++) {
6935
13.0k
      if (i == 0)
6936
5.06k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937
13.0k
      if (hashs1[i] != hashs2[j]) {
6938
11.0k
    if (neq) {
6939
10
        ret = 1;
6940
10
        break;
6941
10
    }
6942
11.0k
      }
6943
2.01k
      else {
6944
2.01k
    if (values1[i] == NULL)
6945
1.13k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946
2.01k
    if (values2[j] == NULL)
6947
1.86k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948
2.01k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949
2.01k
    if (ret)
6950
203
        break;
6951
2.01k
      }
6952
13.0k
  }
6953
6.52k
  if (ret)
6954
213
      break;
6955
6.52k
    }
6956
8.35k
    for (i = 0;i < ns1->nodeNr;i++)
6957
6.94k
  if (values1[i] != NULL)
6958
1.13k
      xmlFree(values1[i]);
6959
8.27k
    for (j = 0;j < ns2->nodeNr;j++)
6960
6.86k
  if (values2[j] != NULL)
6961
1.86k
      xmlFree(values2[j]);
6962
1.40k
    xmlFree(values1);
6963
1.40k
    xmlFree(values2);
6964
1.40k
    xmlFree(hashs1);
6965
1.40k
    xmlFree(hashs2);
6966
1.40k
    return(ret);
6967
1.40k
}
6968
6969
static int
6970
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971
178k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972
178k
    int ret = 0;
6973
    /*
6974
     *At this point we are assured neither arg1 nor arg2
6975
     *is a nodeset, so we can just pick the appropriate routine.
6976
     */
6977
178k
    switch (arg1->type) {
6978
0
        case XPATH_UNDEFINED:
6979
#ifdef DEBUG_EXPR
6980
      xmlGenericError(xmlGenericErrorContext,
6981
        "Equal: undefined\n");
6982
#endif
6983
0
      break;
6984
20.3k
        case XPATH_BOOLEAN:
6985
20.3k
      switch (arg2->type) {
6986
0
          case XPATH_UNDEFINED:
6987
#ifdef DEBUG_EXPR
6988
        xmlGenericError(xmlGenericErrorContext,
6989
          "Equal: undefined\n");
6990
#endif
6991
0
        break;
6992
9.52k
    case XPATH_BOOLEAN:
6993
#ifdef DEBUG_EXPR
6994
        xmlGenericError(xmlGenericErrorContext,
6995
          "Equal: %d boolean %d \n",
6996
          arg1->boolval, arg2->boolval);
6997
#endif
6998
9.52k
        ret = (arg1->boolval == arg2->boolval);
6999
9.52k
        break;
7000
8.56k
    case XPATH_NUMBER:
7001
8.56k
        ret = (arg1->boolval ==
7002
8.56k
         xmlXPathCastNumberToBoolean(arg2->floatval));
7003
8.56k
        break;
7004
2.28k
    case XPATH_STRING:
7005
2.28k
        if ((arg2->stringval == NULL) ||
7006
2.28k
      (arg2->stringval[0] == 0)) ret = 0;
7007
2.28k
        else
7008
2.28k
      ret = 1;
7009
2.28k
        ret = (arg1->boolval == ret);
7010
2.28k
        break;
7011
0
    case XPATH_USERS:
7012
#ifdef LIBXML_XPTR_LOCS_ENABLED
7013
    case XPATH_POINT:
7014
    case XPATH_RANGE:
7015
    case XPATH_LOCATIONSET:
7016
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7017
0
        TODO
7018
0
        break;
7019
0
    case XPATH_NODESET:
7020
0
    case XPATH_XSLT_TREE:
7021
0
        break;
7022
20.3k
      }
7023
20.3k
      break;
7024
141k
        case XPATH_NUMBER:
7025
141k
      switch (arg2->type) {
7026
0
          case XPATH_UNDEFINED:
7027
#ifdef DEBUG_EXPR
7028
        xmlGenericError(xmlGenericErrorContext,
7029
          "Equal: undefined\n");
7030
#endif
7031
0
        break;
7032
7.71k
    case XPATH_BOOLEAN:
7033
7.71k
        ret = (arg2->boolval==
7034
7.71k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7035
7.71k
        break;
7036
9.15k
    case XPATH_STRING:
7037
9.15k
        valuePush(ctxt, arg2);
7038
9.15k
        xmlXPathNumberFunction(ctxt, 1);
7039
9.15k
        arg2 = valuePop(ctxt);
7040
                    /* Falls through. */
7041
133k
    case XPATH_NUMBER:
7042
        /* Hand check NaN and Infinity equalities */
7043
133k
        if (xmlXPathIsNaN(arg1->floatval) ||
7044
133k
          xmlXPathIsNaN(arg2->floatval)) {
7045
15.4k
            ret = 0;
7046
118k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047
153
            if (xmlXPathIsInf(arg2->floatval) == 1)
7048
13
          ret = 1;
7049
140
      else
7050
140
          ret = 0;
7051
118k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052
40
      if (xmlXPathIsInf(arg2->floatval) == -1)
7053
0
          ret = 1;
7054
40
      else
7055
40
          ret = 0;
7056
118k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057
626
      if (xmlXPathIsInf(arg1->floatval) == 1)
7058
0
          ret = 1;
7059
626
      else
7060
626
          ret = 0;
7061
117k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062
30
      if (xmlXPathIsInf(arg1->floatval) == -1)
7063
0
          ret = 1;
7064
30
      else
7065
30
          ret = 0;
7066
117k
        } else {
7067
117k
            ret = (arg1->floatval == arg2->floatval);
7068
117k
        }
7069
133k
        break;
7070
0
    case XPATH_USERS:
7071
#ifdef LIBXML_XPTR_LOCS_ENABLED
7072
    case XPATH_POINT:
7073
    case XPATH_RANGE:
7074
    case XPATH_LOCATIONSET:
7075
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7076
0
        TODO
7077
0
        break;
7078
0
    case XPATH_NODESET:
7079
0
    case XPATH_XSLT_TREE:
7080
0
        break;
7081
141k
      }
7082
141k
      break;
7083
141k
        case XPATH_STRING:
7084
16.1k
      switch (arg2->type) {
7085
0
          case XPATH_UNDEFINED:
7086
#ifdef DEBUG_EXPR
7087
        xmlGenericError(xmlGenericErrorContext,
7088
          "Equal: undefined\n");
7089
#endif
7090
0
        break;
7091
7.14k
    case XPATH_BOOLEAN:
7092
7.14k
        if ((arg1->stringval == NULL) ||
7093
7.14k
      (arg1->stringval[0] == 0)) ret = 0;
7094
7.14k
        else
7095
7.14k
      ret = 1;
7096
7.14k
        ret = (arg2->boolval == ret);
7097
7.14k
        break;
7098
3.04k
    case XPATH_STRING:
7099
3.04k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7100
3.04k
        break;
7101
5.98k
    case XPATH_NUMBER:
7102
5.98k
        valuePush(ctxt, arg1);
7103
5.98k
        xmlXPathNumberFunction(ctxt, 1);
7104
5.98k
        arg1 = valuePop(ctxt);
7105
        /* Hand check NaN and Infinity equalities */
7106
5.98k
        if (xmlXPathIsNaN(arg1->floatval) ||
7107
5.98k
          xmlXPathIsNaN(arg2->floatval)) {
7108
5.98k
            ret = 0;
7109
5.98k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7110
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7111
0
          ret = 1;
7112
0
      else
7113
0
          ret = 0;
7114
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7115
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7116
0
          ret = 1;
7117
0
      else
7118
0
          ret = 0;
7119
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7120
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7121
0
          ret = 1;
7122
0
      else
7123
0
          ret = 0;
7124
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7125
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7126
0
          ret = 1;
7127
0
      else
7128
0
          ret = 0;
7129
0
        } else {
7130
0
            ret = (arg1->floatval == arg2->floatval);
7131
0
        }
7132
5.98k
        break;
7133
0
    case XPATH_USERS:
7134
#ifdef LIBXML_XPTR_LOCS_ENABLED
7135
    case XPATH_POINT:
7136
    case XPATH_RANGE:
7137
    case XPATH_LOCATIONSET:
7138
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7139
0
        TODO
7140
0
        break;
7141
0
    case XPATH_NODESET:
7142
0
    case XPATH_XSLT_TREE:
7143
0
        break;
7144
16.1k
      }
7145
16.1k
      break;
7146
16.1k
        case XPATH_USERS:
7147
#ifdef LIBXML_XPTR_LOCS_ENABLED
7148
  case XPATH_POINT:
7149
  case XPATH_RANGE:
7150
  case XPATH_LOCATIONSET:
7151
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7152
2
      TODO
7153
2
      break;
7154
0
  case XPATH_NODESET:
7155
0
  case XPATH_XSLT_TREE:
7156
0
      break;
7157
178k
    }
7158
178k
    xmlXPathReleaseObject(ctxt->context, arg1);
7159
178k
    xmlXPathReleaseObject(ctxt->context, arg2);
7160
178k
    return(ret);
7161
178k
}
7162
7163
/**
7164
 * xmlXPathEqualValues:
7165
 * @ctxt:  the XPath Parser context
7166
 *
7167
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7168
 *
7169
 * Returns 0 or 1 depending on the results of the test.
7170
 */
7171
int
7172
210k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7173
210k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7174
210k
    int ret = 0;
7175
7176
210k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7177
210k
    arg2 = valuePop(ctxt);
7178
210k
    arg1 = valuePop(ctxt);
7179
210k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7180
0
  if (arg1 != NULL)
7181
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7182
0
  else
7183
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7184
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7185
0
    }
7186
7187
210k
    if (arg1 == arg2) {
7188
#ifdef DEBUG_EXPR
7189
        xmlGenericError(xmlGenericErrorContext,
7190
    "Equal: by pointer\n");
7191
#endif
7192
0
  xmlXPathFreeObject(arg1);
7193
0
        return(1);
7194
0
    }
7195
7196
    /*
7197
     *If either argument is a nodeset, it's a 'special case'
7198
     */
7199
210k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7200
210k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7201
  /*
7202
   *Hack it to assure arg1 is the nodeset
7203
   */
7204
34.0k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7205
10.3k
    argtmp = arg2;
7206
10.3k
    arg2 = arg1;
7207
10.3k
    arg1 = argtmp;
7208
10.3k
  }
7209
34.0k
  switch (arg2->type) {
7210
0
      case XPATH_UNDEFINED:
7211
#ifdef DEBUG_EXPR
7212
    xmlGenericError(xmlGenericErrorContext,
7213
      "Equal: undefined\n");
7214
#endif
7215
0
    break;
7216
6.16k
      case XPATH_NODESET:
7217
6.16k
      case XPATH_XSLT_TREE:
7218
6.16k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7219
6.16k
    break;
7220
18.6k
      case XPATH_BOOLEAN:
7221
18.6k
    if ((arg1->nodesetval == NULL) ||
7222
18.6k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7223
10.7k
    else
7224
10.7k
        ret = 1;
7225
18.6k
    ret = (ret == arg2->boolval);
7226
18.6k
    break;
7227
6.12k
      case XPATH_NUMBER:
7228
6.12k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7229
6.12k
    break;
7230
3.09k
      case XPATH_STRING:
7231
3.09k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7232
3.09k
    break;
7233
0
      case XPATH_USERS:
7234
#ifdef LIBXML_XPTR_LOCS_ENABLED
7235
      case XPATH_POINT:
7236
      case XPATH_RANGE:
7237
      case XPATH_LOCATIONSET:
7238
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7239
0
    TODO
7240
0
    break;
7241
34.0k
  }
7242
34.0k
  xmlXPathReleaseObject(ctxt->context, arg1);
7243
34.0k
  xmlXPathReleaseObject(ctxt->context, arg2);
7244
34.0k
  return(ret);
7245
34.0k
    }
7246
7247
176k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248
210k
}
7249
7250
/**
7251
 * xmlXPathNotEqualValues:
7252
 * @ctxt:  the XPath Parser context
7253
 *
7254
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7255
 *
7256
 * Returns 0 or 1 depending on the results of the test.
7257
 */
7258
int
7259
4.06k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260
4.06k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7261
4.06k
    int ret = 0;
7262
7263
4.06k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264
4.06k
    arg2 = valuePop(ctxt);
7265
4.06k
    arg1 = valuePop(ctxt);
7266
4.06k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7267
0
  if (arg1 != NULL)
7268
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7269
0
  else
7270
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7271
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7272
0
    }
7273
7274
4.06k
    if (arg1 == arg2) {
7275
#ifdef DEBUG_EXPR
7276
        xmlGenericError(xmlGenericErrorContext,
7277
    "NotEqual: by pointer\n");
7278
#endif
7279
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7280
0
        return(0);
7281
0
    }
7282
7283
    /*
7284
     *If either argument is a nodeset, it's a 'special case'
7285
     */
7286
4.06k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287
4.06k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288
  /*
7289
   *Hack it to assure arg1 is the nodeset
7290
   */
7291
2.64k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292
716
    argtmp = arg2;
7293
716
    arg2 = arg1;
7294
716
    arg1 = argtmp;
7295
716
  }
7296
2.64k
  switch (arg2->type) {
7297
0
      case XPATH_UNDEFINED:
7298
#ifdef DEBUG_EXPR
7299
    xmlGenericError(xmlGenericErrorContext,
7300
      "NotEqual: undefined\n");
7301
#endif
7302
0
    break;
7303
452
      case XPATH_NODESET:
7304
452
      case XPATH_XSLT_TREE:
7305
452
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306
452
    break;
7307
892
      case XPATH_BOOLEAN:
7308
892
    if ((arg1->nodesetval == NULL) ||
7309
892
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7310
275
    else
7311
275
        ret = 1;
7312
892
    ret = (ret != arg2->boolval);
7313
892
    break;
7314
1.26k
      case XPATH_NUMBER:
7315
1.26k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316
1.26k
    break;
7317
30
      case XPATH_STRING:
7318
30
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319
30
    break;
7320
0
      case XPATH_USERS:
7321
#ifdef LIBXML_XPTR_LOCS_ENABLED
7322
      case XPATH_POINT:
7323
      case XPATH_RANGE:
7324
      case XPATH_LOCATIONSET:
7325
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7326
0
    TODO
7327
0
    break;
7328
2.64k
  }
7329
2.64k
  xmlXPathReleaseObject(ctxt->context, arg1);
7330
2.64k
  xmlXPathReleaseObject(ctxt->context, arg2);
7331
2.64k
  return(ret);
7332
2.64k
    }
7333
7334
1.42k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7335
4.06k
}
7336
7337
/**
7338
 * xmlXPathCompareValues:
7339
 * @ctxt:  the XPath Parser context
7340
 * @inf:  less than (1) or greater than (0)
7341
 * @strict:  is the comparison strict
7342
 *
7343
 * Implement the compare operation on XPath objects:
7344
 *     @arg1 < @arg2    (1, 1, ...
7345
 *     @arg1 <= @arg2   (1, 0, ...
7346
 *     @arg1 > @arg2    (0, 1, ...
7347
 *     @arg1 >= @arg2   (0, 0, ...
7348
 *
7349
 * When neither object to be compared is a node-set and the operator is
7350
 * <=, <, >=, >, then the objects are compared by converted both objects
7351
 * to numbers and comparing the numbers according to IEEE 754. The <
7352
 * comparison will be true if and only if the first number is less than the
7353
 * second number. The <= comparison will be true if and only if the first
7354
 * number is less than or equal to the second number. The > comparison
7355
 * will be true if and only if the first number is greater than the second
7356
 * number. The >= comparison will be true if and only if the first number
7357
 * is greater than or equal to the second number.
7358
 *
7359
 * Returns 1 if the comparison succeeded, 0 if it failed
7360
 */
7361
int
7362
198k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7363
198k
    int ret = 0, arg1i = 0, arg2i = 0;
7364
198k
    xmlXPathObjectPtr arg1, arg2;
7365
7366
198k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7367
198k
    arg2 = valuePop(ctxt);
7368
198k
    arg1 = valuePop(ctxt);
7369
198k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7370
0
  if (arg1 != NULL)
7371
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7372
0
  else
7373
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7374
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7375
0
    }
7376
7377
198k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7378
198k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7379
  /*
7380
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7381
   * are not freed from within this routine; they will be freed from the
7382
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7383
   */
7384
70.8k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7385
70.8k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7386
21.3k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7387
49.4k
  } else {
7388
49.4k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7389
35.2k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7390
35.2k
                                arg1, arg2);
7391
35.2k
      } else {
7392
14.2k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7393
14.2k
                                arg2, arg1);
7394
14.2k
      }
7395
49.4k
  }
7396
70.8k
  return(ret);
7397
70.8k
    }
7398
7399
127k
    if (arg1->type != XPATH_NUMBER) {
7400
86.7k
  valuePush(ctxt, arg1);
7401
86.7k
  xmlXPathNumberFunction(ctxt, 1);
7402
86.7k
  arg1 = valuePop(ctxt);
7403
86.7k
    }
7404
127k
    if (arg1->type != XPATH_NUMBER) {
7405
0
  xmlXPathFreeObject(arg1);
7406
0
  xmlXPathFreeObject(arg2);
7407
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7408
0
    }
7409
127k
    if (arg2->type != XPATH_NUMBER) {
7410
68.1k
  valuePush(ctxt, arg2);
7411
68.1k
  xmlXPathNumberFunction(ctxt, 1);
7412
68.1k
  arg2 = valuePop(ctxt);
7413
68.1k
    }
7414
127k
    if (arg2->type != XPATH_NUMBER) {
7415
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7416
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7417
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7418
0
    }
7419
    /*
7420
     * Add tests for infinity and nan
7421
     * => feedback on 3.4 for Inf and NaN
7422
     */
7423
    /* Hand check NaN and Infinity comparisons */
7424
127k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7425
79.3k
  ret=0;
7426
79.3k
    } else {
7427
47.9k
  arg1i=xmlXPathIsInf(arg1->floatval);
7428
47.9k
  arg2i=xmlXPathIsInf(arg2->floatval);
7429
47.9k
  if (inf && strict) {
7430
5.81k
      if ((arg1i == -1 && arg2i != -1) ||
7431
5.81k
    (arg2i == 1 && arg1i != 1)) {
7432
196
    ret = 1;
7433
5.61k
      } else if (arg1i == 0 && arg2i == 0) {
7434
5.56k
    ret = (arg1->floatval < arg2->floatval);
7435
5.56k
      } else {
7436
48
    ret = 0;
7437
48
      }
7438
5.81k
  }
7439
42.0k
  else if (inf && !strict) {
7440
3.74k
      if (arg1i == -1 || arg2i == 1) {
7441
1.85k
    ret = 1;
7442
1.89k
      } else if (arg1i == 0 && arg2i == 0) {
7443
1.89k
    ret = (arg1->floatval <= arg2->floatval);
7444
1.89k
      } else {
7445
0
    ret = 0;
7446
0
      }
7447
3.74k
  }
7448
38.3k
  else if (!inf && strict) {
7449
36.6k
      if ((arg1i == 1 && arg2i != 1) ||
7450
36.6k
    (arg2i == -1 && arg1i != -1)) {
7451
846
    ret = 1;
7452
35.8k
      } else if (arg1i == 0 && arg2i == 0) {
7453
35.8k
    ret = (arg1->floatval > arg2->floatval);
7454
35.8k
      } else {
7455
11
    ret = 0;
7456
11
      }
7457
36.6k
  }
7458
1.65k
  else if (!inf && !strict) {
7459
1.65k
      if (arg1i == 1 || arg2i == -1) {
7460
219
    ret = 1;
7461
1.43k
      } else if (arg1i == 0 && arg2i == 0) {
7462
1.40k
    ret = (arg1->floatval >= arg2->floatval);
7463
1.40k
      } else {
7464
29
    ret = 0;
7465
29
      }
7466
1.65k
  }
7467
47.9k
    }
7468
127k
    xmlXPathReleaseObject(ctxt->context, arg1);
7469
127k
    xmlXPathReleaseObject(ctxt->context, arg2);
7470
127k
    return(ret);
7471
127k
}
7472
7473
/**
7474
 * xmlXPathValueFlipSign:
7475
 * @ctxt:  the XPath Parser context
7476
 *
7477
 * Implement the unary - operation on an XPath object
7478
 * The numeric operators convert their operands to numbers as if
7479
 * by calling the number function.
7480
 */
7481
void
7482
6.61k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7483
6.61k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7484
6.61k
    CAST_TO_NUMBER;
7485
6.61k
    CHECK_TYPE(XPATH_NUMBER);
7486
6.61k
    ctxt->value->floatval = -ctxt->value->floatval;
7487
6.61k
}
7488
7489
/**
7490
 * xmlXPathAddValues:
7491
 * @ctxt:  the XPath Parser context
7492
 *
7493
 * Implement the add operation on XPath objects:
7494
 * The numeric operators convert their operands to numbers as if
7495
 * by calling the number function.
7496
 */
7497
void
7498
3.09k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7499
3.09k
    xmlXPathObjectPtr arg;
7500
3.09k
    double val;
7501
7502
3.09k
    arg = valuePop(ctxt);
7503
3.09k
    if (arg == NULL)
7504
3.09k
  XP_ERROR(XPATH_INVALID_OPERAND);
7505
3.09k
    val = xmlXPathCastToNumber(arg);
7506
3.09k
    xmlXPathReleaseObject(ctxt->context, arg);
7507
3.09k
    CAST_TO_NUMBER;
7508
3.09k
    CHECK_TYPE(XPATH_NUMBER);
7509
3.09k
    ctxt->value->floatval += val;
7510
3.09k
}
7511
7512
/**
7513
 * xmlXPathSubValues:
7514
 * @ctxt:  the XPath Parser context
7515
 *
7516
 * Implement the subtraction operation on XPath objects:
7517
 * The numeric operators convert their operands to numbers as if
7518
 * by calling the number function.
7519
 */
7520
void
7521
14.9k
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7522
14.9k
    xmlXPathObjectPtr arg;
7523
14.9k
    double val;
7524
7525
14.9k
    arg = valuePop(ctxt);
7526
14.9k
    if (arg == NULL)
7527
14.9k
  XP_ERROR(XPATH_INVALID_OPERAND);
7528
14.9k
    val = xmlXPathCastToNumber(arg);
7529
14.9k
    xmlXPathReleaseObject(ctxt->context, arg);
7530
14.9k
    CAST_TO_NUMBER;
7531
14.9k
    CHECK_TYPE(XPATH_NUMBER);
7532
14.9k
    ctxt->value->floatval -= val;
7533
14.9k
}
7534
7535
/**
7536
 * xmlXPathMultValues:
7537
 * @ctxt:  the XPath Parser context
7538
 *
7539
 * Implement the multiply operation on XPath objects:
7540
 * The numeric operators convert their operands to numbers as if
7541
 * by calling the number function.
7542
 */
7543
void
7544
234k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7545
234k
    xmlXPathObjectPtr arg;
7546
234k
    double val;
7547
7548
234k
    arg = valuePop(ctxt);
7549
234k
    if (arg == NULL)
7550
234k
  XP_ERROR(XPATH_INVALID_OPERAND);
7551
234k
    val = xmlXPathCastToNumber(arg);
7552
234k
    xmlXPathReleaseObject(ctxt->context, arg);
7553
234k
    CAST_TO_NUMBER;
7554
234k
    CHECK_TYPE(XPATH_NUMBER);
7555
234k
    ctxt->value->floatval *= val;
7556
234k
}
7557
7558
/**
7559
 * xmlXPathDivValues:
7560
 * @ctxt:  the XPath Parser context
7561
 *
7562
 * Implement the div operation on XPath objects @arg1 / @arg2:
7563
 * The numeric operators convert their operands to numbers as if
7564
 * by calling the number function.
7565
 */
7566
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7567
void
7568
6.51k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7569
6.51k
    xmlXPathObjectPtr arg;
7570
6.51k
    double val;
7571
7572
6.51k
    arg = valuePop(ctxt);
7573
6.51k
    if (arg == NULL)
7574
6.51k
  XP_ERROR(XPATH_INVALID_OPERAND);
7575
6.51k
    val = xmlXPathCastToNumber(arg);
7576
6.51k
    xmlXPathReleaseObject(ctxt->context, arg);
7577
6.51k
    CAST_TO_NUMBER;
7578
6.51k
    CHECK_TYPE(XPATH_NUMBER);
7579
6.51k
    ctxt->value->floatval /= val;
7580
6.51k
}
7581
7582
/**
7583
 * xmlXPathModValues:
7584
 * @ctxt:  the XPath Parser context
7585
 *
7586
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7587
 * The numeric operators convert their operands to numbers as if
7588
 * by calling the number function.
7589
 */
7590
void
7591
7.13k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7592
7.13k
    xmlXPathObjectPtr arg;
7593
7.13k
    double arg1, arg2;
7594
7595
7.13k
    arg = valuePop(ctxt);
7596
7.13k
    if (arg == NULL)
7597
7.13k
  XP_ERROR(XPATH_INVALID_OPERAND);
7598
7.13k
    arg2 = xmlXPathCastToNumber(arg);
7599
7.13k
    xmlXPathReleaseObject(ctxt->context, arg);
7600
7.13k
    CAST_TO_NUMBER;
7601
7.13k
    CHECK_TYPE(XPATH_NUMBER);
7602
7.13k
    arg1 = ctxt->value->floatval;
7603
7.13k
    if (arg2 == 0)
7604
32
  ctxt->value->floatval = xmlXPathNAN;
7605
7.10k
    else {
7606
7.10k
  ctxt->value->floatval = fmod(arg1, arg2);
7607
7.10k
    }
7608
7.13k
}
7609
7610
/************************************************************************
7611
 *                  *
7612
 *    The traversal functions         *
7613
 *                  *
7614
 ************************************************************************/
7615
7616
/*
7617
 * A traversal function enumerates nodes along an axis.
7618
 * Initially it must be called with NULL, and it indicates
7619
 * termination on the axis by returning NULL.
7620
 */
7621
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7622
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7623
7624
/*
7625
 * xmlXPathTraversalFunctionExt:
7626
 * A traversal function enumerates nodes along an axis.
7627
 * Initially it must be called with NULL, and it indicates
7628
 * termination on the axis by returning NULL.
7629
 * The context node of the traversal is specified via @contextNode.
7630
 */
7631
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7632
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7633
7634
/*
7635
 * xmlXPathNodeSetMergeFunction:
7636
 * Used for merging node sets in xmlXPathCollectAndTest().
7637
 */
7638
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7639
        (xmlNodeSetPtr, xmlNodeSetPtr);
7640
7641
7642
/**
7643
 * xmlXPathNextSelf:
7644
 * @ctxt:  the XPath Parser context
7645
 * @cur:  the current node in the traversal
7646
 *
7647
 * Traversal function for the "self" direction
7648
 * The self axis contains just the context node itself
7649
 *
7650
 * Returns the next element following that axis
7651
 */
7652
xmlNodePtr
7653
6.41k
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7654
6.41k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7655
6.41k
    if (cur == NULL)
7656
3.20k
        return(ctxt->context->node);
7657
3.20k
    return(NULL);
7658
6.41k
}
7659
7660
/**
7661
 * xmlXPathNextChild:
7662
 * @ctxt:  the XPath Parser context
7663
 * @cur:  the current node in the traversal
7664
 *
7665
 * Traversal function for the "child" direction
7666
 * The child axis contains the children of the context node in document order.
7667
 *
7668
 * Returns the next element following that axis
7669
 */
7670
xmlNodePtr
7671
36.0k
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7672
36.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7673
36.0k
    if (cur == NULL) {
7674
16.4k
  if (ctxt->context->node == NULL) return(NULL);
7675
16.4k
  switch (ctxt->context->node->type) {
7676
4.89k
            case XML_ELEMENT_NODE:
7677
11.4k
            case XML_TEXT_NODE:
7678
11.8k
            case XML_CDATA_SECTION_NODE:
7679
11.8k
            case XML_ENTITY_REF_NODE:
7680
11.8k
            case XML_ENTITY_NODE:
7681
12.2k
            case XML_PI_NODE:
7682
12.8k
            case XML_COMMENT_NODE:
7683
12.8k
            case XML_NOTATION_NODE:
7684
12.8k
            case XML_DTD_NODE:
7685
12.8k
    return(ctxt->context->node->children);
7686
3.20k
            case XML_DOCUMENT_NODE:
7687
3.20k
            case XML_DOCUMENT_TYPE_NODE:
7688
3.20k
            case XML_DOCUMENT_FRAG_NODE:
7689
3.20k
            case XML_HTML_DOCUMENT_NODE:
7690
3.20k
    return(((xmlDocPtr) ctxt->context->node)->children);
7691
0
      case XML_ELEMENT_DECL:
7692
0
      case XML_ATTRIBUTE_DECL:
7693
0
      case XML_ENTITY_DECL:
7694
326
            case XML_ATTRIBUTE_NODE:
7695
401
      case XML_NAMESPACE_DECL:
7696
401
      case XML_XINCLUDE_START:
7697
401
      case XML_XINCLUDE_END:
7698
401
    return(NULL);
7699
16.4k
  }
7700
0
  return(NULL);
7701
16.4k
    }
7702
19.6k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7703
19.6k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7704
0
  return(NULL);
7705
19.6k
    return(cur->next);
7706
19.6k
}
7707
7708
/**
7709
 * xmlXPathNextChildElement:
7710
 * @ctxt:  the XPath Parser context
7711
 * @cur:  the current node in the traversal
7712
 *
7713
 * Traversal function for the "child" direction and nodes of type element.
7714
 * The child axis contains the children of the context node in document order.
7715
 *
7716
 * Returns the next element following that axis
7717
 */
7718
static xmlNodePtr
7719
1.58M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7720
1.58M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7721
1.58M
    if (cur == NULL) {
7722
1.15M
  cur = ctxt->context->node;
7723
1.15M
  if (cur == NULL) return(NULL);
7724
  /*
7725
  * Get the first element child.
7726
  */
7727
1.15M
  switch (cur->type) {
7728
411k
            case XML_ELEMENT_NODE:
7729
411k
      case XML_DOCUMENT_FRAG_NODE:
7730
411k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7731
411k
            case XML_ENTITY_NODE:
7732
411k
    cur = cur->children;
7733
411k
    if (cur != NULL) {
7734
317k
        if (cur->type == XML_ELEMENT_NODE)
7735
0
      return(cur);
7736
317k
        do {
7737
317k
      cur = cur->next;
7738
317k
        } while ((cur != NULL) &&
7739
317k
      (cur->type != XML_ELEMENT_NODE));
7740
317k
        return(cur);
7741
317k
    }
7742
94.4k
    return(NULL);
7743
57.1k
            case XML_DOCUMENT_NODE:
7744
57.1k
            case XML_HTML_DOCUMENT_NODE:
7745
57.1k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7746
690k
      default:
7747
690k
    return(NULL);
7748
1.15M
  }
7749
0
  return(NULL);
7750
1.15M
    }
7751
    /*
7752
    * Get the next sibling element node.
7753
    */
7754
425k
    switch (cur->type) {
7755
425k
  case XML_ELEMENT_NODE:
7756
425k
  case XML_TEXT_NODE:
7757
425k
  case XML_ENTITY_REF_NODE:
7758
425k
  case XML_ENTITY_NODE:
7759
425k
  case XML_CDATA_SECTION_NODE:
7760
425k
  case XML_PI_NODE:
7761
425k
  case XML_COMMENT_NODE:
7762
425k
  case XML_XINCLUDE_END:
7763
425k
      break;
7764
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7765
0
  default:
7766
0
      return(NULL);
7767
425k
    }
7768
425k
    if (cur->next != NULL) {
7769
371k
  if (cur->next->type == XML_ELEMENT_NODE)
7770
552
      return(cur->next);
7771
371k
  cur = cur->next;
7772
575k
  do {
7773
575k
      cur = cur->next;
7774
575k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7775
371k
  return(cur);
7776
371k
    }
7777
54.1k
    return(NULL);
7778
425k
}
7779
7780
#if 0
7781
/**
7782
 * xmlXPathNextDescendantOrSelfElemParent:
7783
 * @ctxt:  the XPath Parser context
7784
 * @cur:  the current node in the traversal
7785
 *
7786
 * Traversal function for the "descendant-or-self" axis.
7787
 * Additionally it returns only nodes which can be parents of
7788
 * element nodes.
7789
 *
7790
 *
7791
 * Returns the next element following that axis
7792
 */
7793
static xmlNodePtr
7794
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7795
               xmlNodePtr contextNode)
7796
{
7797
    if (cur == NULL) {
7798
  if (contextNode == NULL)
7799
      return(NULL);
7800
  switch (contextNode->type) {
7801
      case XML_ELEMENT_NODE:
7802
      case XML_XINCLUDE_START:
7803
      case XML_DOCUMENT_FRAG_NODE:
7804
      case XML_DOCUMENT_NODE:
7805
      case XML_HTML_DOCUMENT_NODE:
7806
    return(contextNode);
7807
      default:
7808
    return(NULL);
7809
  }
7810
  return(NULL);
7811
    } else {
7812
  xmlNodePtr start = cur;
7813
7814
  while (cur != NULL) {
7815
      switch (cur->type) {
7816
    case XML_ELEMENT_NODE:
7817
    /* TODO: OK to have XInclude here? */
7818
    case XML_XINCLUDE_START:
7819
    case XML_DOCUMENT_FRAG_NODE:
7820
        if (cur != start)
7821
      return(cur);
7822
        if (cur->children != NULL) {
7823
      cur = cur->children;
7824
      continue;
7825
        }
7826
        break;
7827
    /* Not sure if we need those here. */
7828
    case XML_DOCUMENT_NODE:
7829
    case XML_HTML_DOCUMENT_NODE:
7830
        if (cur != start)
7831
      return(cur);
7832
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7833
    default:
7834
        break;
7835
      }
7836
7837
next_sibling:
7838
      if ((cur == NULL) || (cur == contextNode))
7839
    return(NULL);
7840
      if (cur->next != NULL) {
7841
    cur = cur->next;
7842
      } else {
7843
    cur = cur->parent;
7844
    goto next_sibling;
7845
      }
7846
  }
7847
    }
7848
    return(NULL);
7849
}
7850
#endif
7851
7852
/**
7853
 * xmlXPathNextDescendant:
7854
 * @ctxt:  the XPath Parser context
7855
 * @cur:  the current node in the traversal
7856
 *
7857
 * Traversal function for the "descendant" direction
7858
 * the descendant axis contains the descendants of the context node in document
7859
 * order; a descendant is a child or a child of a child and so on.
7860
 *
7861
 * Returns the next element following that axis
7862
 */
7863
xmlNodePtr
7864
7.41M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865
7.41M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866
7.41M
    if (cur == NULL) {
7867
610k
  if (ctxt->context->node == NULL)
7868
0
      return(NULL);
7869
610k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870
610k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871
2.66k
      return(NULL);
7872
7873
608k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874
77.2k
      return(ctxt->context->doc->children);
7875
530k
        return(ctxt->context->node->children);
7876
608k
    }
7877
7878
6.80M
    if (cur->type == XML_NAMESPACE_DECL)
7879
0
        return(NULL);
7880
6.80M
    if (cur->children != NULL) {
7881
  /*
7882
   * Do not descend on entities declarations
7883
   */
7884
1.68M
  if (cur->children->type != XML_ENTITY_DECL) {
7885
1.68M
      cur = cur->children;
7886
      /*
7887
       * Skip DTDs
7888
       */
7889
1.68M
      if (cur->type != XML_DTD_NODE)
7890
1.68M
    return(cur);
7891
1.68M
  }
7892
1.68M
    }
7893
7894
5.11M
    if (cur == ctxt->context->node) return(NULL);
7895
7896
5.09M
    while (cur->next != NULL) {
7897
3.17M
  cur = cur->next;
7898
3.17M
  if ((cur->type != XML_ENTITY_DECL) &&
7899
3.17M
      (cur->type != XML_DTD_NODE))
7900
3.17M
      return(cur);
7901
3.17M
    }
7902
7903
2.03M
    do {
7904
2.03M
        cur = cur->parent;
7905
2.03M
  if (cur == NULL) break;
7906
2.03M
  if (cur == ctxt->context->node) return(NULL);
7907
1.39M
  if (cur->next != NULL) {
7908
1.27M
      cur = cur->next;
7909
1.27M
      return(cur);
7910
1.27M
  }
7911
1.39M
    } while (cur != NULL);
7912
0
    return(cur);
7913
1.92M
}
7914
7915
/**
7916
 * xmlXPathNextDescendantOrSelf:
7917
 * @ctxt:  the XPath Parser context
7918
 * @cur:  the current node in the traversal
7919
 *
7920
 * Traversal function for the "descendant-or-self" direction
7921
 * the descendant-or-self axis contains the context node and the descendants
7922
 * of the context node in document order; thus the context node is the first
7923
 * node on the axis, and the first child of the context node is the second node
7924
 * on the axis
7925
 *
7926
 * Returns the next element following that axis
7927
 */
7928
xmlNodePtr
7929
3.27M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930
3.27M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931
3.27M
    if (cur == NULL)
7932
374k
        return(ctxt->context->node);
7933
7934
2.90M
    if (ctxt->context->node == NULL)
7935
0
        return(NULL);
7936
2.90M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7937
2.90M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7938
71.1k
        return(NULL);
7939
7940
2.83M
    return(xmlXPathNextDescendant(ctxt, cur));
7941
2.90M
}
7942
7943
/**
7944
 * xmlXPathNextParent:
7945
 * @ctxt:  the XPath Parser context
7946
 * @cur:  the current node in the traversal
7947
 *
7948
 * Traversal function for the "parent" direction
7949
 * The parent axis contains the parent of the context node, if there is one.
7950
 *
7951
 * Returns the next element following that axis
7952
 */
7953
xmlNodePtr
7954
414k
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955
414k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7956
    /*
7957
     * the parent of an attribute or namespace node is the element
7958
     * to which the attribute or namespace node is attached
7959
     * Namespace handling !!!
7960
     */
7961
414k
    if (cur == NULL) {
7962
214k
  if (ctxt->context->node == NULL) return(NULL);
7963
214k
  switch (ctxt->context->node->type) {
7964
86.7k
            case XML_ELEMENT_NODE:
7965
180k
            case XML_TEXT_NODE:
7966
184k
            case XML_CDATA_SECTION_NODE:
7967
184k
            case XML_ENTITY_REF_NODE:
7968
184k
            case XML_ENTITY_NODE:
7969
190k
            case XML_PI_NODE:
7970
198k
            case XML_COMMENT_NODE:
7971
198k
            case XML_NOTATION_NODE:
7972
198k
            case XML_DTD_NODE:
7973
198k
      case XML_ELEMENT_DECL:
7974
198k
      case XML_ATTRIBUTE_DECL:
7975
198k
      case XML_XINCLUDE_START:
7976
198k
      case XML_XINCLUDE_END:
7977
198k
      case XML_ENTITY_DECL:
7978
198k
    if (ctxt->context->node->parent == NULL)
7979
0
        return((xmlNodePtr) ctxt->context->doc);
7980
198k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981
198k
        ((ctxt->context->node->parent->name[0] == ' ') ||
7982
190k
         (xmlStrEqual(ctxt->context->node->parent->name,
7983
190k
         BAD_CAST "fake node libxslt"))))
7984
0
        return(NULL);
7985
198k
    return(ctxt->context->node->parent);
7986
369
            case XML_ATTRIBUTE_NODE: {
7987
369
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989
369
    return(att->parent);
7990
198k
      }
7991
14.6k
            case XML_DOCUMENT_NODE:
7992
14.6k
            case XML_DOCUMENT_TYPE_NODE:
7993
14.6k
            case XML_DOCUMENT_FRAG_NODE:
7994
14.6k
            case XML_HTML_DOCUMENT_NODE:
7995
14.6k
                return(NULL);
7996
1.16k
      case XML_NAMESPACE_DECL: {
7997
1.16k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7998
7999
1.16k
    if ((ns->next != NULL) &&
8000
1.16k
        (ns->next->type != XML_NAMESPACE_DECL))
8001
1.16k
        return((xmlNodePtr) ns->next);
8002
0
                return(NULL);
8003
1.16k
      }
8004
214k
  }
8005
214k
    }
8006
199k
    return(NULL);
8007
414k
}
8008
8009
/**
8010
 * xmlXPathNextAncestor:
8011
 * @ctxt:  the XPath Parser context
8012
 * @cur:  the current node in the traversal
8013
 *
8014
 * Traversal function for the "ancestor" direction
8015
 * the ancestor axis contains the ancestors of the context node; the ancestors
8016
 * of the context node consist of the parent of context node and the parent's
8017
 * parent and so on; the nodes are ordered in reverse document order; thus the
8018
 * parent is the first node on the axis, and the parent's parent is the second
8019
 * node on the axis
8020
 *
8021
 * Returns the next element following that axis
8022
 */
8023
xmlNodePtr
8024
485k
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8025
485k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8026
    /*
8027
     * the parent of an attribute or namespace node is the element
8028
     * to which the attribute or namespace node is attached
8029
     * !!!!!!!!!!!!!
8030
     */
8031
485k
    if (cur == NULL) {
8032
171k
  if (ctxt->context->node == NULL) return(NULL);
8033
171k
  switch (ctxt->context->node->type) {
8034
49.9k
            case XML_ELEMENT_NODE:
8035
102k
            case XML_TEXT_NODE:
8036
102k
            case XML_CDATA_SECTION_NODE:
8037
102k
            case XML_ENTITY_REF_NODE:
8038
102k
            case XML_ENTITY_NODE:
8039
103k
            case XML_PI_NODE:
8040
104k
            case XML_COMMENT_NODE:
8041
104k
      case XML_DTD_NODE:
8042
104k
      case XML_ELEMENT_DECL:
8043
104k
      case XML_ATTRIBUTE_DECL:
8044
104k
      case XML_ENTITY_DECL:
8045
104k
            case XML_NOTATION_NODE:
8046
104k
      case XML_XINCLUDE_START:
8047
104k
      case XML_XINCLUDE_END:
8048
104k
    if (ctxt->context->node->parent == NULL)
8049
0
        return((xmlNodePtr) ctxt->context->doc);
8050
104k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8051
104k
        ((ctxt->context->node->parent->name[0] == ' ') ||
8052
57.9k
         (xmlStrEqual(ctxt->context->node->parent->name,
8053
57.9k
         BAD_CAST "fake node libxslt"))))
8054
0
        return(NULL);
8055
104k
    return(ctxt->context->node->parent);
8056
237
            case XML_ATTRIBUTE_NODE: {
8057
237
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8058
8059
237
    return(tmp->parent);
8060
104k
      }
8061
308
            case XML_DOCUMENT_NODE:
8062
308
            case XML_DOCUMENT_TYPE_NODE:
8063
308
            case XML_DOCUMENT_FRAG_NODE:
8064
308
            case XML_HTML_DOCUMENT_NODE:
8065
308
                return(NULL);
8066
66.9k
      case XML_NAMESPACE_DECL: {
8067
66.9k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8068
8069
66.9k
    if ((ns->next != NULL) &&
8070
66.9k
        (ns->next->type != XML_NAMESPACE_DECL))
8071
66.9k
        return((xmlNodePtr) ns->next);
8072
    /* Bad, how did that namespace end up here ? */
8073
0
                return(NULL);
8074
66.9k
      }
8075
171k
  }
8076
0
  return(NULL);
8077
171k
    }
8078
314k
    if (cur == ctxt->context->doc->children)
8079
22
  return((xmlNodePtr) ctxt->context->doc);
8080
314k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8081
15.6k
  return(NULL);
8082
298k
    switch (cur->type) {
8083
140k
  case XML_ELEMENT_NODE:
8084
140k
  case XML_TEXT_NODE:
8085
140k
  case XML_CDATA_SECTION_NODE:
8086
140k
  case XML_ENTITY_REF_NODE:
8087
140k
  case XML_ENTITY_NODE:
8088
140k
  case XML_PI_NODE:
8089
141k
  case XML_COMMENT_NODE:
8090
141k
  case XML_NOTATION_NODE:
8091
141k
  case XML_DTD_NODE:
8092
141k
        case XML_ELEMENT_DECL:
8093
141k
        case XML_ATTRIBUTE_DECL:
8094
141k
        case XML_ENTITY_DECL:
8095
141k
  case XML_XINCLUDE_START:
8096
141k
  case XML_XINCLUDE_END:
8097
141k
      if (cur->parent == NULL)
8098
0
    return(NULL);
8099
141k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8100
141k
    ((cur->parent->name[0] == ' ') ||
8101
14.2k
     (xmlStrEqual(cur->parent->name,
8102
14.2k
            BAD_CAST "fake node libxslt"))))
8103
0
    return(NULL);
8104
141k
      return(cur->parent);
8105
9
  case XML_ATTRIBUTE_NODE: {
8106
9
      xmlAttrPtr att = (xmlAttrPtr) cur;
8107
8108
9
      return(att->parent);
8109
141k
  }
8110
21
  case XML_NAMESPACE_DECL: {
8111
21
      xmlNsPtr ns = (xmlNsPtr) cur;
8112
8113
21
      if ((ns->next != NULL) &&
8114
21
          (ns->next->type != XML_NAMESPACE_DECL))
8115
21
          return((xmlNodePtr) ns->next);
8116
      /* Bad, how did that namespace end up here ? */
8117
0
            return(NULL);
8118
21
  }
8119
157k
  case XML_DOCUMENT_NODE:
8120
157k
  case XML_DOCUMENT_TYPE_NODE:
8121
157k
  case XML_DOCUMENT_FRAG_NODE:
8122
157k
  case XML_HTML_DOCUMENT_NODE:
8123
157k
      return(NULL);
8124
298k
    }
8125
0
    return(NULL);
8126
298k
}
8127
8128
/**
8129
 * xmlXPathNextAncestorOrSelf:
8130
 * @ctxt:  the XPath Parser context
8131
 * @cur:  the current node in the traversal
8132
 *
8133
 * Traversal function for the "ancestor-or-self" direction
8134
 * he ancestor-or-self axis contains the context node and ancestors of
8135
 * the context node in reverse document order; thus the context node is
8136
 * the first node on the axis, and the context node's parent the second;
8137
 * parent here is defined the same as with the parent axis.
8138
 *
8139
 * Returns the next element following that axis
8140
 */
8141
xmlNodePtr
8142
8.21k
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8143
8.21k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8144
8.21k
    if (cur == NULL)
8145
1.80k
        return(ctxt->context->node);
8146
6.40k
    return(xmlXPathNextAncestor(ctxt, cur));
8147
8.21k
}
8148
8149
/**
8150
 * xmlXPathNextFollowingSibling:
8151
 * @ctxt:  the XPath Parser context
8152
 * @cur:  the current node in the traversal
8153
 *
8154
 * Traversal function for the "following-sibling" direction
8155
 * The following-sibling axis contains the following siblings of the context
8156
 * node in document order.
8157
 *
8158
 * Returns the next element following that axis
8159
 */
8160
xmlNodePtr
8161
53.5k
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8162
53.5k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163
53.5k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8164
53.5k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8165
49
  return(NULL);
8166
53.5k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8167
0
        return(NULL);
8168
53.5k
    if (cur == NULL)
8169
8.68k
        return(ctxt->context->node->next);
8170
44.8k
    return(cur->next);
8171
53.5k
}
8172
8173
/**
8174
 * xmlXPathNextPrecedingSibling:
8175
 * @ctxt:  the XPath Parser context
8176
 * @cur:  the current node in the traversal
8177
 *
8178
 * Traversal function for the "preceding-sibling" direction
8179
 * The preceding-sibling axis contains the preceding siblings of the context
8180
 * node in reverse document order; the first preceding sibling is first on the
8181
 * axis; the sibling preceding that node is the second on the axis and so on.
8182
 *
8183
 * Returns the next element following that axis
8184
 */
8185
xmlNodePtr
8186
111k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8187
111k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8188
111k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8189
111k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8190
60
  return(NULL);
8191
111k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8192
0
        return(NULL);
8193
111k
    if (cur == NULL)
8194
3.11k
        return(ctxt->context->node->prev);
8195
108k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8196
0
  cur = cur->prev;
8197
0
  if (cur == NULL)
8198
0
      return(ctxt->context->node->prev);
8199
0
    }
8200
108k
    return(cur->prev);
8201
108k
}
8202
8203
/**
8204
 * xmlXPathNextFollowing:
8205
 * @ctxt:  the XPath Parser context
8206
 * @cur:  the current node in the traversal
8207
 *
8208
 * Traversal function for the "following" direction
8209
 * The following axis contains all nodes in the same document as the context
8210
 * node that are after the context node in document order, excluding any
8211
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8212
 * are ordered in document order
8213
 *
8214
 * Returns the next element following that axis
8215
 */
8216
xmlNodePtr
8217
7.56M
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8218
7.56M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219
7.56M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8220
7.56M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8221
3.67M
        return(cur->children);
8222
8223
3.88M
    if (cur == NULL) {
8224
23.0k
        cur = ctxt->context->node;
8225
23.0k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8226
15
            cur = cur->parent;
8227
23.0k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8228
1.45k
            xmlNsPtr ns = (xmlNsPtr) cur;
8229
8230
1.45k
            if ((ns->next == NULL) ||
8231
1.45k
                (ns->next->type == XML_NAMESPACE_DECL))
8232
0
                return (NULL);
8233
1.45k
            cur = (xmlNodePtr) ns->next;
8234
1.45k
        }
8235
23.0k
    }
8236
3.88M
    if (cur == NULL) return(NULL) ; /* ERROR */
8237
3.88M
    if (cur->next != NULL) return(cur->next) ;
8238
3.73M
    do {
8239
3.73M
        cur = cur->parent;
8240
3.73M
        if (cur == NULL) break;
8241
3.73M
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8242
3.71M
        if (cur->next != NULL) return(cur->next);
8243
3.71M
    } while (cur != NULL);
8244
7.58k
    return(cur);
8245
3.71M
}
8246
8247
/*
8248
 * xmlXPathIsAncestor:
8249
 * @ancestor:  the ancestor node
8250
 * @node:  the current node
8251
 *
8252
 * Check that @ancestor is a @node's ancestor
8253
 *
8254
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8255
 */
8256
static int
8257
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8258
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8259
0
    if (node->type == XML_NAMESPACE_DECL)
8260
0
        return(0);
8261
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8262
0
        return(0);
8263
    /* nodes need to be in the same document */
8264
0
    if (ancestor->doc != node->doc) return(0);
8265
    /* avoid searching if ancestor or node is the root node */
8266
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8267
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8268
0
    while (node->parent != NULL) {
8269
0
        if (node->parent == ancestor)
8270
0
            return(1);
8271
0
  node = node->parent;
8272
0
    }
8273
0
    return(0);
8274
0
}
8275
8276
/**
8277
 * xmlXPathNextPreceding:
8278
 * @ctxt:  the XPath Parser context
8279
 * @cur:  the current node in the traversal
8280
 *
8281
 * Traversal function for the "preceding" direction
8282
 * the preceding axis contains all nodes in the same document as the context
8283
 * node that are before the context node in document order, excluding any
8284
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8285
 * ordered in reverse document order
8286
 *
8287
 * Returns the next element following that axis
8288
 */
8289
xmlNodePtr
8290
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8291
0
{
8292
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8293
0
    if (cur == NULL) {
8294
0
        cur = ctxt->context->node;
8295
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8296
0
            cur = cur->parent;
8297
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8298
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8299
8300
0
            if ((ns->next == NULL) ||
8301
0
                (ns->next->type == XML_NAMESPACE_DECL))
8302
0
                return (NULL);
8303
0
            cur = (xmlNodePtr) ns->next;
8304
0
        }
8305
0
    }
8306
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8307
0
  return (NULL);
8308
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8309
0
  cur = cur->prev;
8310
0
    do {
8311
0
        if (cur->prev != NULL) {
8312
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8313
0
            return (cur);
8314
0
        }
8315
8316
0
        cur = cur->parent;
8317
0
        if (cur == NULL)
8318
0
            return (NULL);
8319
0
        if (cur == ctxt->context->doc->children)
8320
0
            return (NULL);
8321
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8322
0
    return (cur);
8323
0
}
8324
8325
/**
8326
 * xmlXPathNextPrecedingInternal:
8327
 * @ctxt:  the XPath Parser context
8328
 * @cur:  the current node in the traversal
8329
 *
8330
 * Traversal function for the "preceding" direction
8331
 * the preceding axis contains all nodes in the same document as the context
8332
 * node that are before the context node in document order, excluding any
8333
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8334
 * ordered in reverse document order
8335
 * This is a faster implementation but internal only since it requires a
8336
 * state kept in the parser context: ctxt->ancestor.
8337
 *
8338
 * Returns the next element following that axis
8339
 */
8340
static xmlNodePtr
8341
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8342
                              xmlNodePtr cur)
8343
5.97M
{
8344
5.97M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8345
5.97M
    if (cur == NULL) {
8346
26.1k
        cur = ctxt->context->node;
8347
26.1k
        if (cur == NULL)
8348
0
            return (NULL);
8349
26.1k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8350
876
            cur = cur->parent;
8351
25.3k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8352
117
            xmlNsPtr ns = (xmlNsPtr) cur;
8353
8354
117
            if ((ns->next == NULL) ||
8355
117
                (ns->next->type == XML_NAMESPACE_DECL))
8356
0
                return (NULL);
8357
117
            cur = (xmlNodePtr) ns->next;
8358
117
        }
8359
26.1k
        ctxt->ancestor = cur->parent;
8360
26.1k
    }
8361
5.97M
    if (cur->type == XML_NAMESPACE_DECL)
8362
0
        return(NULL);
8363
5.97M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8364
0
  cur = cur->prev;
8365
6.02M
    while (cur->prev == NULL) {
8366
3.02M
        cur = cur->parent;
8367
3.02M
        if (cur == NULL)
8368
26.1k
            return (NULL);
8369
2.99M
        if (cur == ctxt->context->doc->children)
8370
0
            return (NULL);
8371
2.99M
        if (cur != ctxt->ancestor)
8372
2.94M
            return (cur);
8373
51.5k
        ctxt->ancestor = cur->parent;
8374
51.5k
    }
8375
3.00M
    cur = cur->prev;
8376
5.94M
    while (cur->last != NULL)
8377
2.94M
        cur = cur->last;
8378
3.00M
    return (cur);
8379
5.97M
}
8380
8381
/**
8382
 * xmlXPathNextNamespace:
8383
 * @ctxt:  the XPath Parser context
8384
 * @cur:  the current attribute in the traversal
8385
 *
8386
 * Traversal function for the "namespace" direction
8387
 * the namespace axis contains the namespace nodes of the context node;
8388
 * the order of nodes on this axis is implementation-defined; the axis will
8389
 * be empty unless the context node is an element
8390
 *
8391
 * We keep the XML namespace node at the end of the list.
8392
 *
8393
 * Returns the next element following that axis
8394
 */
8395
xmlNodePtr
8396
526k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8397
526k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8398
526k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8399
350k
    if (cur == NULL) {
8400
155k
        if (ctxt->context->tmpNsList != NULL)
8401
865
      xmlFree(ctxt->context->tmpNsList);
8402
155k
  ctxt->context->tmpNsList =
8403
155k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8404
155k
  ctxt->context->tmpNsNr = 0;
8405
155k
  if (ctxt->context->tmpNsList != NULL) {
8406
66.8k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8407
42.5k
    ctxt->context->tmpNsNr++;
8408
42.5k
      }
8409
24.2k
  }
8410
155k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8411
155k
    }
8412
195k
    if (ctxt->context->tmpNsNr > 0) {
8413
40.9k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8414
154k
    } else {
8415
154k
  if (ctxt->context->tmpNsList != NULL)
8416
23.3k
      xmlFree(ctxt->context->tmpNsList);
8417
154k
  ctxt->context->tmpNsList = NULL;
8418
154k
  return(NULL);
8419
154k
    }
8420
195k
}
8421
8422
/**
8423
 * xmlXPathNextAttribute:
8424
 * @ctxt:  the XPath Parser context
8425
 * @cur:  the current attribute in the traversal
8426
 *
8427
 * Traversal function for the "attribute" direction
8428
 * TODO: support DTD inherited default attributes
8429
 *
8430
 * Returns the next element following that axis
8431
 */
8432
xmlNodePtr
8433
674k
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8434
674k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8435
674k
    if (ctxt->context->node == NULL)
8436
0
  return(NULL);
8437
674k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8438
400k
  return(NULL);
8439
274k
    if (cur == NULL) {
8440
176k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8441
0
      return(NULL);
8442
176k
        return((xmlNodePtr)ctxt->context->node->properties);
8443
176k
    }
8444
97.8k
    return((xmlNodePtr)cur->next);
8445
274k
}
8446
8447
/************************************************************************
8448
 *                  *
8449
 *    NodeTest Functions          *
8450
 *                  *
8451
 ************************************************************************/
8452
8453
#define IS_FUNCTION     200
8454
8455
8456
/************************************************************************
8457
 *                  *
8458
 *    Implicit tree core function library     *
8459
 *                  *
8460
 ************************************************************************/
8461
8462
/**
8463
 * xmlXPathRoot:
8464
 * @ctxt:  the XPath Parser context
8465
 *
8466
 * Initialize the context to the root of the document
8467
 */
8468
void
8469
174k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8470
174k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8471
0
  return;
8472
174k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8473
174k
  (xmlNodePtr) ctxt->context->doc));
8474
174k
}
8475
8476
/************************************************************************
8477
 *                  *
8478
 *    The explicit core function library      *
8479
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8480
 *                  *
8481
 ************************************************************************/
8482
8483
8484
/**
8485
 * xmlXPathLastFunction:
8486
 * @ctxt:  the XPath Parser context
8487
 * @nargs:  the number of arguments
8488
 *
8489
 * Implement the last() XPath function
8490
 *    number last()
8491
 * The last function returns the number of nodes in the context node list.
8492
 */
8493
void
8494
4.60k
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8495
13.8k
    CHECK_ARITY(0);
8496
13.8k
    if (ctxt->context->contextSize >= 0) {
8497
4.60k
  valuePush(ctxt,
8498
4.60k
      xmlXPathCacheNewFloat(ctxt->context,
8499
4.60k
    (double) ctxt->context->contextSize));
8500
#ifdef DEBUG_EXPR
8501
  xmlGenericError(xmlGenericErrorContext,
8502
    "last() : %d\n", ctxt->context->contextSize);
8503
#endif
8504
4.60k
    } else {
8505
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8506
0
    }
8507
13.8k
}
8508
8509
/**
8510
 * xmlXPathPositionFunction:
8511
 * @ctxt:  the XPath Parser context
8512
 * @nargs:  the number of arguments
8513
 *
8514
 * Implement the position() XPath function
8515
 *    number position()
8516
 * The position function returns the position of the context node in the
8517
 * context node list. The first position is 1, and so the last position
8518
 * will be equal to last().
8519
 */
8520
void
8521
5
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522
15
    CHECK_ARITY(0);
8523
15
    if (ctxt->context->proximityPosition >= 0) {
8524
5
  valuePush(ctxt,
8525
5
        xmlXPathCacheNewFloat(ctxt->context,
8526
5
    (double) ctxt->context->proximityPosition));
8527
#ifdef DEBUG_EXPR
8528
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8529
    ctxt->context->proximityPosition);
8530
#endif
8531
5
    } else {
8532
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8533
0
    }
8534
15
}
8535
8536
/**
8537
 * xmlXPathCountFunction:
8538
 * @ctxt:  the XPath Parser context
8539
 * @nargs:  the number of arguments
8540
 *
8541
 * Implement the count() XPath function
8542
 *    number count(node-set)
8543
 */
8544
void
8545
4
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546
4
    xmlXPathObjectPtr cur;
8547
8548
8
    CHECK_ARITY(1);
8549
8
    if ((ctxt->value == NULL) ||
8550
2
  ((ctxt->value->type != XPATH_NODESET) &&
8551
2
   (ctxt->value->type != XPATH_XSLT_TREE)))
8552
2
  XP_ERROR(XPATH_INVALID_TYPE);
8553
2
    cur = valuePop(ctxt);
8554
8555
2
    if ((cur == NULL) || (cur->nodesetval == NULL))
8556
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8557
2
    else
8558
2
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8559
2
      (double) cur->nodesetval->nodeNr));
8560
2
    xmlXPathReleaseObject(ctxt->context, cur);
8561
2
}
8562
8563
/**
8564
 * xmlXPathGetElementsByIds:
8565
 * @doc:  the document
8566
 * @ids:  a whitespace separated list of IDs
8567
 *
8568
 * Selects elements by their unique ID.
8569
 *
8570
 * Returns a node-set of selected elements.
8571
 */
8572
static xmlNodeSetPtr
8573
812
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8574
812
    xmlNodeSetPtr ret;
8575
812
    const xmlChar *cur = ids;
8576
812
    xmlChar *ID;
8577
812
    xmlAttrPtr attr;
8578
812
    xmlNodePtr elem = NULL;
8579
8580
812
    if (ids == NULL) return(NULL);
8581
8582
812
    ret = xmlXPathNodeSetCreate(NULL);
8583
812
    if (ret == NULL)
8584
0
        return(ret);
8585
8586
2.59k
    while (IS_BLANK_CH(*cur)) cur++;
8587
2.34k
    while (*cur != 0) {
8588
46.2k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8589
44.7k
      cur++;
8590
8591
1.52k
        ID = xmlStrndup(ids, cur - ids);
8592
1.52k
  if (ID != NULL) {
8593
      /*
8594
       * We used to check the fact that the value passed
8595
       * was an NCName, but this generated much troubles for
8596
       * me and Aleksey Sanin, people blatantly violated that
8597
       * constraint, like Visa3D spec.
8598
       * if (xmlValidateNCName(ID, 1) == 0)
8599
       */
8600
1.52k
      attr = xmlGetID(doc, ID);
8601
1.52k
      if (attr != NULL) {
8602
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8603
0
        elem = attr->parent;
8604
0
    else if (attr->type == XML_ELEMENT_NODE)
8605
0
        elem = (xmlNodePtr) attr;
8606
0
    else
8607
0
        elem = NULL;
8608
                /* TODO: Check memory error. */
8609
0
    if (elem != NULL)
8610
0
        xmlXPathNodeSetAdd(ret, elem);
8611
0
      }
8612
1.52k
      xmlFree(ID);
8613
1.52k
  }
8614
8615
10.1k
  while (IS_BLANK_CH(*cur)) cur++;
8616
1.52k
  ids = cur;
8617
1.52k
    }
8618
812
    return(ret);
8619
812
}
8620
8621
/**
8622
 * xmlXPathIdFunction:
8623
 * @ctxt:  the XPath Parser context
8624
 * @nargs:  the number of arguments
8625
 *
8626
 * Implement the id() XPath function
8627
 *    node-set id(object)
8628
 * The id function selects elements by their unique ID
8629
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8630
 * then the result is the union of the result of applying id to the
8631
 * string value of each of the nodes in the argument node-set. When the
8632
 * argument to id is of any other type, the argument is converted to a
8633
 * string as if by a call to the string function; the string is split
8634
 * into a whitespace-separated list of tokens (whitespace is any sequence
8635
 * of characters matching the production S); the result is a node-set
8636
 * containing the elements in the same document as the context node that
8637
 * have a unique ID equal to any of the tokens in the list.
8638
 */
8639
void
8640
633
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8641
633
    xmlChar *tokens;
8642
633
    xmlNodeSetPtr ret;
8643
633
    xmlXPathObjectPtr obj;
8644
8645
1.89k
    CHECK_ARITY(1);
8646
1.89k
    obj = valuePop(ctxt);
8647
1.89k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8648
631
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8649
53
  xmlNodeSetPtr ns;
8650
53
  int i;
8651
8652
        /* TODO: Check memory error. */
8653
53
  ret = xmlXPathNodeSetCreate(NULL);
8654
8655
53
  if (obj->nodesetval != NULL) {
8656
285
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8657
234
    tokens =
8658
234
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8659
234
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8660
                /* TODO: Check memory error. */
8661
234
    ret = xmlXPathNodeSetMerge(ret, ns);
8662
234
    xmlXPathFreeNodeSet(ns);
8663
234
    if (tokens != NULL)
8664
234
        xmlFree(tokens);
8665
234
      }
8666
51
  }
8667
53
  xmlXPathReleaseObject(ctxt->context, obj);
8668
53
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8669
53
  return;
8670
53
    }
8671
578
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8672
578
    if (obj == NULL) return;
8673
578
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8674
578
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8675
578
    xmlXPathReleaseObject(ctxt->context, obj);
8676
578
    return;
8677
578
}
8678
8679
/**
8680
 * xmlXPathLocalNameFunction:
8681
 * @ctxt:  the XPath Parser context
8682
 * @nargs:  the number of arguments
8683
 *
8684
 * Implement the local-name() XPath function
8685
 *    string local-name(node-set?)
8686
 * The local-name function returns a string containing the local part
8687
 * of the name of the node in the argument node-set that is first in
8688
 * document order. If the node-set is empty or the first node has no
8689
 * name, an empty string is returned. If the argument is omitted it
8690
 * defaults to the context node.
8691
 */
8692
void
8693
42
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8694
42
    xmlXPathObjectPtr cur;
8695
8696
42
    if (ctxt == NULL) return;
8697
8698
42
    if (nargs == 0) {
8699
2
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8700
2
      ctxt->context->node));
8701
2
  nargs = 1;
8702
2
    }
8703
8704
124
    CHECK_ARITY(1);
8705
124
    if ((ctxt->value == NULL) ||
8706
41
  ((ctxt->value->type != XPATH_NODESET) &&
8707
41
   (ctxt->value->type != XPATH_XSLT_TREE)))
8708
40
  XP_ERROR(XPATH_INVALID_TYPE);
8709
40
    cur = valuePop(ctxt);
8710
8711
40
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8712
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
40
    } else {
8714
40
  int i = 0; /* Should be first in document order !!!!! */
8715
40
  switch (cur->nodesetval->nodeTab[i]->type) {
8716
0
  case XML_ELEMENT_NODE:
8717
0
  case XML_ATTRIBUTE_NODE:
8718
0
  case XML_PI_NODE:
8719
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8720
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8721
0
      else
8722
0
    valuePush(ctxt,
8723
0
          xmlXPathCacheNewString(ctxt->context,
8724
0
      cur->nodesetval->nodeTab[i]->name));
8725
0
      break;
8726
0
  case XML_NAMESPACE_DECL:
8727
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8728
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8729
0
      break;
8730
40
  default:
8731
40
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8732
40
  }
8733
40
    }
8734
40
    xmlXPathReleaseObject(ctxt->context, cur);
8735
40
}
8736
8737
/**
8738
 * xmlXPathNamespaceURIFunction:
8739
 * @ctxt:  the XPath Parser context
8740
 * @nargs:  the number of arguments
8741
 *
8742
 * Implement the namespace-uri() XPath function
8743
 *    string namespace-uri(node-set?)
8744
 * The namespace-uri function returns a string containing the
8745
 * namespace URI of the expanded name of the node in the argument
8746
 * node-set that is first in document order. If the node-set is empty,
8747
 * the first node has no name, or the expanded name has no namespace
8748
 * URI, an empty string is returned. If the argument is omitted it
8749
 * defaults to the context node.
8750
 */
8751
void
8752
6
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8753
6
    xmlXPathObjectPtr cur;
8754
8755
6
    if (ctxt == NULL) return;
8756
8757
6
    if (nargs == 0) {
8758
1
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8759
1
      ctxt->context->node));
8760
1
  nargs = 1;
8761
1
    }
8762
16
    CHECK_ARITY(1);
8763
16
    if ((ctxt->value == NULL) ||
8764
5
  ((ctxt->value->type != XPATH_NODESET) &&
8765
5
   (ctxt->value->type != XPATH_XSLT_TREE)))
8766
4
  XP_ERROR(XPATH_INVALID_TYPE);
8767
4
    cur = valuePop(ctxt);
8768
8769
4
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8770
1
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8771
3
    } else {
8772
3
  int i = 0; /* Should be first in document order !!!!! */
8773
3
  switch (cur->nodesetval->nodeTab[i]->type) {
8774
0
  case XML_ELEMENT_NODE:
8775
0
  case XML_ATTRIBUTE_NODE:
8776
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8777
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8778
0
      else
8779
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8780
0
        cur->nodesetval->nodeTab[i]->ns->href));
8781
0
      break;
8782
3
  default:
8783
3
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784
3
  }
8785
3
    }
8786
4
    xmlXPathReleaseObject(ctxt->context, cur);
8787
4
}
8788
8789
/**
8790
 * xmlXPathNameFunction:
8791
 * @ctxt:  the XPath Parser context
8792
 * @nargs:  the number of arguments
8793
 *
8794
 * Implement the name() XPath function
8795
 *    string name(node-set?)
8796
 * The name function returns a string containing a QName representing
8797
 * the name of the node in the argument node-set that is first in document
8798
 * order. The QName must represent the name with respect to the namespace
8799
 * declarations in effect on the node whose name is being represented.
8800
 * Typically, this will be the form in which the name occurred in the XML
8801
 * source. This need not be the case if there are namespace declarations
8802
 * in effect on the node that associate multiple prefixes with the same
8803
 * namespace. However, an implementation may include information about
8804
 * the original prefix in its representation of nodes; in this case, an
8805
 * implementation can ensure that the returned string is always the same
8806
 * as the QName used in the XML source. If the argument it omitted it
8807
 * defaults to the context node.
8808
 * Libxml keep the original prefix so the "real qualified name" used is
8809
 * returned.
8810
 */
8811
static void
8812
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8813
330
{
8814
330
    xmlXPathObjectPtr cur;
8815
8816
330
    if (nargs == 0) {
8817
72
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8818
72
      ctxt->context->node));
8819
72
        nargs = 1;
8820
72
    }
8821
8822
986
    CHECK_ARITY(1);
8823
986
    if ((ctxt->value == NULL) ||
8824
328
        ((ctxt->value->type != XPATH_NODESET) &&
8825
328
         (ctxt->value->type != XPATH_XSLT_TREE)))
8826
324
        XP_ERROR(XPATH_INVALID_TYPE);
8827
324
    cur = valuePop(ctxt);
8828
8829
324
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8830
224
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8831
224
    } else {
8832
100
        int i = 0;              /* Should be first in document order !!!!! */
8833
8834
100
        switch (cur->nodesetval->nodeTab[i]->type) {
8835
64
            case XML_ELEMENT_NODE:
8836
64
            case XML_ATTRIBUTE_NODE:
8837
64
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8838
0
        valuePush(ctxt,
8839
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8840
64
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8841
64
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8842
26
        valuePush(ctxt,
8843
26
            xmlXPathCacheNewString(ctxt->context,
8844
26
          cur->nodesetval->nodeTab[i]->name));
8845
38
    } else {
8846
38
        xmlChar *fullname;
8847
8848
38
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8849
38
             cur->nodesetval->nodeTab[i]->ns->prefix,
8850
38
             NULL, 0);
8851
38
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8852
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8853
38
        if (fullname == NULL) {
8854
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8855
0
        }
8856
38
        valuePush(ctxt, xmlXPathCacheWrapString(
8857
38
      ctxt->context, fullname));
8858
38
                }
8859
64
                break;
8860
64
            default:
8861
36
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8862
36
        cur->nodesetval->nodeTab[i]));
8863
36
                xmlXPathLocalNameFunction(ctxt, 1);
8864
100
        }
8865
100
    }
8866
324
    xmlXPathReleaseObject(ctxt->context, cur);
8867
324
}
8868
8869
8870
/**
8871
 * xmlXPathStringFunction:
8872
 * @ctxt:  the XPath Parser context
8873
 * @nargs:  the number of arguments
8874
 *
8875
 * Implement the string() XPath function
8876
 *    string string(object?)
8877
 * The string function converts an object to a string as follows:
8878
 *    - A node-set is converted to a string by returning the value of
8879
 *      the node in the node-set that is first in document order.
8880
 *      If the node-set is empty, an empty string is returned.
8881
 *    - A number is converted to a string as follows
8882
 *      + NaN is converted to the string NaN
8883
 *      + positive zero is converted to the string 0
8884
 *      + negative zero is converted to the string 0
8885
 *      + positive infinity is converted to the string Infinity
8886
 *      + negative infinity is converted to the string -Infinity
8887
 *      + if the number is an integer, the number is represented in
8888
 *        decimal form as a Number with no decimal point and no leading
8889
 *        zeros, preceded by a minus sign (-) if the number is negative
8890
 *      + otherwise, the number is represented in decimal form as a
8891
 *        Number including a decimal point with at least one digit
8892
 *        before the decimal point and at least one digit after the
8893
 *        decimal point, preceded by a minus sign (-) if the number
8894
 *        is negative; there must be no leading zeros before the decimal
8895
 *        point apart possibly from the one required digit immediately
8896
 *        before the decimal point; beyond the one required digit
8897
 *        after the decimal point there must be as many, but only as
8898
 *        many, more digits as are needed to uniquely distinguish the
8899
 *        number from all other IEEE 754 numeric values.
8900
 *    - The boolean false value is converted to the string false.
8901
 *      The boolean true value is converted to the string true.
8902
 *
8903
 * If the argument is omitted, it defaults to a node-set with the
8904
 * context node as its only member.
8905
 */
8906
void
8907
1.79M
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908
1.79M
    xmlXPathObjectPtr cur;
8909
8910
1.79M
    if (ctxt == NULL) return;
8911
1.79M
    if (nargs == 0) {
8912
2
    valuePush(ctxt,
8913
2
  xmlXPathCacheWrapString(ctxt->context,
8914
2
      xmlXPathCastNodeToString(ctxt->context->node)));
8915
2
  return;
8916
2
    }
8917
8918
7.19M
    CHECK_ARITY(1);
8919
7.19M
    cur = valuePop(ctxt);
8920
7.19M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8921
1.79M
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8922
1.79M
}
8923
8924
/**
8925
 * xmlXPathStringLengthFunction:
8926
 * @ctxt:  the XPath Parser context
8927
 * @nargs:  the number of arguments
8928
 *
8929
 * Implement the string-length() XPath function
8930
 *    number string-length(string?)
8931
 * The string-length returns the number of characters in the string
8932
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8933
 * the context node converted to a string, in other words the value
8934
 * of the context node.
8935
 */
8936
void
8937
2
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8938
2
    xmlXPathObjectPtr cur;
8939
8940
2
    if (nargs == 0) {
8941
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8942
0
      return;
8943
0
  if (ctxt->context->node == NULL) {
8944
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8945
0
  } else {
8946
0
      xmlChar *content;
8947
8948
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8949
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8950
0
    xmlUTF8Strlen(content)));
8951
0
      xmlFree(content);
8952
0
  }
8953
0
  return;
8954
0
    }
8955
8
    CHECK_ARITY(1);
8956
8
    CAST_TO_STRING;
8957
8
    CHECK_TYPE(XPATH_STRING);
8958
2
    cur = valuePop(ctxt);
8959
2
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960
2
  xmlUTF8Strlen(cur->stringval)));
8961
2
    xmlXPathReleaseObject(ctxt->context, cur);
8962
2
}
8963
8964
/**
8965
 * xmlXPathConcatFunction:
8966
 * @ctxt:  the XPath Parser context
8967
 * @nargs:  the number of arguments
8968
 *
8969
 * Implement the concat() XPath function
8970
 *    string concat(string, string, string*)
8971
 * The concat function returns the concatenation of its arguments.
8972
 */
8973
void
8974
19
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975
19
    xmlXPathObjectPtr cur, newobj;
8976
19
    xmlChar *tmp;
8977
8978
19
    if (ctxt == NULL) return;
8979
19
    if (nargs < 2) {
8980
2
  CHECK_ARITY(2);
8981
2
    }
8982
8983
17
    CAST_TO_STRING;
8984
17
    cur = valuePop(ctxt);
8985
17
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8986
0
  xmlXPathReleaseObject(ctxt->context, cur);
8987
0
  return;
8988
0
    }
8989
17
    nargs--;
8990
8991
63
    while (nargs > 0) {
8992
46
  CAST_TO_STRING;
8993
46
  newobj = valuePop(ctxt);
8994
46
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8995
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8996
0
      xmlXPathReleaseObject(ctxt->context, cur);
8997
0
      XP_ERROR(XPATH_INVALID_TYPE);
8998
0
  }
8999
46
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
9000
46
  newobj->stringval = cur->stringval;
9001
46
  cur->stringval = tmp;
9002
46
  xmlXPathReleaseObject(ctxt->context, newobj);
9003
46
  nargs--;
9004
46
    }
9005
17
    valuePush(ctxt, cur);
9006
17
}
9007
9008
/**
9009
 * xmlXPathContainsFunction:
9010
 * @ctxt:  the XPath Parser context
9011
 * @nargs:  the number of arguments
9012
 *
9013
 * Implement the contains() XPath function
9014
 *    boolean contains(string, string)
9015
 * The contains function returns true if the first argument string
9016
 * contains the second argument string, and otherwise returns false.
9017
 */
9018
void
9019
7
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
7
    xmlXPathObjectPtr hay, needle;
9021
9022
17
    CHECK_ARITY(2);
9023
17
    CAST_TO_STRING;
9024
17
    CHECK_TYPE(XPATH_STRING);
9025
5
    needle = valuePop(ctxt);
9026
5
    CAST_TO_STRING;
9027
5
    hay = valuePop(ctxt);
9028
9029
5
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9030
0
  xmlXPathReleaseObject(ctxt->context, hay);
9031
0
  xmlXPathReleaseObject(ctxt->context, needle);
9032
0
  XP_ERROR(XPATH_INVALID_TYPE);
9033
0
    }
9034
5
    if (xmlStrstr(hay->stringval, needle->stringval))
9035
2
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9036
3
    else
9037
3
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
5
    xmlXPathReleaseObject(ctxt->context, hay);
9039
5
    xmlXPathReleaseObject(ctxt->context, needle);
9040
5
}
9041
9042
/**
9043
 * xmlXPathStartsWithFunction:
9044
 * @ctxt:  the XPath Parser context
9045
 * @nargs:  the number of arguments
9046
 *
9047
 * Implement the starts-with() XPath function
9048
 *    boolean starts-with(string, string)
9049
 * The starts-with function returns true if the first argument string
9050
 * starts with the second argument string, and otherwise returns false.
9051
 */
9052
void
9053
14
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9054
14
    xmlXPathObjectPtr hay, needle;
9055
14
    int n;
9056
9057
40
    CHECK_ARITY(2);
9058
40
    CAST_TO_STRING;
9059
40
    CHECK_TYPE(XPATH_STRING);
9060
13
    needle = valuePop(ctxt);
9061
13
    CAST_TO_STRING;
9062
13
    hay = valuePop(ctxt);
9063
9064
13
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9065
0
  xmlXPathReleaseObject(ctxt->context, hay);
9066
0
  xmlXPathReleaseObject(ctxt->context, needle);
9067
0
  XP_ERROR(XPATH_INVALID_TYPE);
9068
0
    }
9069
13
    n = xmlStrlen(needle->stringval);
9070
13
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9071
12
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9072
1
    else
9073
1
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9074
13
    xmlXPathReleaseObject(ctxt->context, hay);
9075
13
    xmlXPathReleaseObject(ctxt->context, needle);
9076
13
}
9077
9078
/**
9079
 * xmlXPathSubstringFunction:
9080
 * @ctxt:  the XPath Parser context
9081
 * @nargs:  the number of arguments
9082
 *
9083
 * Implement the substring() XPath function
9084
 *    string substring(string, number, number?)
9085
 * The substring function returns the substring of the first argument
9086
 * starting at the position specified in the second argument with
9087
 * length specified in the third argument. For example,
9088
 * substring("12345",2,3) returns "234". If the third argument is not
9089
 * specified, it returns the substring starting at the position specified
9090
 * in the second argument and continuing to the end of the string. For
9091
 * example, substring("12345",2) returns "2345".  More precisely, each
9092
 * character in the string (see [3.6 Strings]) is considered to have a
9093
 * numeric position: the position of the first character is 1, the position
9094
 * of the second character is 2 and so on. The returned substring contains
9095
 * those characters for which the position of the character is greater than
9096
 * or equal to the second argument and, if the third argument is specified,
9097
 * less than the sum of the second and third arguments; the comparisons
9098
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9099
 *  - substring("12345", 1.5, 2.6) returns "234"
9100
 *  - substring("12345", 0, 3) returns "12"
9101
 *  - substring("12345", 0 div 0, 3) returns ""
9102
 *  - substring("12345", 1, 0 div 0) returns ""
9103
 *  - substring("12345", -42, 1 div 0) returns "12345"
9104
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9105
 */
9106
void
9107
31
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9108
31
    xmlXPathObjectPtr str, start, len;
9109
31
    double le=0, in;
9110
31
    int i = 1, j = INT_MAX;
9111
9112
31
    if (nargs < 2) {
9113
2
  CHECK_ARITY(2);
9114
2
    }
9115
29
    if (nargs > 3) {
9116
2
  CHECK_ARITY(3);
9117
2
    }
9118
    /*
9119
     * take care of possible last (position) argument
9120
    */
9121
27
    if (nargs == 3) {
9122
14
  CAST_TO_NUMBER;
9123
14
  CHECK_TYPE(XPATH_NUMBER);
9124
14
  len = valuePop(ctxt);
9125
14
  le = len->floatval;
9126
14
  xmlXPathReleaseObject(ctxt->context, len);
9127
14
    }
9128
9129
27
    CAST_TO_NUMBER;
9130
27
    CHECK_TYPE(XPATH_NUMBER);
9131
27
    start = valuePop(ctxt);
9132
27
    in = start->floatval;
9133
27
    xmlXPathReleaseObject(ctxt->context, start);
9134
27
    CAST_TO_STRING;
9135
27
    CHECK_TYPE(XPATH_STRING);
9136
27
    str = valuePop(ctxt);
9137
9138
27
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9139
9
        i = INT_MAX;
9140
18
    } else if (in >= 1.0) {
9141
16
        i = (int)in;
9142
16
        if (in - floor(in) >= 0.5)
9143
0
            i += 1;
9144
16
    }
9145
9146
27
    if (nargs == 3) {
9147
14
        double rin, rle, end;
9148
9149
14
        rin = floor(in);
9150
14
        if (in - rin >= 0.5)
9151
0
            rin += 1.0;
9152
9153
14
        rle = floor(le);
9154
14
        if (le - rle >= 0.5)
9155
0
            rle += 1.0;
9156
9157
14
        end = rin + rle;
9158
14
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9159
4
            j = 1;
9160
10
        } else if (end < INT_MAX) {
9161
9
            j = (int)end;
9162
9
        }
9163
14
    }
9164
9165
27
    if (i < j) {
9166
17
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9167
17
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9168
17
  xmlFree(ret);
9169
17
    } else {
9170
10
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9171
10
    }
9172
9173
27
    xmlXPathReleaseObject(ctxt->context, str);
9174
27
}
9175
9176
/**
9177
 * xmlXPathSubstringBeforeFunction:
9178
 * @ctxt:  the XPath Parser context
9179
 * @nargs:  the number of arguments
9180
 *
9181
 * Implement the substring-before() XPath function
9182
 *    string substring-before(string, string)
9183
 * The substring-before function returns the substring of the first
9184
 * argument string that precedes the first occurrence of the second
9185
 * argument string in the first argument string, or the empty string
9186
 * if the first argument string does not contain the second argument
9187
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9188
 */
9189
void
9190
7
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9191
7
  xmlXPathObjectPtr str;
9192
7
  xmlXPathObjectPtr find;
9193
7
  xmlBufPtr target;
9194
7
  const xmlChar *point;
9195
7
  int offset;
9196
9197
17
  CHECK_ARITY(2);
9198
17
  CAST_TO_STRING;
9199
17
  find = valuePop(ctxt);
9200
17
  CAST_TO_STRING;
9201
17
  str = valuePop(ctxt);
9202
9203
17
  target = xmlBufCreate();
9204
17
  if (target) {
9205
5
    point = xmlStrstr(str->stringval, find->stringval);
9206
5
    if (point) {
9207
2
      offset = point - str->stringval;
9208
2
      xmlBufAdd(target, str->stringval, offset);
9209
2
    }
9210
5
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211
5
  xmlBufContent(target)));
9212
5
    xmlBufFree(target);
9213
5
  }
9214
17
  xmlXPathReleaseObject(ctxt->context, str);
9215
17
  xmlXPathReleaseObject(ctxt->context, find);
9216
17
}
9217
9218
/**
9219
 * xmlXPathSubstringAfterFunction:
9220
 * @ctxt:  the XPath Parser context
9221
 * @nargs:  the number of arguments
9222
 *
9223
 * Implement the substring-after() XPath function
9224
 *    string substring-after(string, string)
9225
 * The substring-after function returns the substring of the first
9226
 * argument string that follows the first occurrence of the second
9227
 * argument string in the first argument string, or the empty stringi
9228
 * if the first argument string does not contain the second argument
9229
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9230
 * and substring-after("1999/04/01","19") returns 99/04/01.
9231
 */
9232
void
9233
9
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234
9
  xmlXPathObjectPtr str;
9235
9
  xmlXPathObjectPtr find;
9236
9
  xmlBufPtr target;
9237
9
  const xmlChar *point;
9238
9
  int offset;
9239
9240
21
  CHECK_ARITY(2);
9241
21
  CAST_TO_STRING;
9242
21
  find = valuePop(ctxt);
9243
21
  CAST_TO_STRING;
9244
21
  str = valuePop(ctxt);
9245
9246
21
  target = xmlBufCreate();
9247
21
  if (target) {
9248
6
    point = xmlStrstr(str->stringval, find->stringval);
9249
6
    if (point) {
9250
3
      offset = point - str->stringval + xmlStrlen(find->stringval);
9251
3
      xmlBufAdd(target, &str->stringval[offset],
9252
3
       xmlStrlen(str->stringval) - offset);
9253
3
    }
9254
6
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9255
6
  xmlBufContent(target)));
9256
6
    xmlBufFree(target);
9257
6
  }
9258
21
  xmlXPathReleaseObject(ctxt->context, str);
9259
21
  xmlXPathReleaseObject(ctxt->context, find);
9260
21
}
9261
9262
/**
9263
 * xmlXPathNormalizeFunction:
9264
 * @ctxt:  the XPath Parser context
9265
 * @nargs:  the number of arguments
9266
 *
9267
 * Implement the normalize-space() XPath function
9268
 *    string normalize-space(string?)
9269
 * The normalize-space function returns the argument string with white
9270
 * space normalized by stripping leading and trailing whitespace
9271
 * and replacing sequences of whitespace characters by a single
9272
 * space. Whitespace characters are the same allowed by the S production
9273
 * in XML. If the argument is omitted, it defaults to the context
9274
 * node converted to a string, in other words the value of the context node.
9275
 */
9276
void
9277
65
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9278
65
    xmlChar *source, *target;
9279
65
    int blank;
9280
9281
65
    if (ctxt == NULL) return;
9282
65
    if (nargs == 0) {
9283
        /* Use current context node */
9284
1
        valuePush(ctxt,
9285
1
            xmlXPathCacheWrapString(ctxt->context,
9286
1
                xmlXPathCastNodeToString(ctxt->context->node)));
9287
1
        nargs = 1;
9288
1
    }
9289
9290
193
    CHECK_ARITY(1);
9291
193
    CAST_TO_STRING;
9292
193
    CHECK_TYPE(XPATH_STRING);
9293
64
    source = ctxt->value->stringval;
9294
64
    if (source == NULL)
9295
0
        return;
9296
64
    target = source;
9297
9298
    /* Skip leading whitespaces */
9299
64
    while (IS_BLANK_CH(*source))
9300
290
        source++;
9301
9302
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9303
64
    blank = 0;
9304
53.8k
    while (*source) {
9305
53.7k
        if (IS_BLANK_CH(*source)) {
9306
6.20k
      blank = 1;
9307
47.5k
        } else {
9308
47.5k
            if (blank) {
9309
451
                *target++ = 0x20;
9310
451
                blank = 0;
9311
451
            }
9312
47.5k
            *target++ = *source;
9313
47.5k
        }
9314
53.7k
        source++;
9315
53.7k
    }
9316
64
    *target = 0;
9317
64
}
9318
9319
/**
9320
 * xmlXPathTranslateFunction:
9321
 * @ctxt:  the XPath Parser context
9322
 * @nargs:  the number of arguments
9323
 *
9324
 * Implement the translate() XPath function
9325
 *    string translate(string, string, string)
9326
 * The translate function returns the first argument string with
9327
 * occurrences of characters in the second argument string replaced
9328
 * by the character at the corresponding position in the third argument
9329
 * string. For example, translate("bar","abc","ABC") returns the string
9330
 * BAr. If there is a character in the second argument string with no
9331
 * character at a corresponding position in the third argument string
9332
 * (because the second argument string is longer than the third argument
9333
 * string), then occurrences of that character in the first argument
9334
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9335
 * returns "AAA". If a character occurs more than once in second
9336
 * argument string, then the first occurrence determines the replacement
9337
 * character. If the third argument string is longer than the second
9338
 * argument string, then excess characters are ignored.
9339
 */
9340
void
9341
176
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342
176
    xmlXPathObjectPtr str;
9343
176
    xmlXPathObjectPtr from;
9344
176
    xmlXPathObjectPtr to;
9345
176
    xmlBufPtr target;
9346
176
    int offset, max;
9347
176
    xmlChar ch;
9348
176
    const xmlChar *point;
9349
176
    xmlChar *cptr;
9350
9351
528
    CHECK_ARITY(3);
9352
9353
528
    CAST_TO_STRING;
9354
528
    to = valuePop(ctxt);
9355
528
    CAST_TO_STRING;
9356
528
    from = valuePop(ctxt);
9357
528
    CAST_TO_STRING;
9358
528
    str = valuePop(ctxt);
9359
9360
528
    target = xmlBufCreate();
9361
528
    if (target) {
9362
176
  max = xmlUTF8Strlen(to->stringval);
9363
299k
  for (cptr = str->stringval; (ch=*cptr); ) {
9364
299k
      offset = xmlUTF8Strloc(from->stringval, cptr);
9365
299k
      if (offset >= 0) {
9366
6.67k
    if (offset < max) {
9367
4.68k
        point = xmlUTF8Strpos(to->stringval, offset);
9368
4.68k
        if (point)
9369
4.48k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9370
4.68k
    }
9371
6.67k
      } else
9372
292k
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9373
9374
      /* Step to next character in input */
9375
299k
      cptr++;
9376
299k
      if ( ch & 0x80 ) {
9377
    /* if not simple ascii, verify proper format */
9378
337
    if ( (ch & 0xc0) != 0xc0 ) {
9379
29
        xmlGenericError(xmlGenericErrorContext,
9380
29
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                    /* not asserting an XPath error is probably better */
9382
29
        break;
9383
29
    }
9384
    /* then skip over remaining bytes for this char */
9385
809
    while ( (ch <<= 1) & 0x80 )
9386
510
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9387
9
      xmlGenericError(xmlGenericErrorContext,
9388
9
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9389
                        /* not asserting an XPath error is probably better */
9390
9
      break;
9391
9
        }
9392
308
    if (ch & 0x80) /* must have had error encountered */
9393
9
        break;
9394
308
      }
9395
299k
  }
9396
176
    }
9397
528
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9398
528
  xmlBufContent(target)));
9399
528
    xmlBufFree(target);
9400
528
    xmlXPathReleaseObject(ctxt->context, str);
9401
528
    xmlXPathReleaseObject(ctxt->context, from);
9402
528
    xmlXPathReleaseObject(ctxt->context, to);
9403
528
}
9404
9405
/**
9406
 * xmlXPathBooleanFunction:
9407
 * @ctxt:  the XPath Parser context
9408
 * @nargs:  the number of arguments
9409
 *
9410
 * Implement the boolean() XPath function
9411
 *    boolean boolean(object)
9412
 * The boolean function converts its argument to a boolean as follows:
9413
 *    - a number is true if and only if it is neither positive or
9414
 *      negative zero nor NaN
9415
 *    - a node-set is true if and only if it is non-empty
9416
 *    - a string is true if and only if its length is non-zero
9417
 */
9418
void
9419
54.6k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420
54.6k
    xmlXPathObjectPtr cur;
9421
9422
163k
    CHECK_ARITY(1);
9423
163k
    cur = valuePop(ctxt);
9424
163k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9425
54.6k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9426
54.6k
    valuePush(ctxt, cur);
9427
54.6k
}
9428
9429
/**
9430
 * xmlXPathNotFunction:
9431
 * @ctxt:  the XPath Parser context
9432
 * @nargs:  the number of arguments
9433
 *
9434
 * Implement the not() XPath function
9435
 *    boolean not(boolean)
9436
 * The not function returns true if its argument is false,
9437
 * and false otherwise.
9438
 */
9439
void
9440
5
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9441
11
    CHECK_ARITY(1);
9442
11
    CAST_TO_BOOLEAN;
9443
11
    CHECK_TYPE(XPATH_BOOLEAN);
9444
3
    ctxt->value->boolval = ! ctxt->value->boolval;
9445
3
}
9446
9447
/**
9448
 * xmlXPathTrueFunction:
9449
 * @ctxt:  the XPath Parser context
9450
 * @nargs:  the number of arguments
9451
 *
9452
 * Implement the true() XPath function
9453
 *    boolean true()
9454
 */
9455
void
9456
72
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457
206
    CHECK_ARITY(0);
9458
206
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9459
206
}
9460
9461
/**
9462
 * xmlXPathFalseFunction:
9463
 * @ctxt:  the XPath Parser context
9464
 * @nargs:  the number of arguments
9465
 *
9466
 * Implement the false() XPath function
9467
 *    boolean false()
9468
 */
9469
void
9470
13
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9471
37
    CHECK_ARITY(0);
9472
37
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9473
37
}
9474
9475
/**
9476
 * xmlXPathLangFunction:
9477
 * @ctxt:  the XPath Parser context
9478
 * @nargs:  the number of arguments
9479
 *
9480
 * Implement the lang() XPath function
9481
 *    boolean lang(string)
9482
 * The lang function returns true or false depending on whether the
9483
 * language of the context node as specified by xml:lang attributes
9484
 * is the same as or is a sublanguage of the language specified by
9485
 * the argument string. The language of the context node is determined
9486
 * by the value of the xml:lang attribute on the context node, or, if
9487
 * the context node has no xml:lang attribute, by the value of the
9488
 * xml:lang attribute on the nearest ancestor of the context node that
9489
 * has an xml:lang attribute. If there is no such attribute, then lang
9490
 * returns false. If there is such an attribute, then lang returns
9491
 * true if the attribute value is equal to the argument ignoring case,
9492
 * or if there is some suffix starting with - such that the attribute
9493
 * value is equal to the argument ignoring that suffix of the attribute
9494
 * value and ignoring case.
9495
 */
9496
void
9497
15
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498
15
    xmlXPathObjectPtr val = NULL;
9499
15
    const xmlChar *theLang = NULL;
9500
15
    const xmlChar *lang;
9501
15
    int ret = 0;
9502
15
    int i;
9503
9504
41
    CHECK_ARITY(1);
9505
41
    CAST_TO_STRING;
9506
41
    CHECK_TYPE(XPATH_STRING);
9507
13
    val = valuePop(ctxt);
9508
13
    lang = val->stringval;
9509
13
    theLang = xmlNodeGetLang(ctxt->context->node);
9510
13
    if ((theLang != NULL) && (lang != NULL)) {
9511
0
        for (i = 0;lang[i] != 0;i++)
9512
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9513
0
          goto not_equal;
9514
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9515
0
      ret = 1;
9516
0
    }
9517
13
not_equal:
9518
13
    if (theLang != NULL)
9519
0
  xmlFree((void *)theLang);
9520
9521
13
    xmlXPathReleaseObject(ctxt->context, val);
9522
13
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9523
13
}
9524
9525
/**
9526
 * xmlXPathNumberFunction:
9527
 * @ctxt:  the XPath Parser context
9528
 * @nargs:  the number of arguments
9529
 *
9530
 * Implement the number() XPath function
9531
 *    number number(object?)
9532
 */
9533
void
9534
276k
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
276k
    xmlXPathObjectPtr cur;
9536
276k
    double res;
9537
9538
276k
    if (ctxt == NULL) return;
9539
276k
    if (nargs == 0) {
9540
2
  if (ctxt->context->node == NULL) {
9541
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9542
2
  } else {
9543
2
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9544
9545
2
      res = xmlXPathStringEvalNumber(content);
9546
2
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9547
2
      xmlFree(content);
9548
2
  }
9549
2
  return;
9550
2
    }
9551
9552
1.10M
    CHECK_ARITY(1);
9553
1.10M
    cur = valuePop(ctxt);
9554
1.10M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9555
1.10M
}
9556
9557
/**
9558
 * xmlXPathSumFunction:
9559
 * @ctxt:  the XPath Parser context
9560
 * @nargs:  the number of arguments
9561
 *
9562
 * Implement the sum() XPath function
9563
 *    number sum(node-set)
9564
 * The sum function returns the sum of the values of the nodes in
9565
 * the argument node-set.
9566
 */
9567
void
9568
38
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9569
38
    xmlXPathObjectPtr cur;
9570
38
    int i;
9571
38
    double res = 0.0;
9572
9573
114
    CHECK_ARITY(1);
9574
114
    if ((ctxt->value == NULL) ||
9575
38
  ((ctxt->value->type != XPATH_NODESET) &&
9576
38
   (ctxt->value->type != XPATH_XSLT_TREE)))
9577
34
  XP_ERROR(XPATH_INVALID_TYPE);
9578
34
    cur = valuePop(ctxt);
9579
9580
34
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9581
54.3k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9582
54.3k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9583
54.3k
  }
9584
26
    }
9585
34
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9586
34
    xmlXPathReleaseObject(ctxt->context, cur);
9587
34
}
9588
9589
/**
9590
 * xmlXPathFloorFunction:
9591
 * @ctxt:  the XPath Parser context
9592
 * @nargs:  the number of arguments
9593
 *
9594
 * Implement the floor() XPath function
9595
 *    number floor(number)
9596
 * The floor function returns the largest (closest to positive infinity)
9597
 * number that is not greater than the argument and that is an integer.
9598
 */
9599
void
9600
4
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601
8
    CHECK_ARITY(1);
9602
8
    CAST_TO_NUMBER;
9603
8
    CHECK_TYPE(XPATH_NUMBER);
9604
9605
2
    ctxt->value->floatval = floor(ctxt->value->floatval);
9606
2
}
9607
9608
/**
9609
 * xmlXPathCeilingFunction:
9610
 * @ctxt:  the XPath Parser context
9611
 * @nargs:  the number of arguments
9612
 *
9613
 * Implement the ceiling() XPath function
9614
 *    number ceiling(number)
9615
 * The ceiling function returns the smallest (closest to negative infinity)
9616
 * number that is not less than the argument and that is an integer.
9617
 */
9618
void
9619
5
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9620
11
    CHECK_ARITY(1);
9621
11
    CAST_TO_NUMBER;
9622
11
    CHECK_TYPE(XPATH_NUMBER);
9623
9624
#ifdef _AIX
9625
    /* Work around buggy ceil() function on AIX */
9626
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9627
#else
9628
3
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9629
3
#endif
9630
3
}
9631
9632
/**
9633
 * xmlXPathRoundFunction:
9634
 * @ctxt:  the XPath Parser context
9635
 * @nargs:  the number of arguments
9636
 *
9637
 * Implement the round() XPath function
9638
 *    number round(number)
9639
 * The round function returns the number that is closest to the
9640
 * argument and that is an integer. If there are two such numbers,
9641
 * then the one that is closest to positive infinity is returned.
9642
 */
9643
void
9644
8
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9645
8
    double f;
9646
9647
20
    CHECK_ARITY(1);
9648
20
    CAST_TO_NUMBER;
9649
20
    CHECK_TYPE(XPATH_NUMBER);
9650
9651
6
    f = ctxt->value->floatval;
9652
9653
6
    if ((f >= -0.5) && (f < 0.5)) {
9654
        /* Handles negative zero. */
9655
2
        ctxt->value->floatval *= 0.0;
9656
2
    }
9657
4
    else {
9658
4
        double rounded = floor(f);
9659
4
        if (f - rounded >= 0.5)
9660
0
            rounded += 1.0;
9661
4
        ctxt->value->floatval = rounded;
9662
4
    }
9663
6
}
9664
9665
/************************************************************************
9666
 *                  *
9667
 *      The Parser          *
9668
 *                  *
9669
 ************************************************************************/
9670
9671
/*
9672
 * a few forward declarations since we use a recursive call based
9673
 * implementation.
9674
 */
9675
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9676
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9677
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9678
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9679
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9680
                                    int qualified);
9681
9682
/**
9683
 * xmlXPathCurrentChar:
9684
 * @ctxt:  the XPath parser context
9685
 * @cur:  pointer to the beginning of the char
9686
 * @len:  pointer to the length of the char read
9687
 *
9688
 * The current char value, if using UTF-8 this may actually span multiple
9689
 * bytes in the input buffer.
9690
 *
9691
 * Returns the current char value and its length
9692
 */
9693
9694
static int
9695
3.48M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9696
3.48M
    unsigned char c;
9697
3.48M
    unsigned int val;
9698
3.48M
    const xmlChar *cur;
9699
9700
3.48M
    if (ctxt == NULL)
9701
0
  return(0);
9702
3.48M
    cur = ctxt->cur;
9703
9704
    /*
9705
     * We are supposed to handle UTF8, check it's valid
9706
     * From rfc2044: encoding of the Unicode values on UTF-8:
9707
     *
9708
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9709
     * 0000 0000-0000 007F   0xxxxxxx
9710
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9711
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9712
     *
9713
     * Check for the 0x110000 limit too
9714
     */
9715
3.48M
    c = *cur;
9716
3.48M
    if (c & 0x80) {
9717
62.4k
  if ((cur[1] & 0xc0) != 0x80)
9718
1.74k
      goto encoding_error;
9719
60.6k
  if ((c & 0xe0) == 0xe0) {
9720
9721
545
      if ((cur[2] & 0xc0) != 0x80)
9722
37
    goto encoding_error;
9723
508
      if ((c & 0xf0) == 0xf0) {
9724
213
    if (((c & 0xf8) != 0xf0) ||
9725
213
        ((cur[3] & 0xc0) != 0x80))
9726
25
        goto encoding_error;
9727
    /* 4-byte code */
9728
188
    *len = 4;
9729
188
    val = (cur[0] & 0x7) << 18;
9730
188
    val |= (cur[1] & 0x3f) << 12;
9731
188
    val |= (cur[2] & 0x3f) << 6;
9732
188
    val |= cur[3] & 0x3f;
9733
295
      } else {
9734
        /* 3-byte code */
9735
295
    *len = 3;
9736
295
    val = (cur[0] & 0xf) << 12;
9737
295
    val |= (cur[1] & 0x3f) << 6;
9738
295
    val |= cur[2] & 0x3f;
9739
295
      }
9740
60.1k
  } else {
9741
    /* 2-byte code */
9742
60.1k
      *len = 2;
9743
60.1k
      val = (cur[0] & 0x1f) << 6;
9744
60.1k
      val |= cur[1] & 0x3f;
9745
60.1k
  }
9746
60.5k
  if (!IS_CHAR(val)) {
9747
34
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9748
0
  }
9749
60.5k
  return(val);
9750
3.41M
    } else {
9751
  /* 1-byte code */
9752
3.41M
  *len = 1;
9753
3.41M
  return(*cur);
9754
3.41M
    }
9755
1.80k
encoding_error:
9756
    /*
9757
     * If we detect an UTF8 error that probably means that the
9758
     * input encoding didn't get properly advertised in the
9759
     * declaration header. Report the error and switch the encoding
9760
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9761
     * encoding !)
9762
     */
9763
1.80k
    *len = 0;
9764
1.80k
    XP_ERROR0(XPATH_ENCODING_ERROR);
9765
0
}
9766
9767
/**
9768
 * xmlXPathParseNCName:
9769
 * @ctxt:  the XPath Parser context
9770
 *
9771
 * parse an XML namespace non qualified name.
9772
 *
9773
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9774
 *
9775
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9776
 *                       CombiningChar | Extender
9777
 *
9778
 * Returns the namespace name or NULL
9779
 */
9780
9781
xmlChar *
9782
192k
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9783
192k
    const xmlChar *in;
9784
192k
    xmlChar *ret;
9785
192k
    int count = 0;
9786
9787
192k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9788
    /*
9789
     * Accelerator for simple ASCII names
9790
     */
9791
192k
    in = ctxt->cur;
9792
192k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9793
192k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9794
192k
  (*in == '_')) {
9795
181k
  in++;
9796
969k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9797
969k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9798
969k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9799
969k
         (*in == '_') || (*in == '.') ||
9800
969k
         (*in == '-'))
9801
788k
      in++;
9802
181k
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9803
181k
            (*in == '[') || (*in == ']') || (*in == ':') ||
9804
181k
            (*in == '@') || (*in == '*')) {
9805
97.5k
      count = in - ctxt->cur;
9806
97.5k
      if (count == 0)
9807
0
    return(NULL);
9808
97.5k
      ret = xmlStrndup(ctxt->cur, count);
9809
97.5k
      ctxt->cur = in;
9810
97.5k
      return(ret);
9811
97.5k
  }
9812
181k
    }
9813
95.3k
    return(xmlXPathParseNameComplex(ctxt, 0));
9814
192k
}
9815
9816
9817
/**
9818
 * xmlXPathParseQName:
9819
 * @ctxt:  the XPath Parser context
9820
 * @prefix:  a xmlChar **
9821
 *
9822
 * parse an XML qualified name
9823
 *
9824
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9825
 *
9826
 * [NS 6] Prefix ::= NCName
9827
 *
9828
 * [NS 7] LocalPart ::= NCName
9829
 *
9830
 * Returns the function returns the local part, and prefix is updated
9831
 *   to get the Prefix if any.
9832
 */
9833
9834
static xmlChar *
9835
19.0k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9836
19.0k
    xmlChar *ret = NULL;
9837
9838
19.0k
    *prefix = NULL;
9839
19.0k
    ret = xmlXPathParseNCName(ctxt);
9840
19.0k
    if (ret && CUR == ':') {
9841
5.75k
        *prefix = ret;
9842
5.75k
  NEXT;
9843
5.75k
  ret = xmlXPathParseNCName(ctxt);
9844
5.75k
    }
9845
19.0k
    return(ret);
9846
19.0k
}
9847
9848
/**
9849
 * xmlXPathParseName:
9850
 * @ctxt:  the XPath Parser context
9851
 *
9852
 * parse an XML name
9853
 *
9854
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9855
 *                  CombiningChar | Extender
9856
 *
9857
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9858
 *
9859
 * Returns the namespace name or NULL
9860
 */
9861
9862
xmlChar *
9863
344k
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9864
344k
    const xmlChar *in;
9865
344k
    xmlChar *ret;
9866
344k
    size_t count = 0;
9867
9868
344k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9869
    /*
9870
     * Accelerator for simple ASCII names
9871
     */
9872
344k
    in = ctxt->cur;
9873
344k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874
344k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9875
344k
  (*in == '_') || (*in == ':')) {
9876
665
  in++;
9877
36.6k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878
36.6k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9879
36.6k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9880
36.6k
         (*in == '_') || (*in == '-') ||
9881
36.6k
         (*in == ':') || (*in == '.'))
9882
35.9k
      in++;
9883
665
  if ((*in > 0) && (*in < 0x80)) {
9884
531
      count = in - ctxt->cur;
9885
531
            if (count > XML_MAX_NAME_LENGTH) {
9886
0
                ctxt->cur = in;
9887
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9888
0
            }
9889
531
      ret = xmlStrndup(ctxt->cur, count);
9890
531
      ctxt->cur = in;
9891
531
      return(ret);
9892
531
  }
9893
665
    }
9894
344k
    return(xmlXPathParseNameComplex(ctxt, 1));
9895
344k
}
9896
9897
static xmlChar *
9898
439k
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9899
439k
    xmlChar buf[XML_MAX_NAMELEN + 5];
9900
439k
    int len = 0, l;
9901
439k
    int c;
9902
9903
    /*
9904
     * Handler for more complex cases
9905
     */
9906
439k
    c = CUR_CHAR(l);
9907
439k
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9908
439k
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9909
439k
        (c == '*') || /* accelerators */
9910
439k
  (!IS_LETTER(c) && (c != '_') &&
9911
432k
         ((!qualified) || (c != ':')))) {
9912
352k
  return(NULL);
9913
352k
    }
9914
9915
530k
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9916
530k
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9917
524k
            (c == '.') || (c == '-') ||
9918
524k
      (c == '_') || ((qualified) && (c == ':')) ||
9919
524k
      (IS_COMBINING(c)) ||
9920
524k
      (IS_EXTENDER(c)))) {
9921
444k
  COPY_BUF(l,buf,len,c);
9922
444k
  NEXTL(l);
9923
444k
  c = CUR_CHAR(l);
9924
444k
  if (len >= XML_MAX_NAMELEN) {
9925
      /*
9926
       * Okay someone managed to make a huge name, so he's ready to pay
9927
       * for the processing speed.
9928
       */
9929
1.56k
      xmlChar *buffer;
9930
1.56k
      int max = len * 2;
9931
9932
1.56k
            if (len > XML_MAX_NAME_LENGTH) {
9933
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9934
0
            }
9935
1.56k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9936
1.56k
      if (buffer == NULL) {
9937
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9938
0
      }
9939
1.56k
      memcpy(buffer, buf, len);
9940
471k
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9941
471k
       (c == '.') || (c == '-') ||
9942
471k
       (c == '_') || ((qualified) && (c == ':')) ||
9943
471k
       (IS_COMBINING(c)) ||
9944
471k
       (IS_EXTENDER(c))) {
9945
469k
    if (len + 10 > max) {
9946
1.49k
                    xmlChar *tmp;
9947
1.49k
                    if (max > XML_MAX_NAME_LENGTH) {
9948
1
                        xmlFree(buffer);
9949
1
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9950
0
                    }
9951
1.49k
        max *= 2;
9952
1.49k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9953
1.49k
        if (tmp == NULL) {
9954
0
                        xmlFree(buffer);
9955
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9956
0
        }
9957
1.49k
                    buffer = tmp;
9958
1.49k
    }
9959
469k
    COPY_BUF(l,buffer,len,c);
9960
469k
    NEXTL(l);
9961
469k
    c = CUR_CHAR(l);
9962
469k
      }
9963
1.56k
      buffer[len] = 0;
9964
1.56k
      return(buffer);
9965
1.56k
  }
9966
444k
    }
9967
85.5k
    if (len == 0)
9968
0
  return(NULL);
9969
85.5k
    return(xmlStrndup(buf, len));
9970
85.5k
}
9971
9972
4.22k
#define MAX_FRAC 20
9973
9974
/**
9975
 * xmlXPathStringEvalNumber:
9976
 * @str:  A string to scan
9977
 *
9978
 *  [30a]  Float  ::= Number ('e' Digits?)?
9979
 *
9980
 *  [30]   Number ::=   Digits ('.' Digits?)?
9981
 *                    | '.' Digits
9982
 *  [31]   Digits ::=   [0-9]+
9983
 *
9984
 * Compile a Number in the string
9985
 * In complement of the Number expression, this function also handles
9986
 * negative values : '-' Number.
9987
 *
9988
 * Returns the double value.
9989
 */
9990
double
9991
522k
xmlXPathStringEvalNumber(const xmlChar *str) {
9992
522k
    const xmlChar *cur = str;
9993
522k
    double ret;
9994
522k
    int ok = 0;
9995
522k
    int isneg = 0;
9996
522k
    int exponent = 0;
9997
522k
    int is_exponent_negative = 0;
9998
522k
#ifdef __GNUC__
9999
522k
    unsigned long tmp = 0;
10000
522k
    double temp;
10001
522k
#endif
10002
522k
    if (cur == NULL) return(0);
10003
958k
    while (IS_BLANK_CH(*cur)) cur++;
10004
522k
    if (*cur == '-') {
10005
1.72k
  isneg = 1;
10006
1.72k
  cur++;
10007
1.72k
    }
10008
522k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
10009
494k
        return(xmlXPathNAN);
10010
494k
    }
10011
10012
27.9k
#ifdef __GNUC__
10013
    /*
10014
     * tmp/temp is a workaround against a gcc compiler bug
10015
     * http://veillard.com/gcc.bug
10016
     */
10017
27.9k
    ret = 0;
10018
65.7k
    while ((*cur >= '0') && (*cur <= '9')) {
10019
37.8k
  ret = ret * 10;
10020
37.8k
  tmp = (*cur - '0');
10021
37.8k
  ok = 1;
10022
37.8k
  cur++;
10023
37.8k
  temp = (double) tmp;
10024
37.8k
  ret = ret + temp;
10025
37.8k
    }
10026
#else
10027
    ret = 0;
10028
    while ((*cur >= '0') && (*cur <= '9')) {
10029
  ret = ret * 10 + (*cur - '0');
10030
  ok = 1;
10031
  cur++;
10032
    }
10033
#endif
10034
10035
27.9k
    if (*cur == '.') {
10036
4.33k
  int v, frac = 0, max;
10037
4.33k
  double fraction = 0;
10038
10039
4.33k
        cur++;
10040
4.33k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10041
3.13k
      return(xmlXPathNAN);
10042
3.13k
  }
10043
1.59k
        while (*cur == '0') {
10044
390
      frac = frac + 1;
10045
390
      cur++;
10046
390
        }
10047
1.20k
        max = frac + MAX_FRAC;
10048
3.09k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10049
1.88k
      v = (*cur - '0');
10050
1.88k
      fraction = fraction * 10 + v;
10051
1.88k
      frac = frac + 1;
10052
1.88k
      cur++;
10053
1.88k
  }
10054
1.20k
  fraction /= pow(10.0, frac);
10055
1.20k
  ret = ret + fraction;
10056
3.60k
  while ((*cur >= '0') && (*cur <= '9'))
10057
2.39k
      cur++;
10058
1.20k
    }
10059
24.8k
    if ((*cur == 'e') || (*cur == 'E')) {
10060
503
      cur++;
10061
503
      if (*cur == '-') {
10062
305
  is_exponent_negative = 1;
10063
305
  cur++;
10064
305
      } else if (*cur == '+') {
10065
11
        cur++;
10066
11
      }
10067
15.1k
      while ((*cur >= '0') && (*cur <= '9')) {
10068
14.5k
        if (exponent < 1000000)
10069
875
    exponent = exponent * 10 + (*cur - '0');
10070
14.5k
  cur++;
10071
14.5k
      }
10072
503
    }
10073
46.7k
    while (IS_BLANK_CH(*cur)) cur++;
10074
24.8k
    if (*cur != 0) return(xmlXPathNAN);
10075
18.3k
    if (isneg) ret = -ret;
10076
18.3k
    if (is_exponent_negative) exponent = -exponent;
10077
18.3k
    ret *= pow(10.0, (double)exponent);
10078
18.3k
    return(ret);
10079
24.8k
}
10080
10081
/**
10082
 * xmlXPathCompNumber:
10083
 * @ctxt:  the XPath Parser context
10084
 *
10085
 *  [30]   Number ::=   Digits ('.' Digits?)?
10086
 *                    | '.' Digits
10087
 *  [31]   Digits ::=   [0-9]+
10088
 *
10089
 * Compile a Number, then push it on the stack
10090
 *
10091
 */
10092
static void
10093
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10094
21.5k
{
10095
21.5k
    double ret = 0.0;
10096
21.5k
    int ok = 0;
10097
21.5k
    int exponent = 0;
10098
21.5k
    int is_exponent_negative = 0;
10099
21.5k
    xmlXPathObjectPtr num;
10100
21.5k
#ifdef __GNUC__
10101
21.5k
    unsigned long tmp = 0;
10102
21.5k
    double temp;
10103
21.5k
#endif
10104
10105
21.5k
    CHECK_ERROR;
10106
21.5k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10107
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10108
0
    }
10109
21.5k
#ifdef __GNUC__
10110
    /*
10111
     * tmp/temp is a workaround against a gcc compiler bug
10112
     * http://veillard.com/gcc.bug
10113
     */
10114
21.5k
    ret = 0;
10115
308k
    while ((CUR >= '0') && (CUR <= '9')) {
10116
287k
  ret = ret * 10;
10117
287k
  tmp = (CUR - '0');
10118
287k
        ok = 1;
10119
287k
        NEXT;
10120
287k
  temp = (double) tmp;
10121
287k
  ret = ret + temp;
10122
287k
    }
10123
#else
10124
    ret = 0;
10125
    while ((CUR >= '0') && (CUR <= '9')) {
10126
  ret = ret * 10 + (CUR - '0');
10127
  ok = 1;
10128
  NEXT;
10129
    }
10130
#endif
10131
21.5k
    if (CUR == '.') {
10132
3.02k
  int v, frac = 0, max;
10133
3.02k
  double fraction = 0;
10134
10135
3.02k
        NEXT;
10136
3.02k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10137
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10138
0
        }
10139
5.09k
        while (CUR == '0') {
10140
2.07k
            frac = frac + 1;
10141
2.07k
            NEXT;
10142
2.07k
        }
10143
3.02k
        max = frac + MAX_FRAC;
10144
4.41k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10145
1.39k
      v = (CUR - '0');
10146
1.39k
      fraction = fraction * 10 + v;
10147
1.39k
      frac = frac + 1;
10148
1.39k
            NEXT;
10149
1.39k
        }
10150
3.02k
        fraction /= pow(10.0, frac);
10151
3.02k
        ret = ret + fraction;
10152
4.54k
        while ((CUR >= '0') && (CUR <= '9'))
10153
1.52k
            NEXT;
10154
3.02k
    }
10155
21.5k
    if ((CUR == 'e') || (CUR == 'E')) {
10156
1.04k
        NEXT;
10157
1.04k
        if (CUR == '-') {
10158
69
            is_exponent_negative = 1;
10159
69
            NEXT;
10160
976
        } else if (CUR == '+') {
10161
23
      NEXT;
10162
23
  }
10163
11.3k
        while ((CUR >= '0') && (CUR <= '9')) {
10164
10.3k
            if (exponent < 1000000)
10165
4.96k
                exponent = exponent * 10 + (CUR - '0');
10166
10.3k
            NEXT;
10167
10.3k
        }
10168
1.04k
        if (is_exponent_negative)
10169
69
            exponent = -exponent;
10170
1.04k
        ret *= pow(10.0, (double) exponent);
10171
1.04k
    }
10172
21.5k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10173
21.5k
    if (num == NULL) {
10174
0
  ctxt->error = XPATH_MEMORY_ERROR;
10175
21.5k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10176
21.5k
                              NULL) == -1) {
10177
0
        xmlXPathReleaseObject(ctxt->context, num);
10178
0
    }
10179
21.5k
}
10180
10181
/**
10182
 * xmlXPathParseLiteral:
10183
 * @ctxt:  the XPath Parser context
10184
 *
10185
 * Parse a Literal
10186
 *
10187
 *  [29]   Literal ::=   '"' [^"]* '"'
10188
 *                    | "'" [^']* "'"
10189
 *
10190
 * Returns the value found or NULL in case of error
10191
 */
10192
static xmlChar *
10193
246
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10194
246
    const xmlChar *q;
10195
246
    xmlChar *ret = NULL;
10196
10197
246
    if (CUR == '"') {
10198
83
        NEXT;
10199
83
  q = CUR_PTR;
10200
16.3k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10201
16.2k
      NEXT;
10202
83
  if (!IS_CHAR_CH(CUR)) {
10203
68
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10204
15
  } else {
10205
15
      ret = xmlStrndup(q, CUR_PTR - q);
10206
15
      NEXT;
10207
15
        }
10208
163
    } else if (CUR == '\'') {
10209
149
        NEXT;
10210
149
  q = CUR_PTR;
10211
29.6k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10212
29.4k
      NEXT;
10213
149
  if (!IS_CHAR_CH(CUR)) {
10214
50
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10215
99
  } else {
10216
99
      ret = xmlStrndup(q, CUR_PTR - q);
10217
99
      NEXT;
10218
99
        }
10219
149
    } else {
10220
14
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10221
0
    }
10222
114
    return(ret);
10223
246
}
10224
10225
/**
10226
 * xmlXPathCompLiteral:
10227
 * @ctxt:  the XPath Parser context
10228
 *
10229
 * Parse a Literal and push it on the stack.
10230
 *
10231
 *  [29]   Literal ::=   '"' [^"]* '"'
10232
 *                    | "'" [^']* "'"
10233
 *
10234
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10235
 */
10236
static void
10237
16.8k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10238
16.8k
    const xmlChar *q;
10239
16.8k
    xmlChar *ret = NULL;
10240
16.8k
    xmlXPathObjectPtr lit;
10241
10242
16.8k
    if (CUR == '"') {
10243
344
        NEXT;
10244
344
  q = CUR_PTR;
10245
413k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10246
413k
      NEXT;
10247
344
  if (!IS_CHAR_CH(CUR)) {
10248
88
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10249
256
  } else {
10250
256
      ret = xmlStrndup(q, CUR_PTR - q);
10251
256
      NEXT;
10252
256
        }
10253
16.5k
    } else if (CUR == '\'') {
10254
16.5k
        NEXT;
10255
16.5k
  q = CUR_PTR;
10256
8.64M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10257
8.62M
      NEXT;
10258
16.5k
  if (!IS_CHAR_CH(CUR)) {
10259
98
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10260
16.4k
  } else {
10261
16.4k
      ret = xmlStrndup(q, CUR_PTR - q);
10262
16.4k
      NEXT;
10263
16.4k
        }
10264
16.5k
    } else {
10265
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10266
0
    }
10267
16.7k
    if (ret == NULL) return;
10268
16.7k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10269
16.7k
    if (lit == NULL) {
10270
0
  ctxt->error = XPATH_MEMORY_ERROR;
10271
16.7k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10272
16.7k
                              NULL) == -1) {
10273
0
        xmlXPathReleaseObject(ctxt->context, lit);
10274
0
    }
10275
16.7k
    xmlFree(ret);
10276
16.7k
}
10277
10278
/**
10279
 * xmlXPathCompVariableReference:
10280
 * @ctxt:  the XPath Parser context
10281
 *
10282
 * Parse a VariableReference, evaluate it and push it on the stack.
10283
 *
10284
 * The variable bindings consist of a mapping from variable names
10285
 * to variable values. The value of a variable is an object, which can be
10286
 * of any of the types that are possible for the value of an expression,
10287
 * and may also be of additional types not specified here.
10288
 *
10289
 * Early evaluation is possible since:
10290
 * The variable bindings [...] used to evaluate a subexpression are
10291
 * always the same as those used to evaluate the containing expression.
10292
 *
10293
 *  [36]   VariableReference ::=   '$' QName
10294
 */
10295
static void
10296
2.43k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10297
2.43k
    xmlChar *name;
10298
2.43k
    xmlChar *prefix;
10299
10300
2.43k
    SKIP_BLANKS;
10301
2.43k
    if (CUR != '$') {
10302
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10303
0
    }
10304
2.43k
    NEXT;
10305
2.43k
    name = xmlXPathParseQName(ctxt, &prefix);
10306
2.43k
    if (name == NULL) {
10307
121
        xmlFree(prefix);
10308
121
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10309
0
    }
10310
2.31k
    ctxt->comp->last = -1;
10311
2.31k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10312
0
        xmlFree(prefix);
10313
0
        xmlFree(name);
10314
0
    }
10315
2.31k
    SKIP_BLANKS;
10316
2.31k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10317
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10318
0
    }
10319
2.31k
}
10320
10321
/**
10322
 * xmlXPathIsNodeType:
10323
 * @name:  a name string
10324
 *
10325
 * Is the name given a NodeType one.
10326
 *
10327
 *  [38]   NodeType ::=   'comment'
10328
 *                    | 'text'
10329
 *                    | 'processing-instruction'
10330
 *                    | 'node'
10331
 *
10332
 * Returns 1 if true 0 otherwise
10333
 */
10334
int
10335
16.8k
xmlXPathIsNodeType(const xmlChar *name) {
10336
16.8k
    if (name == NULL)
10337
0
  return(0);
10338
10339
16.8k
    if (xmlStrEqual(name, BAD_CAST "node"))
10340
217
  return(1);
10341
16.6k
    if (xmlStrEqual(name, BAD_CAST "text"))
10342
37
  return(1);
10343
16.6k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10344
15
  return(1);
10345
16.6k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10346
1
  return(1);
10347
16.6k
    return(0);
10348
16.6k
}
10349
10350
/**
10351
 * xmlXPathCompFunctionCall:
10352
 * @ctxt:  the XPath Parser context
10353
 *
10354
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10355
 *  [17]   Argument ::=   Expr
10356
 *
10357
 * Compile a function call, the evaluation of all arguments are
10358
 * pushed on the stack
10359
 */
10360
static void
10361
16.6k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10362
16.6k
    xmlChar *name;
10363
16.6k
    xmlChar *prefix;
10364
16.6k
    int nbargs = 0;
10365
16.6k
    int sort = 1;
10366
10367
16.6k
    name = xmlXPathParseQName(ctxt, &prefix);
10368
16.6k
    if (name == NULL) {
10369
13
  xmlFree(prefix);
10370
13
  XP_ERROR(XPATH_EXPR_ERROR);
10371
0
    }
10372
16.6k
    SKIP_BLANKS;
10373
#ifdef DEBUG_EXPR
10374
    if (prefix == NULL)
10375
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10376
      name);
10377
    else
10378
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10379
      prefix, name);
10380
#endif
10381
10382
16.6k
    if (CUR != '(') {
10383
14
  xmlFree(name);
10384
14
  xmlFree(prefix);
10385
14
  XP_ERROR(XPATH_EXPR_ERROR);
10386
0
    }
10387
16.5k
    NEXT;
10388
16.5k
    SKIP_BLANKS;
10389
10390
    /*
10391
    * Optimization for count(): we don't need the node-set to be sorted.
10392
    */
10393
16.5k
    if ((prefix == NULL) && (name[0] == 'c') &&
10394
16.5k
  xmlStrEqual(name, BAD_CAST "count"))
10395
4
    {
10396
4
  sort = 0;
10397
4
    }
10398
16.5k
    ctxt->comp->last = -1;
10399
16.5k
    if (CUR != ')') {
10400
24.5k
  while (CUR != 0) {
10401
24.1k
      int op1 = ctxt->comp->last;
10402
24.1k
      ctxt->comp->last = -1;
10403
24.1k
      xmlXPathCompileExpr(ctxt, sort);
10404
24.1k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10405
2.29k
    xmlFree(name);
10406
2.29k
    xmlFree(prefix);
10407
2.29k
    return;
10408
2.29k
      }
10409
21.8k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10410
21.8k
      nbargs++;
10411
21.8k
      if (CUR == ')') break;
10412
11.4k
      if (CUR != ',') {
10413
491
    xmlFree(name);
10414
491
    xmlFree(prefix);
10415
491
    XP_ERROR(XPATH_EXPR_ERROR);
10416
0
      }
10417
10.9k
      NEXT;
10418
10.9k
      SKIP_BLANKS;
10419
10.9k
  }
10420
13.5k
    }
10421
13.8k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10422
0
        xmlFree(prefix);
10423
0
        xmlFree(name);
10424
0
    }
10425
13.8k
    NEXT;
10426
13.8k
    SKIP_BLANKS;
10427
13.8k
}
10428
10429
/**
10430
 * xmlXPathCompPrimaryExpr:
10431
 * @ctxt:  the XPath Parser context
10432
 *
10433
 *  [15]   PrimaryExpr ::=   VariableReference
10434
 *                | '(' Expr ')'
10435
 *                | Literal
10436
 *                | Number
10437
 *                | FunctionCall
10438
 *
10439
 * Compile a primary expression.
10440
 */
10441
static void
10442
63.9k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10443
63.9k
    SKIP_BLANKS;
10444
63.9k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10445
61.5k
    else if (CUR == '(') {
10446
6.44k
  NEXT;
10447
6.44k
  SKIP_BLANKS;
10448
6.44k
  xmlXPathCompileExpr(ctxt, 1);
10449
6.44k
  CHECK_ERROR;
10450
5.62k
  if (CUR != ')') {
10451
92
      XP_ERROR(XPATH_EXPR_ERROR);
10452
0
  }
10453
5.53k
  NEXT;
10454
5.53k
  SKIP_BLANKS;
10455
55.1k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10456
21.5k
  xmlXPathCompNumber(ctxt);
10457
33.5k
    } else if ((CUR == '\'') || (CUR == '"')) {
10458
16.8k
  xmlXPathCompLiteral(ctxt);
10459
16.8k
    } else {
10460
16.6k
  xmlXPathCompFunctionCall(ctxt);
10461
16.6k
    }
10462
63.0k
    SKIP_BLANKS;
10463
63.0k
}
10464
10465
/**
10466
 * xmlXPathCompFilterExpr:
10467
 * @ctxt:  the XPath Parser context
10468
 *
10469
 *  [20]   FilterExpr ::=   PrimaryExpr
10470
 *               | FilterExpr Predicate
10471
 *
10472
 * Compile a filter expression.
10473
 * Square brackets are used to filter expressions in the same way that
10474
 * they are used in location paths. It is an error if the expression to
10475
 * be filtered does not evaluate to a node-set. The context node list
10476
 * used for evaluating the expression in square brackets is the node-set
10477
 * to be filtered listed in document order.
10478
 */
10479
10480
static void
10481
63.9k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10482
63.9k
    xmlXPathCompPrimaryExpr(ctxt);
10483
63.9k
    CHECK_ERROR;
10484
59.9k
    SKIP_BLANKS;
10485
10486
277k
    while (CUR == '[') {
10487
217k
  xmlXPathCompPredicate(ctxt, 1);
10488
217k
  SKIP_BLANKS;
10489
217k
    }
10490
10491
10492
59.9k
}
10493
10494
/**
10495
 * xmlXPathScanName:
10496
 * @ctxt:  the XPath Parser context
10497
 *
10498
 * Trickery: parse an XML name but without consuming the input flow
10499
 * Needed to avoid insanity in the parser state.
10500
 *
10501
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10502
 *                  CombiningChar | Extender
10503
 *
10504
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10505
 *
10506
 * [6] Names ::= Name (S Name)*
10507
 *
10508
 * Returns the Name parsed or NULL
10509
 */
10510
10511
static xmlChar *
10512
1.41M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10513
1.41M
    int l;
10514
1.41M
    int c;
10515
1.41M
    const xmlChar *cur;
10516
1.41M
    xmlChar *ret;
10517
10518
1.41M
    cur = ctxt->cur;
10519
10520
1.41M
    c = CUR_CHAR(l);
10521
1.41M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10522
1.41M
  (!IS_LETTER(c) && (c != '_') &&
10523
1.41M
         (c != ':'))) {
10524
1.36M
  return(NULL);
10525
1.36M
    }
10526
10527
763k
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10528
763k
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10529
755k
            (c == '.') || (c == '-') ||
10530
755k
      (c == '_') || (c == ':') ||
10531
755k
      (IS_COMBINING(c)) ||
10532
755k
      (IS_EXTENDER(c)))) {
10533
711k
  NEXTL(l);
10534
711k
  c = CUR_CHAR(l);
10535
711k
    }
10536
52.5k
    ret = xmlStrndup(cur, ctxt->cur - cur);
10537
52.5k
    ctxt->cur = cur;
10538
52.5k
    return(ret);
10539
1.41M
}
10540
10541
/**
10542
 * xmlXPathCompPathExpr:
10543
 * @ctxt:  the XPath Parser context
10544
 *
10545
 *  [19]   PathExpr ::=   LocationPath
10546
 *               | FilterExpr
10547
 *               | FilterExpr '/' RelativeLocationPath
10548
 *               | FilterExpr '//' RelativeLocationPath
10549
 *
10550
 * Compile a path expression.
10551
 * The / operator and // operators combine an arbitrary expression
10552
 * and a relative location path. It is an error if the expression
10553
 * does not evaluate to a node-set.
10554
 * The / operator does composition in the same way as when / is
10555
 * used in a location path. As in location paths, // is short for
10556
 * /descendant-or-self::node()/.
10557
 */
10558
10559
static void
10560
1.60M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10561
1.60M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10562
1.60M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10563
10564
1.60M
    SKIP_BLANKS;
10565
1.60M
    if ((CUR == '$') || (CUR == '(') ||
10566
1.60M
  (IS_ASCII_DIGIT(CUR)) ||
10567
1.60M
        (CUR == '\'') || (CUR == '"') ||
10568
1.60M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10569
47.3k
  lc = 0;
10570
1.55M
    } else if (CUR == '*') {
10571
  /* relative or absolute location path */
10572
70.2k
  lc = 1;
10573
1.48M
    } else if (CUR == '/') {
10574
  /* relative or absolute location path */
10575
60.2k
  lc = 1;
10576
1.42M
    } else if (CUR == '@') {
10577
  /* relative abbreviated attribute location path */
10578
1.11k
  lc = 1;
10579
1.42M
    } else if (CUR == '.') {
10580
  /* relative abbreviated attribute location path */
10581
6.15k
  lc = 1;
10582
1.41M
    } else {
10583
  /*
10584
   * Problem is finding if we have a name here whether it's:
10585
   *   - a nodetype
10586
   *   - a function call in which case it's followed by '('
10587
   *   - an axis in which case it's followed by ':'
10588
   *   - a element name
10589
   * We do an a priori analysis here rather than having to
10590
   * maintain parsed token content through the recursive function
10591
   * calls. This looks uglier but makes the code easier to
10592
   * read/write/debug.
10593
   */
10594
1.41M
  SKIP_BLANKS;
10595
1.41M
  name = xmlXPathScanName(ctxt);
10596
1.41M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10597
#ifdef DEBUG_STEP
10598
      xmlGenericError(xmlGenericErrorContext,
10599
        "PathExpr: Axis\n");
10600
#endif
10601
3.31k
      lc = 1;
10602
3.31k
      xmlFree(name);
10603
1.41M
  } else if (name != NULL) {
10604
49.2k
      int len =xmlStrlen(name);
10605
10606
10607
72.3k
      while (NXT(len) != 0) {
10608
71.9k
    if (NXT(len) == '/') {
10609
        /* element name */
10610
#ifdef DEBUG_STEP
10611
        xmlGenericError(xmlGenericErrorContext,
10612
          "PathExpr: AbbrRelLocation\n");
10613
#endif
10614
6.34k
        lc = 1;
10615
6.34k
        break;
10616
65.6k
    } else if (IS_BLANK_CH(NXT(len))) {
10617
        /* ignore blanks */
10618
23.0k
        ;
10619
42.6k
    } else if (NXT(len) == ':') {
10620
#ifdef DEBUG_STEP
10621
        xmlGenericError(xmlGenericErrorContext,
10622
          "PathExpr: AbbrRelLocation\n");
10623
#endif
10624
67
        lc = 1;
10625
67
        break;
10626
42.5k
    } else if ((NXT(len) == '(')) {
10627
        /* Node Type or Function */
10628
16.8k
        if (xmlXPathIsNodeType(name)) {
10629
#ifdef DEBUG_STEP
10630
            xmlGenericError(xmlGenericErrorContext,
10631
        "PathExpr: Type search\n");
10632
#endif
10633
270
      lc = 1;
10634
#ifdef LIBXML_XPTR_LOCS_ENABLED
10635
                    } else if (ctxt->xptr &&
10636
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10637
                        lc = 1;
10638
#endif
10639
16.6k
        } else {
10640
#ifdef DEBUG_STEP
10641
            xmlGenericError(xmlGenericErrorContext,
10642
        "PathExpr: function call\n");
10643
#endif
10644
16.6k
      lc = 0;
10645
16.6k
        }
10646
16.8k
                    break;
10647
25.6k
    } else if ((NXT(len) == '[')) {
10648
        /* element name */
10649
#ifdef DEBUG_STEP
10650
        xmlGenericError(xmlGenericErrorContext,
10651
          "PathExpr: AbbrRelLocation\n");
10652
#endif
10653
1.34k
        lc = 1;
10654
1.34k
        break;
10655
24.3k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10656
24.3k
         (NXT(len) == '=')) {
10657
9.23k
        lc = 1;
10658
9.23k
        break;
10659
15.0k
    } else {
10660
15.0k
        lc = 1;
10661
15.0k
        break;
10662
15.0k
    }
10663
23.0k
    len++;
10664
23.0k
      }
10665
49.2k
      if (NXT(len) == 0) {
10666
#ifdef DEBUG_STEP
10667
    xmlGenericError(xmlGenericErrorContext,
10668
      "PathExpr: AbbrRelLocation\n");
10669
#endif
10670
    /* element name */
10671
305
    lc = 1;
10672
305
      }
10673
49.2k
      xmlFree(name);
10674
1.36M
  } else {
10675
      /* make sure all cases are covered explicitly */
10676
1.36M
      XP_ERROR(XPATH_EXPR_ERROR);
10677
0
  }
10678
1.41M
    }
10679
10680
237k
    if (lc) {
10681
173k
  if (CUR == '/') {
10682
60.2k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10683
113k
  } else {
10684
113k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10685
113k
  }
10686
173k
  xmlXPathCompLocationPath(ctxt);
10687
173k
    } else {
10688
63.9k
  xmlXPathCompFilterExpr(ctxt);
10689
63.9k
  CHECK_ERROR;
10690
59.4k
  if ((CUR == '/') && (NXT(1) == '/')) {
10691
1.03k
      SKIP(2);
10692
1.03k
      SKIP_BLANKS;
10693
10694
1.03k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10695
1.03k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10696
10697
1.03k
      xmlXPathCompRelativeLocationPath(ctxt);
10698
58.4k
  } else if (CUR == '/') {
10699
786
      xmlXPathCompRelativeLocationPath(ctxt);
10700
786
  }
10701
59.4k
    }
10702
233k
    SKIP_BLANKS;
10703
233k
}
10704
10705
/**
10706
 * xmlXPathCompUnionExpr:
10707
 * @ctxt:  the XPath Parser context
10708
 *
10709
 *  [18]   UnionExpr ::=   PathExpr
10710
 *               | UnionExpr '|' PathExpr
10711
 *
10712
 * Compile an union expression.
10713
 */
10714
10715
static void
10716
200k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10717
200k
    xmlXPathCompPathExpr(ctxt);
10718
200k
    CHECK_ERROR;
10719
186k
    SKIP_BLANKS;
10720
1.58M
    while (CUR == '|') {
10721
1.40M
  int op1 = ctxt->comp->last;
10722
1.40M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723
10724
1.40M
  NEXT;
10725
1.40M
  SKIP_BLANKS;
10726
1.40M
  xmlXPathCompPathExpr(ctxt);
10727
10728
1.40M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10729
10730
1.40M
  SKIP_BLANKS;
10731
1.40M
    }
10732
186k
}
10733
10734
/**
10735
 * xmlXPathCompUnaryExpr:
10736
 * @ctxt:  the XPath Parser context
10737
 *
10738
 *  [27]   UnaryExpr ::=   UnionExpr
10739
 *                   | '-' UnaryExpr
10740
 *
10741
 * Compile an unary expression.
10742
 */
10743
10744
static void
10745
200k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10746
200k
    int minus = 0;
10747
200k
    int found = 0;
10748
10749
200k
    SKIP_BLANKS;
10750
214k
    while (CUR == '-') {
10751
13.4k
        minus = 1 - minus;
10752
13.4k
  found = 1;
10753
13.4k
  NEXT;
10754
13.4k
  SKIP_BLANKS;
10755
13.4k
    }
10756
10757
200k
    xmlXPathCompUnionExpr(ctxt);
10758
200k
    CHECK_ERROR;
10759
186k
    if (found) {
10760
3.22k
  if (minus)
10761
2.92k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10762
302
  else
10763
302
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10764
3.22k
    }
10765
186k
}
10766
10767
/**
10768
 * xmlXPathCompMultiplicativeExpr:
10769
 * @ctxt:  the XPath Parser context
10770
 *
10771
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10772
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10773
 *                   | MultiplicativeExpr 'div' UnaryExpr
10774
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10775
 *  [34]   MultiplyOperator ::=   '*'
10776
 *
10777
 * Compile an Additive expression.
10778
 */
10779
10780
static void
10781
114k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10782
114k
    xmlXPathCompUnaryExpr(ctxt);
10783
114k
    CHECK_ERROR;
10784
101k
    SKIP_BLANKS;
10785
186k
    while ((CUR == '*') ||
10786
186k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10787
186k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10788
85.9k
  int op = -1;
10789
85.9k
  int op1 = ctxt->comp->last;
10790
10791
85.9k
        if (CUR == '*') {
10792
85.5k
      op = 0;
10793
85.5k
      NEXT;
10794
85.5k
  } else if (CUR == 'd') {
10795
211
      op = 1;
10796
211
      SKIP(3);
10797
235
  } else if (CUR == 'm') {
10798
235
      op = 2;
10799
235
      SKIP(3);
10800
235
  }
10801
85.9k
  SKIP_BLANKS;
10802
85.9k
        xmlXPathCompUnaryExpr(ctxt);
10803
85.9k
  CHECK_ERROR;
10804
84.9k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10805
84.9k
  SKIP_BLANKS;
10806
84.9k
    }
10807
101k
}
10808
10809
/**
10810
 * xmlXPathCompAdditiveExpr:
10811
 * @ctxt:  the XPath Parser context
10812
 *
10813
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10814
 *                   | AdditiveExpr '+' MultiplicativeExpr
10815
 *                   | AdditiveExpr '-' MultiplicativeExpr
10816
 *
10817
 * Compile an Additive expression.
10818
 */
10819
10820
static void
10821
111k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10822
10823
111k
    xmlXPathCompMultiplicativeExpr(ctxt);
10824
111k
    CHECK_ERROR;
10825
97.0k
    SKIP_BLANKS;
10826
100k
    while ((CUR == '+') || (CUR == '-')) {
10827
3.75k
  int plus;
10828
3.75k
  int op1 = ctxt->comp->last;
10829
10830
3.75k
        if (CUR == '+') plus = 1;
10831
2.73k
  else plus = 0;
10832
3.75k
  NEXT;
10833
3.75k
  SKIP_BLANKS;
10834
3.75k
        xmlXPathCompMultiplicativeExpr(ctxt);
10835
3.75k
  CHECK_ERROR;
10836
3.19k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10837
3.19k
  SKIP_BLANKS;
10838
3.19k
    }
10839
97.0k
}
10840
10841
/**
10842
 * xmlXPathCompRelationalExpr:
10843
 * @ctxt:  the XPath Parser context
10844
 *
10845
 *  [24]   RelationalExpr ::=   AdditiveExpr
10846
 *                 | RelationalExpr '<' AdditiveExpr
10847
 *                 | RelationalExpr '>' AdditiveExpr
10848
 *                 | RelationalExpr '<=' AdditiveExpr
10849
 *                 | RelationalExpr '>=' AdditiveExpr
10850
 *
10851
 *  A <= B > C is allowed ? Answer from James, yes with
10852
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10853
 *  which is basically what got implemented.
10854
 *
10855
 * Compile a Relational expression, then push the result
10856
 * on the stack
10857
 */
10858
10859
static void
10860
90.4k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10861
90.4k
    xmlXPathCompAdditiveExpr(ctxt);
10862
90.4k
    CHECK_ERROR;
10863
76.5k
    SKIP_BLANKS;
10864
96.4k
    while ((CUR == '<') || (CUR == '>')) {
10865
20.5k
  int inf, strict;
10866
20.5k
  int op1 = ctxt->comp->last;
10867
10868
20.5k
        if (CUR == '<') inf = 1;
10869
7.63k
  else inf = 0;
10870
20.5k
  if (NXT(1) == '=') strict = 0;
10871
16.8k
  else strict = 1;
10872
20.5k
  NEXT;
10873
20.5k
  if (!strict) NEXT;
10874
20.5k
  SKIP_BLANKS;
10875
20.5k
        xmlXPathCompAdditiveExpr(ctxt);
10876
20.5k
  CHECK_ERROR;
10877
19.9k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10878
19.9k
  SKIP_BLANKS;
10879
19.9k
    }
10880
76.5k
}
10881
10882
/**
10883
 * xmlXPathCompEqualityExpr:
10884
 * @ctxt:  the XPath Parser context
10885
 *
10886
 *  [23]   EqualityExpr ::=   RelationalExpr
10887
 *                 | EqualityExpr '=' RelationalExpr
10888
 *                 | EqualityExpr '!=' RelationalExpr
10889
 *
10890
 *  A != B != C is allowed ? Answer from James, yes with
10891
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10892
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10893
 *  which is basically what got implemented.
10894
 *
10895
 * Compile an Equality expression.
10896
 *
10897
 */
10898
static void
10899
71.0k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10900
71.0k
    xmlXPathCompRelationalExpr(ctxt);
10901
71.0k
    CHECK_ERROR;
10902
57.3k
    SKIP_BLANKS;
10903
75.8k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10904
19.3k
  int eq;
10905
19.3k
  int op1 = ctxt->comp->last;
10906
10907
19.3k
        if (CUR == '=') eq = 1;
10908
1.85k
  else eq = 0;
10909
19.3k
  NEXT;
10910
19.3k
  if (!eq) NEXT;
10911
19.3k
  SKIP_BLANKS;
10912
19.3k
        xmlXPathCompRelationalExpr(ctxt);
10913
19.3k
  CHECK_ERROR;
10914
18.5k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10915
18.5k
  SKIP_BLANKS;
10916
18.5k
    }
10917
57.3k
}
10918
10919
/**
10920
 * xmlXPathCompAndExpr:
10921
 * @ctxt:  the XPath Parser context
10922
 *
10923
 *  [22]   AndExpr ::=   EqualityExpr
10924
 *                 | AndExpr 'and' EqualityExpr
10925
 *
10926
 * Compile an AND expression.
10927
 *
10928
 */
10929
static void
10930
69.2k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10931
69.2k
    xmlXPathCompEqualityExpr(ctxt);
10932
69.2k
    CHECK_ERROR;
10933
54.8k
    SKIP_BLANKS;
10934
56.4k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10935
1.78k
  int op1 = ctxt->comp->last;
10936
1.78k
        SKIP(3);
10937
1.78k
  SKIP_BLANKS;
10938
1.78k
        xmlXPathCompEqualityExpr(ctxt);
10939
1.78k
  CHECK_ERROR;
10940
1.64k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10941
1.64k
  SKIP_BLANKS;
10942
1.64k
    }
10943
54.8k
}
10944
10945
/**
10946
 * xmlXPathCompileExpr:
10947
 * @ctxt:  the XPath Parser context
10948
 *
10949
 *  [14]   Expr ::=   OrExpr
10950
 *  [21]   OrExpr ::=   AndExpr
10951
 *                 | OrExpr 'or' AndExpr
10952
 *
10953
 * Parse and compile an expression
10954
 */
10955
static void
10956
949k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10957
949k
    xmlXPathContextPtr xpctxt = ctxt->context;
10958
10959
949k
    if (xpctxt != NULL) {
10960
949k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10961
882k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10962
        /*
10963
         * Parsing a single '(' pushes about 10 functions on the call stack
10964
         * before recursing!
10965
         */
10966
67.5k
        xpctxt->depth += 10;
10967
67.5k
    }
10968
10969
67.5k
    xmlXPathCompAndExpr(ctxt);
10970
67.5k
    CHECK_ERROR;
10971
53.1k
    SKIP_BLANKS;
10972
54.7k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10973
1.70k
  int op1 = ctxt->comp->last;
10974
1.70k
        SKIP(2);
10975
1.70k
  SKIP_BLANKS;
10976
1.70k
        xmlXPathCompAndExpr(ctxt);
10977
1.70k
  CHECK_ERROR;
10978
1.55k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10979
1.55k
  SKIP_BLANKS;
10980
1.55k
    }
10981
53.0k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10982
  /* more ops could be optimized too */
10983
  /*
10984
  * This is the main place to eliminate sorting for
10985
  * operations which don't require a sorted node-set.
10986
  * E.g. count().
10987
  */
10988
26.5k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10989
26.5k
    }
10990
10991
53.0k
    if (xpctxt != NULL)
10992
53.0k
        xpctxt->depth -= 10;
10993
53.0k
}
10994
10995
/**
10996
 * xmlXPathCompPredicate:
10997
 * @ctxt:  the XPath Parser context
10998
 * @filter:  act as a filter
10999
 *
11000
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11001
 *  [9]   PredicateExpr ::=   Expr
11002
 *
11003
 * Compile a predicate expression
11004
 */
11005
static void
11006
900k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11007
900k
    int op1 = ctxt->comp->last;
11008
11009
900k
    SKIP_BLANKS;
11010
900k
    if (CUR != '[') {
11011
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11012
0
    }
11013
900k
    NEXT;
11014
900k
    SKIP_BLANKS;
11015
11016
900k
    ctxt->comp->last = -1;
11017
    /*
11018
    * This call to xmlXPathCompileExpr() will deactivate sorting
11019
    * of the predicate result.
11020
    * TODO: Sorting is still activated for filters, since I'm not
11021
    *  sure if needed. Normally sorting should not be needed, since
11022
    *  a filter can only diminish the number of items in a sequence,
11023
    *  but won't change its order; so if the initial sequence is sorted,
11024
    *  subsequent sorting is not needed.
11025
    */
11026
900k
    if (! filter)
11027
683k
  xmlXPathCompileExpr(ctxt, 0);
11028
217k
    else
11029
217k
  xmlXPathCompileExpr(ctxt, 1);
11030
900k
    CHECK_ERROR;
11031
11032
11.8k
    if (CUR != ']') {
11033
215
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11034
0
    }
11035
11036
11.5k
    if (filter)
11037
3.17k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11038
8.41k
    else
11039
8.41k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11040
11041
11.5k
    NEXT;
11042
11.5k
    SKIP_BLANKS;
11043
11.5k
}
11044
11045
/**
11046
 * xmlXPathCompNodeTest:
11047
 * @ctxt:  the XPath Parser context
11048
 * @test:  pointer to a xmlXPathTestVal
11049
 * @type:  pointer to a xmlXPathTypeVal
11050
 * @prefix:  placeholder for a possible name prefix
11051
 *
11052
 * [7] NodeTest ::=   NameTest
11053
 *        | NodeType '(' ')'
11054
 *        | 'processing-instruction' '(' Literal ')'
11055
 *
11056
 * [37] NameTest ::=  '*'
11057
 *        | NCName ':' '*'
11058
 *        | QName
11059
 * [38] NodeType ::= 'comment'
11060
 *       | 'text'
11061
 *       | 'processing-instruction'
11062
 *       | 'node'
11063
 *
11064
 * Returns the name found and updates @test, @type and @prefix appropriately
11065
 */
11066
static xmlChar *
11067
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11068
               xmlXPathTypeVal *type, xmlChar **prefix,
11069
249k
         xmlChar *name) {
11070
249k
    int blanks;
11071
11072
249k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11073
0
  STRANGE;
11074
0
  return(NULL);
11075
0
    }
11076
249k
    *type = (xmlXPathTypeVal) 0;
11077
249k
    *test = (xmlXPathTestVal) 0;
11078
249k
    *prefix = NULL;
11079
249k
    SKIP_BLANKS;
11080
11081
249k
    if ((name == NULL) && (CUR == '*')) {
11082
  /*
11083
   * All elements
11084
   */
11085
101k
  NEXT;
11086
101k
  *test = NODE_TEST_ALL;
11087
101k
  return(NULL);
11088
101k
    }
11089
11090
147k
    if (name == NULL)
11091
6.87k
  name = xmlXPathParseNCName(ctxt);
11092
147k
    if (name == NULL) {
11093
774
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11094
0
    }
11095
11096
146k
    blanks = IS_BLANK_CH(CUR);
11097
146k
    SKIP_BLANKS;
11098
146k
    if (CUR == '(') {
11099
4.12k
  NEXT;
11100
  /*
11101
   * NodeType or PI search
11102
   */
11103
4.12k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11104
254
      *type = NODE_TYPE_COMMENT;
11105
3.87k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11106
2.61k
      *type = NODE_TYPE_NODE;
11107
1.26k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11108
337
      *type = NODE_TYPE_PI;
11109
926
  else if (xmlStrEqual(name, BAD_CAST "text"))
11110
779
      *type = NODE_TYPE_TEXT;
11111
147
  else {
11112
147
      if (name != NULL)
11113
147
    xmlFree(name);
11114
147
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11115
0
  }
11116
11117
3.98k
  *test = NODE_TEST_TYPE;
11118
11119
3.98k
  SKIP_BLANKS;
11120
3.98k
  if (*type == NODE_TYPE_PI) {
11121
      /*
11122
       * Specific case: search a PI by name.
11123
       */
11124
337
      if (name != NULL)
11125
337
    xmlFree(name);
11126
337
      name = NULL;
11127
337
      if (CUR != ')') {
11128
246
    name = xmlXPathParseLiteral(ctxt);
11129
246
                if (name == NULL) {
11130
132
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11131
0
                }
11132
114
    *test = NODE_TEST_PI;
11133
114
    SKIP_BLANKS;
11134
114
      }
11135
337
  }
11136
3.84k
  if (CUR != ')') {
11137
185
      if (name != NULL)
11138
185
    xmlFree(name);
11139
185
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11140
0
  }
11141
3.66k
  NEXT;
11142
3.66k
  return(name);
11143
3.84k
    }
11144
142k
    *test = NODE_TEST_NAME;
11145
142k
    if ((!blanks) && (CUR == ':')) {
11146
5.11k
  NEXT;
11147
11148
  /*
11149
   * Since currently the parser context don't have a
11150
   * namespace list associated:
11151
   * The namespace name for this prefix can be computed
11152
   * only at evaluation time. The compilation is done
11153
   * outside of any context.
11154
   */
11155
#if 0
11156
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11157
  if (name != NULL)
11158
      xmlFree(name);
11159
  if (*prefix == NULL) {
11160
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11161
  }
11162
#else
11163
5.11k
  *prefix = name;
11164
5.11k
#endif
11165
11166
5.11k
  if (CUR == '*') {
11167
      /*
11168
       * All elements
11169
       */
11170
790
      NEXT;
11171
790
      *test = NODE_TEST_ALL;
11172
790
      return(NULL);
11173
790
  }
11174
11175
4.32k
  name = xmlXPathParseNCName(ctxt);
11176
4.32k
  if (name == NULL) {
11177
207
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11178
0
  }
11179
4.32k
    }
11180
141k
    return(name);
11181
142k
}
11182
11183
/**
11184
 * xmlXPathIsAxisName:
11185
 * @name:  a preparsed name token
11186
 *
11187
 * [6] AxisName ::=   'ancestor'
11188
 *                  | 'ancestor-or-self'
11189
 *                  | 'attribute'
11190
 *                  | 'child'
11191
 *                  | 'descendant'
11192
 *                  | 'descendant-or-self'
11193
 *                  | 'following'
11194
 *                  | 'following-sibling'
11195
 *                  | 'namespace'
11196
 *                  | 'parent'
11197
 *                  | 'preceding'
11198
 *                  | 'preceding-sibling'
11199
 *                  | 'self'
11200
 *
11201
 * Returns the axis or 0
11202
 */
11203
static xmlXPathAxisVal
11204
149k
xmlXPathIsAxisName(const xmlChar *name) {
11205
149k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11206
149k
    switch (name[0]) {
11207
16.0k
  case 'a':
11208
16.0k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11209
252
    ret = AXIS_ANCESTOR;
11210
16.0k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11211
2.43k
    ret = AXIS_ANCESTOR_OR_SELF;
11212
16.0k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11213
111
    ret = AXIS_ATTRIBUTE;
11214
16.0k
      break;
11215
4.11k
  case 'c':
11216
4.11k
      if (xmlStrEqual(name, BAD_CAST "child"))
11217
54
    ret = AXIS_CHILD;
11218
4.11k
      break;
11219
9.96k
  case 'd':
11220
9.96k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11221
33
    ret = AXIS_DESCENDANT;
11222
9.96k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11223
88
    ret = AXIS_DESCENDANT_OR_SELF;
11224
9.96k
      break;
11225
864
  case 'f':
11226
864
      if (xmlStrEqual(name, BAD_CAST "following"))
11227
251
    ret = AXIS_FOLLOWING;
11228
864
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11229
141
    ret = AXIS_FOLLOWING_SIBLING;
11230
864
      break;
11231
7.09k
  case 'n':
11232
7.09k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11233
1.61k
    ret = AXIS_NAMESPACE;
11234
7.09k
      break;
11235
4.22k
  case 'p':
11236
4.22k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11237
76
    ret = AXIS_PARENT;
11238
4.22k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11239
389
    ret = AXIS_PRECEDING;
11240
4.22k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11241
136
    ret = AXIS_PRECEDING_SIBLING;
11242
4.22k
      break;
11243
9.61k
  case 's':
11244
9.61k
      if (xmlStrEqual(name, BAD_CAST "self"))
11245
576
    ret = AXIS_SELF;
11246
9.61k
      break;
11247
149k
    }
11248
149k
    return(ret);
11249
149k
}
11250
11251
/**
11252
 * xmlXPathCompStep:
11253
 * @ctxt:  the XPath Parser context
11254
 *
11255
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11256
 *                  | AbbreviatedStep
11257
 *
11258
 * [12] AbbreviatedStep ::=   '.' | '..'
11259
 *
11260
 * [5] AxisSpecifier ::= AxisName '::'
11261
 *                  | AbbreviatedAxisSpecifier
11262
 *
11263
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11264
 *
11265
 * Modified for XPtr range support as:
11266
 *
11267
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11268
 *                     | AbbreviatedStep
11269
 *                     | 'range-to' '(' Expr ')' Predicate*
11270
 *
11271
 * Compile one step in a Location Path
11272
 * A location step of . is short for self::node(). This is
11273
 * particularly useful in conjunction with //. For example, the
11274
 * location path .//para is short for
11275
 * self::node()/descendant-or-self::node()/child::para
11276
 * and so will select all para descendant elements of the context
11277
 * node.
11278
 * Similarly, a location step of .. is short for parent::node().
11279
 * For example, ../title is short for parent::node()/child::title
11280
 * and so will select the title children of the parent of the context
11281
 * node.
11282
 */
11283
static void
11284
271k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11285
#ifdef LIBXML_XPTR_LOCS_ENABLED
11286
    int rangeto = 0;
11287
    int op2 = -1;
11288
#endif
11289
11290
271k
    SKIP_BLANKS;
11291
271k
    if ((CUR == '.') && (NXT(1) == '.')) {
11292
3.99k
  SKIP(2);
11293
3.99k
  SKIP_BLANKS;
11294
3.99k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11295
3.99k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11296
267k
    } else if (CUR == '.') {
11297
14.0k
  NEXT;
11298
14.0k
  SKIP_BLANKS;
11299
253k
    } else {
11300
253k
  xmlChar *name = NULL;
11301
253k
  xmlChar *prefix = NULL;
11302
253k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11303
253k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11304
253k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11305
253k
  int op1;
11306
11307
  /*
11308
   * The modification needed for XPointer change to the production
11309
   */
11310
#ifdef LIBXML_XPTR_LOCS_ENABLED
11311
  if (ctxt->xptr) {
11312
      name = xmlXPathParseNCName(ctxt);
11313
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11314
                op2 = ctxt->comp->last;
11315
    xmlFree(name);
11316
    SKIP_BLANKS;
11317
    if (CUR != '(') {
11318
        XP_ERROR(XPATH_EXPR_ERROR);
11319
    }
11320
    NEXT;
11321
    SKIP_BLANKS;
11322
11323
    xmlXPathCompileExpr(ctxt, 1);
11324
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11325
    CHECK_ERROR;
11326
11327
    SKIP_BLANKS;
11328
    if (CUR != ')') {
11329
        XP_ERROR(XPATH_EXPR_ERROR);
11330
    }
11331
    NEXT;
11332
    rangeto = 1;
11333
    goto eval_predicates;
11334
      }
11335
  }
11336
#endif
11337
253k
  if (CUR == '*') {
11338
96.9k
      axis = AXIS_CHILD;
11339
156k
  } else {
11340
156k
      if (name == NULL)
11341
156k
    name = xmlXPathParseNCName(ctxt);
11342
156k
      if (name != NULL) {
11343
149k
    axis = xmlXPathIsAxisName(name);
11344
149k
    if (axis != 0) {
11345
6.15k
        SKIP_BLANKS;
11346
6.15k
        if ((CUR == ':') && (NXT(1) == ':')) {
11347
5.78k
      SKIP(2);
11348
5.78k
      xmlFree(name);
11349
5.78k
      name = NULL;
11350
5.78k
        } else {
11351
      /* an element name can conflict with an axis one :-\ */
11352
375
      axis = AXIS_CHILD;
11353
375
        }
11354
143k
    } else {
11355
143k
        axis = AXIS_CHILD;
11356
143k
    }
11357
149k
      } else if (CUR == '@') {
11358
5.42k
    NEXT;
11359
5.42k
    axis = AXIS_ATTRIBUTE;
11360
5.42k
      } else {
11361
1.80k
    axis = AXIS_CHILD;
11362
1.80k
      }
11363
156k
  }
11364
11365
253k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11366
4.74k
            xmlFree(name);
11367
4.74k
            return;
11368
4.74k
        }
11369
11370
249k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11371
249k
  if (test == 0)
11372
921
      return;
11373
11374
248k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11375
248k
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11376
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11377
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11378
0
      }
11379
0
  }
11380
#ifdef DEBUG_STEP
11381
  xmlGenericError(xmlGenericErrorContext,
11382
    "Basis : computing new set\n");
11383
#endif
11384
11385
#ifdef DEBUG_STEP
11386
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11387
  if (ctxt->value == NULL)
11388
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11389
  else if (ctxt->value->nodesetval == NULL)
11390
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11391
  else
11392
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11393
#endif
11394
11395
#ifdef LIBXML_XPTR_LOCS_ENABLED
11396
eval_predicates:
11397
#endif
11398
248k
  op1 = ctxt->comp->last;
11399
248k
  ctxt->comp->last = -1;
11400
11401
248k
  SKIP_BLANKS;
11402
931k
  while (CUR == '[') {
11403
683k
      xmlXPathCompPredicate(ctxt, 0);
11404
683k
  }
11405
11406
#ifdef LIBXML_XPTR_LOCS_ENABLED
11407
  if (rangeto) {
11408
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11409
  } else
11410
#endif
11411
248k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11412
248k
                           test, type, (void *)prefix, (void *)name) == -1) {
11413
0
            xmlFree(prefix);
11414
0
            xmlFree(name);
11415
0
        }
11416
248k
    }
11417
#ifdef DEBUG_STEP
11418
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11419
    if (ctxt->value == NULL)
11420
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11421
    else if (ctxt->value->nodesetval == NULL)
11422
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11423
    else
11424
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11425
    ctxt->value->nodesetval);
11426
#endif
11427
271k
}
11428
11429
/**
11430
 * xmlXPathCompRelativeLocationPath:
11431
 * @ctxt:  the XPath Parser context
11432
 *
11433
 *  [3]   RelativeLocationPath ::=   Step
11434
 *                     | RelativeLocationPath '/' Step
11435
 *                     | AbbreviatedRelativeLocationPath
11436
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11437
 *
11438
 * Compile a relative location path.
11439
 */
11440
static void
11441
xmlXPathCompRelativeLocationPath
11442
172k
(xmlXPathParserContextPtr ctxt) {
11443
172k
    SKIP_BLANKS;
11444
172k
    if ((CUR == '/') && (NXT(1) == '/')) {
11445
1.86k
  SKIP(2);
11446
1.86k
  SKIP_BLANKS;
11447
1.86k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11448
1.86k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11449
170k
    } else if (CUR == '/') {
11450
7.83k
      NEXT;
11451
7.83k
  SKIP_BLANKS;
11452
7.83k
    }
11453
172k
    xmlXPathCompStep(ctxt);
11454
172k
    CHECK_ERROR;
11455
166k
    SKIP_BLANKS;
11456
266k
    while (CUR == '/') {
11457
99.7k
  if ((CUR == '/') && (NXT(1) == '/')) {
11458
32.2k
      SKIP(2);
11459
32.2k
      SKIP_BLANKS;
11460
32.2k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11461
32.2k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11462
32.2k
      xmlXPathCompStep(ctxt);
11463
67.5k
  } else if (CUR == '/') {
11464
67.5k
      NEXT;
11465
67.5k
      SKIP_BLANKS;
11466
67.5k
      xmlXPathCompStep(ctxt);
11467
67.5k
  }
11468
99.7k
  SKIP_BLANKS;
11469
99.7k
    }
11470
166k
}
11471
11472
/**
11473
 * xmlXPathCompLocationPath:
11474
 * @ctxt:  the XPath Parser context
11475
 *
11476
 *  [1]   LocationPath ::=   RelativeLocationPath
11477
 *                     | AbsoluteLocationPath
11478
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11479
 *                     | AbbreviatedAbsoluteLocationPath
11480
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11481
 *                           '//' RelativeLocationPath
11482
 *
11483
 * Compile a location path
11484
 *
11485
 * // is short for /descendant-or-self::node()/. For example,
11486
 * //para is short for /descendant-or-self::node()/child::para and
11487
 * so will select any para element in the document (even a para element
11488
 * that is a document element will be selected by //para since the
11489
 * document element node is a child of the root node); div//para is
11490
 * short for div/descendant-or-self::node()/child::para and so will
11491
 * select all para descendants of div children.
11492
 */
11493
static void
11494
173k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11495
173k
    SKIP_BLANKS;
11496
173k
    if (CUR != '/') {
11497
113k
        xmlXPathCompRelativeLocationPath(ctxt);
11498
113k
    } else {
11499
120k
  while (CUR == '/') {
11500
61.6k
      if ((CUR == '/') && (NXT(1) == '/')) {
11501
30.8k
    SKIP(2);
11502
30.8k
    SKIP_BLANKS;
11503
30.8k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11504
30.8k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11505
30.8k
    xmlXPathCompRelativeLocationPath(ctxt);
11506
30.8k
      } else if (CUR == '/') {
11507
30.8k
    NEXT;
11508
30.8k
    SKIP_BLANKS;
11509
30.8k
    if ((CUR != 0 ) &&
11510
30.8k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11511
30.6k
         (CUR == '@') || (CUR == '*')))
11512
25.9k
        xmlXPathCompRelativeLocationPath(ctxt);
11513
30.8k
      }
11514
61.6k
      CHECK_ERROR;
11515
61.6k
  }
11516
60.2k
    }
11517
173k
}
11518
11519
/************************************************************************
11520
 *                  *
11521
 *    XPath precompiled expression evaluation     *
11522
 *                  *
11523
 ************************************************************************/
11524
11525
static int
11526
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11527
11528
#ifdef DEBUG_STEP
11529
static void
11530
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11531
        int nbNodes)
11532
{
11533
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11534
    switch (op->value) {
11535
        case AXIS_ANCESTOR:
11536
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11537
            break;
11538
        case AXIS_ANCESTOR_OR_SELF:
11539
            xmlGenericError(xmlGenericErrorContext,
11540
                            "axis 'ancestors-or-self' ");
11541
            break;
11542
        case AXIS_ATTRIBUTE:
11543
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11544
            break;
11545
        case AXIS_CHILD:
11546
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11547
            break;
11548
        case AXIS_DESCENDANT:
11549
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11550
            break;
11551
        case AXIS_DESCENDANT_OR_SELF:
11552
            xmlGenericError(xmlGenericErrorContext,
11553
                            "axis 'descendant-or-self' ");
11554
            break;
11555
        case AXIS_FOLLOWING:
11556
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11557
            break;
11558
        case AXIS_FOLLOWING_SIBLING:
11559
            xmlGenericError(xmlGenericErrorContext,
11560
                            "axis 'following-siblings' ");
11561
            break;
11562
        case AXIS_NAMESPACE:
11563
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11564
            break;
11565
        case AXIS_PARENT:
11566
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11567
            break;
11568
        case AXIS_PRECEDING:
11569
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11570
            break;
11571
        case AXIS_PRECEDING_SIBLING:
11572
            xmlGenericError(xmlGenericErrorContext,
11573
                            "axis 'preceding-sibling' ");
11574
            break;
11575
        case AXIS_SELF:
11576
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11577
            break;
11578
    }
11579
    xmlGenericError(xmlGenericErrorContext,
11580
  " context contains %d nodes\n", nbNodes);
11581
    switch (op->value2) {
11582
        case NODE_TEST_NONE:
11583
            xmlGenericError(xmlGenericErrorContext,
11584
                            "           searching for none !!!\n");
11585
            break;
11586
        case NODE_TEST_TYPE:
11587
            xmlGenericError(xmlGenericErrorContext,
11588
                            "           searching for type %d\n", op->value3);
11589
            break;
11590
        case NODE_TEST_PI:
11591
            xmlGenericError(xmlGenericErrorContext,
11592
                            "           searching for PI !!!\n");
11593
            break;
11594
        case NODE_TEST_ALL:
11595
            xmlGenericError(xmlGenericErrorContext,
11596
                            "           searching for *\n");
11597
            break;
11598
        case NODE_TEST_NS:
11599
            xmlGenericError(xmlGenericErrorContext,
11600
                            "           searching for namespace %s\n",
11601
                            op->value5);
11602
            break;
11603
        case NODE_TEST_NAME:
11604
            xmlGenericError(xmlGenericErrorContext,
11605
                            "           searching for name %s\n", op->value5);
11606
            if (op->value4)
11607
                xmlGenericError(xmlGenericErrorContext,
11608
                                "           with namespace %s\n", op->value4);
11609
            break;
11610
    }
11611
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11612
}
11613
#endif /* DEBUG_STEP */
11614
11615
/**
11616
 * xmlXPathNodeSetFilter:
11617
 * @ctxt:  the XPath Parser context
11618
 * @set: the node set to filter
11619
 * @filterOpIndex: the index of the predicate/filter op
11620
 * @minPos: minimum position in the filtered set (1-based)
11621
 * @maxPos: maximum position in the filtered set (1-based)
11622
 * @hasNsNodes: true if the node set may contain namespace nodes
11623
 *
11624
 * Filter a node set, keeping only nodes for which the predicate expression
11625
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11626
 * filtered result.
11627
 */
11628
static void
11629
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11630
          xmlNodeSetPtr set,
11631
          int filterOpIndex,
11632
                      int minPos, int maxPos,
11633
          int hasNsNodes)
11634
172k
{
11635
172k
    xmlXPathContextPtr xpctxt;
11636
172k
    xmlNodePtr oldnode;
11637
172k
    xmlDocPtr olddoc;
11638
172k
    xmlXPathStepOpPtr filterOp;
11639
172k
    int oldcs, oldpp;
11640
172k
    int i, j, pos;
11641
11642
172k
    if ((set == NULL) || (set->nodeNr == 0))
11643
7.94k
        return;
11644
11645
    /*
11646
    * Check if the node set contains a sufficient number of nodes for
11647
    * the requested range.
11648
    */
11649
164k
    if (set->nodeNr < minPos) {
11650
411
        xmlXPathNodeSetClear(set, hasNsNodes);
11651
411
        return;
11652
411
    }
11653
11654
164k
    xpctxt = ctxt->context;
11655
164k
    oldnode = xpctxt->node;
11656
164k
    olddoc = xpctxt->doc;
11657
164k
    oldcs = xpctxt->contextSize;
11658
164k
    oldpp = xpctxt->proximityPosition;
11659
164k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11660
11661
164k
    xpctxt->contextSize = set->nodeNr;
11662
11663
376k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11664
294k
        xmlNodePtr node = set->nodeTab[i];
11665
294k
        int res;
11666
11667
294k
        xpctxt->node = node;
11668
294k
        xpctxt->proximityPosition = i + 1;
11669
11670
        /*
11671
        * Also set the xpath document in case things like
11672
        * key() are evaluated in the predicate.
11673
        *
11674
        * TODO: Get real doc for namespace nodes.
11675
        */
11676
294k
        if ((node->type != XML_NAMESPACE_DECL) &&
11677
294k
            (node->doc != NULL))
11678
275k
            xpctxt->doc = node->doc;
11679
11680
294k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11681
11682
294k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11683
273
            break;
11684
294k
        if (res < 0) {
11685
            /* Shouldn't happen */
11686
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11687
0
            break;
11688
0
        }
11689
11690
294k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11691
153k
            if (i != j) {
11692
1.08k
                set->nodeTab[j] = node;
11693
1.08k
                set->nodeTab[i] = NULL;
11694
1.08k
            }
11695
11696
153k
            j += 1;
11697
153k
        } else {
11698
            /* Remove the entry from the initial node set. */
11699
141k
            set->nodeTab[i] = NULL;
11700
141k
            if (node->type == XML_NAMESPACE_DECL)
11701
11.8k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11702
141k
        }
11703
11704
294k
        if (res != 0) {
11705
153k
            if (pos == maxPos) {
11706
82.6k
                i += 1;
11707
82.6k
                break;
11708
82.6k
            }
11709
11710
70.5k
            pos += 1;
11711
70.5k
        }
11712
294k
    }
11713
11714
    /* Free remaining nodes. */
11715
164k
    if (hasNsNodes) {
11716
60.3k
        for (; i < set->nodeNr; i++) {
11717
52.1k
            xmlNodePtr node = set->nodeTab[i];
11718
52.1k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11719
97
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11720
52.1k
        }
11721
8.19k
    }
11722
11723
164k
    set->nodeNr = j;
11724
11725
    /* If too many elements were removed, shrink table to preserve memory. */
11726
164k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11727
164k
        (set->nodeNr < set->nodeMax / 2)) {
11728
300
        xmlNodePtr *tmp;
11729
300
        int nodeMax = set->nodeNr;
11730
11731
300
        if (nodeMax < XML_NODESET_DEFAULT)
11732
300
            nodeMax = XML_NODESET_DEFAULT;
11733
300
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11734
300
                nodeMax * sizeof(xmlNodePtr));
11735
300
        if (tmp == NULL) {
11736
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11737
300
        } else {
11738
300
            set->nodeTab = tmp;
11739
300
            set->nodeMax = nodeMax;
11740
300
        }
11741
300
    }
11742
11743
164k
    xpctxt->node = oldnode;
11744
164k
    xpctxt->doc = olddoc;
11745
164k
    xpctxt->contextSize = oldcs;
11746
164k
    xpctxt->proximityPosition = oldpp;
11747
164k
}
11748
11749
#ifdef LIBXML_XPTR_LOCS_ENABLED
11750
/**
11751
 * xmlXPathLocationSetFilter:
11752
 * @ctxt:  the XPath Parser context
11753
 * @locset: the location set to filter
11754
 * @filterOpIndex: the index of the predicate/filter op
11755
 * @minPos: minimum position in the filtered set (1-based)
11756
 * @maxPos: maximum position in the filtered set (1-based)
11757
 *
11758
 * Filter a location set, keeping only nodes for which the predicate
11759
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11760
 * in the filtered result.
11761
 */
11762
static void
11763
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11764
              xmlLocationSetPtr locset,
11765
              int filterOpIndex,
11766
                          int minPos, int maxPos)
11767
{
11768
    xmlXPathContextPtr xpctxt;
11769
    xmlNodePtr oldnode;
11770
    xmlDocPtr olddoc;
11771
    xmlXPathStepOpPtr filterOp;
11772
    int oldcs, oldpp;
11773
    int i, j, pos;
11774
11775
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11776
        return;
11777
11778
    xpctxt = ctxt->context;
11779
    oldnode = xpctxt->node;
11780
    olddoc = xpctxt->doc;
11781
    oldcs = xpctxt->contextSize;
11782
    oldpp = xpctxt->proximityPosition;
11783
    filterOp = &ctxt->comp->steps[filterOpIndex];
11784
11785
    xpctxt->contextSize = locset->locNr;
11786
11787
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11788
        xmlNodePtr contextNode = locset->locTab[i]->user;
11789
        int res;
11790
11791
        xpctxt->node = contextNode;
11792
        xpctxt->proximityPosition = i + 1;
11793
11794
        /*
11795
        * Also set the xpath document in case things like
11796
        * key() are evaluated in the predicate.
11797
        *
11798
        * TODO: Get real doc for namespace nodes.
11799
        */
11800
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11801
            (contextNode->doc != NULL))
11802
            xpctxt->doc = contextNode->doc;
11803
11804
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11805
11806
        if (ctxt->error != XPATH_EXPRESSION_OK)
11807
            break;
11808
        if (res < 0) {
11809
            /* Shouldn't happen */
11810
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11811
            break;
11812
        }
11813
11814
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11815
            if (i != j) {
11816
                locset->locTab[j] = locset->locTab[i];
11817
                locset->locTab[i] = NULL;
11818
            }
11819
11820
            j += 1;
11821
        } else {
11822
            /* Remove the entry from the initial location set. */
11823
            xmlXPathFreeObject(locset->locTab[i]);
11824
            locset->locTab[i] = NULL;
11825
        }
11826
11827
        if (res != 0) {
11828
            if (pos == maxPos) {
11829
                i += 1;
11830
                break;
11831
            }
11832
11833
            pos += 1;
11834
        }
11835
    }
11836
11837
    /* Free remaining nodes. */
11838
    for (; i < locset->locNr; i++)
11839
        xmlXPathFreeObject(locset->locTab[i]);
11840
11841
    locset->locNr = j;
11842
11843
    /* If too many elements were removed, shrink table to preserve memory. */
11844
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11845
        (locset->locNr < locset->locMax / 2)) {
11846
        xmlXPathObjectPtr *tmp;
11847
        int locMax = locset->locNr;
11848
11849
        if (locMax < XML_NODESET_DEFAULT)
11850
            locMax = XML_NODESET_DEFAULT;
11851
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11852
                locMax * sizeof(xmlXPathObjectPtr));
11853
        if (tmp == NULL) {
11854
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11855
        } else {
11856
            locset->locTab = tmp;
11857
            locset->locMax = locMax;
11858
        }
11859
    }
11860
11861
    xpctxt->node = oldnode;
11862
    xpctxt->doc = olddoc;
11863
    xpctxt->contextSize = oldcs;
11864
    xpctxt->proximityPosition = oldpp;
11865
}
11866
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11867
11868
/**
11869
 * xmlXPathCompOpEvalPredicate:
11870
 * @ctxt:  the XPath Parser context
11871
 * @op: the predicate op
11872
 * @set: the node set to filter
11873
 * @minPos: minimum position in the filtered set (1-based)
11874
 * @maxPos: maximum position in the filtered set (1-based)
11875
 * @hasNsNodes: true if the node set may contain namespace nodes
11876
 *
11877
 * Filter a node set, keeping only nodes for which the sequence of predicate
11878
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11879
 * in the filtered result.
11880
 */
11881
static void
11882
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11883
          xmlXPathStepOpPtr op,
11884
          xmlNodeSetPtr set,
11885
                            int minPos, int maxPos,
11886
          int hasNsNodes)
11887
168k
{
11888
168k
    if (op->ch1 != -1) {
11889
60.6k
  xmlXPathCompExprPtr comp = ctxt->comp;
11890
  /*
11891
  * Process inner predicates first.
11892
  */
11893
60.6k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11894
0
            xmlGenericError(xmlGenericErrorContext,
11895
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11896
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11897
0
  }
11898
60.6k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11899
60.6k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11900
60.6k
        ctxt->context->depth += 1;
11901
60.6k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11902
60.6k
                                    1, set->nodeNr, hasNsNodes);
11903
60.6k
        ctxt->context->depth -= 1;
11904
60.6k
  CHECK_ERROR;
11905
60.6k
    }
11906
11907
168k
    if (op->ch2 != -1)
11908
168k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11909
168k
}
11910
11911
static int
11912
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11913
          xmlXPathStepOpPtr op,
11914
          int *maxPos)
11915
46.4k
{
11916
11917
46.4k
    xmlXPathStepOpPtr exprOp;
11918
11919
    /*
11920
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11921
    */
11922
11923
    /*
11924
    * If not -1, then ch1 will point to:
11925
    * 1) For predicates (XPATH_OP_PREDICATE):
11926
    *    - an inner predicate operator
11927
    * 2) For filters (XPATH_OP_FILTER):
11928
    *    - an inner filter operator OR
11929
    *    - an expression selecting the node set.
11930
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11931
    */
11932
46.4k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11933
0
  return(0);
11934
11935
46.4k
    if (op->ch2 != -1) {
11936
46.4k
  exprOp = &ctxt->comp->steps[op->ch2];
11937
46.4k
    } else
11938
0
  return(0);
11939
11940
46.4k
    if ((exprOp != NULL) &&
11941
46.4k
  (exprOp->op == XPATH_OP_VALUE) &&
11942
46.4k
  (exprOp->value4 != NULL) &&
11943
46.4k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11944
15.2k
    {
11945
15.2k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11946
11947
  /*
11948
  * We have a "[n]" predicate here.
11949
  * TODO: Unfortunately this simplistic test here is not
11950
  * able to detect a position() predicate in compound
11951
  * expressions like "[@attr = 'a" and position() = 1],
11952
  * and even not the usage of position() in
11953
  * "[position() = 1]"; thus - obviously - a position-range,
11954
  * like it "[position() < 5]", is also not detected.
11955
  * Maybe we could rewrite the AST to ease the optimization.
11956
  */
11957
11958
15.2k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11959
15.1k
      *maxPos = (int) floatval;
11960
15.1k
            if (floatval == (double) *maxPos)
11961
15.1k
                return(1);
11962
15.1k
        }
11963
15.2k
    }
11964
31.3k
    return(0);
11965
46.4k
}
11966
11967
static int
11968
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11969
                           xmlXPathStepOpPtr op,
11970
         xmlNodePtr * first, xmlNodePtr * last,
11971
         int toBool)
11972
738k
{
11973
11974
738k
#define XP_TEST_HIT \
11975
13.6M
    if (hasAxisRange != 0) { \
11976
59.6k
  if (++pos == maxPos) { \
11977
45.1k
      if (addNode(seq, cur) < 0) \
11978
45.1k
          ctxt->error = XPATH_MEMORY_ERROR; \
11979
45.1k
      goto axis_range_end; } \
11980
13.5M
    } else { \
11981
13.5M
  if (addNode(seq, cur) < 0) \
11982
13.5M
      ctxt->error = XPATH_MEMORY_ERROR; \
11983
13.5M
  if (breakOnFirstHit) goto first_hit; }
11984
11985
738k
#define XP_TEST_HIT_NS \
11986
738k
    if (hasAxisRange != 0) { \
11987
1.14k
  if (++pos == maxPos) { \
11988
944
      hasNsNodes = 1; \
11989
944
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11990
944
          ctxt->error = XPATH_MEMORY_ERROR; \
11991
944
  goto axis_range_end; } \
11992
109k
    } else { \
11993
109k
  hasNsNodes = 1; \
11994
109k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11995
109k
      ctxt->error = XPATH_MEMORY_ERROR; \
11996
109k
  if (breakOnFirstHit) goto first_hit; }
11997
11998
738k
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999
738k
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000
738k
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001
738k
    const xmlChar *prefix = op->value4;
12002
738k
    const xmlChar *name = op->value5;
12003
738k
    const xmlChar *URI = NULL;
12004
12005
#ifdef DEBUG_STEP
12006
    int nbMatches = 0, prevMatches = 0;
12007
#endif
12008
738k
    int total = 0, hasNsNodes = 0;
12009
    /* The popped object holding the context nodes */
12010
738k
    xmlXPathObjectPtr obj;
12011
    /* The set of context nodes for the node tests */
12012
738k
    xmlNodeSetPtr contextSeq;
12013
738k
    int contextIdx;
12014
738k
    xmlNodePtr contextNode;
12015
    /* The final resulting node set wrt to all context nodes */
12016
738k
    xmlNodeSetPtr outSeq;
12017
    /*
12018
    * The temporary resulting node set wrt 1 context node.
12019
    * Used to feed predicate evaluation.
12020
    */
12021
738k
    xmlNodeSetPtr seq;
12022
738k
    xmlNodePtr cur;
12023
    /* First predicate operator */
12024
738k
    xmlXPathStepOpPtr predOp;
12025
738k
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12026
738k
    int hasPredicateRange, hasAxisRange, pos;
12027
738k
    int breakOnFirstHit;
12028
12029
738k
    xmlXPathTraversalFunction next = NULL;
12030
738k
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12031
738k
    xmlXPathNodeSetMergeFunction mergeAndClear;
12032
738k
    xmlNodePtr oldContextNode;
12033
738k
    xmlXPathContextPtr xpctxt = ctxt->context;
12034
12035
12036
738k
    CHECK_TYPE0(XPATH_NODESET);
12037
738k
    obj = valuePop(ctxt);
12038
    /*
12039
    * Setup namespaces.
12040
    */
12041
738k
    if (prefix != NULL) {
12042
21.6k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12043
21.6k
        if (URI == NULL) {
12044
136
      xmlXPathReleaseObject(xpctxt, obj);
12045
136
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12046
0
  }
12047
21.6k
    }
12048
    /*
12049
    * Setup axis.
12050
    *
12051
    * MAYBE FUTURE TODO: merging optimizations:
12052
    * - If the nodes to be traversed wrt to the initial nodes and
12053
    *   the current axis cannot overlap, then we could avoid searching
12054
    *   for duplicates during the merge.
12055
    *   But the question is how/when to evaluate if they cannot overlap.
12056
    *   Example: if we know that for two initial nodes, the one is
12057
    *   not in the ancestor-or-self axis of the other, then we could safely
12058
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12059
    *   the descendant-or-self axis.
12060
    */
12061
738k
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12062
738k
    switch (axis) {
12063
1.22k
        case AXIS_ANCESTOR:
12064
1.22k
            first = NULL;
12065
1.22k
            next = xmlXPathNextAncestor;
12066
1.22k
            break;
12067
388
        case AXIS_ANCESTOR_OR_SELF:
12068
388
            first = NULL;
12069
388
            next = xmlXPathNextAncestorOrSelf;
12070
388
            break;
12071
39.3k
        case AXIS_ATTRIBUTE:
12072
39.3k
            first = NULL;
12073
39.3k
      last = NULL;
12074
39.3k
            next = xmlXPathNextAttribute;
12075
39.3k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12076
39.3k
            break;
12077
438k
        case AXIS_CHILD:
12078
438k
      last = NULL;
12079
438k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12080
438k
    (type == NODE_TYPE_NODE))
12081
433k
      {
12082
    /*
12083
    * Optimization if an element node type is 'element'.
12084
    */
12085
433k
    next = xmlXPathNextChildElement;
12086
433k
      } else
12087
4.49k
    next = xmlXPathNextChild;
12088
438k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12089
438k
            break;
12090
106k
        case AXIS_DESCENDANT:
12091
106k
      last = NULL;
12092
106k
            next = xmlXPathNextDescendant;
12093
106k
            break;
12094
100k
        case AXIS_DESCENDANT_OR_SELF:
12095
100k
      last = NULL;
12096
100k
            next = xmlXPathNextDescendantOrSelf;
12097
100k
            break;
12098
1.98k
        case AXIS_FOLLOWING:
12099
1.98k
      last = NULL;
12100
1.98k
            next = xmlXPathNextFollowing;
12101
1.98k
            break;
12102
703
        case AXIS_FOLLOWING_SIBLING:
12103
703
      last = NULL;
12104
703
            next = xmlXPathNextFollowingSibling;
12105
703
            break;
12106
5.73k
        case AXIS_NAMESPACE:
12107
5.73k
            first = NULL;
12108
5.73k
      last = NULL;
12109
5.73k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12110
5.73k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12111
5.73k
            break;
12112
42.5k
        case AXIS_PARENT:
12113
42.5k
            first = NULL;
12114
42.5k
            next = xmlXPathNextParent;
12115
42.5k
            break;
12116
941
        case AXIS_PRECEDING:
12117
941
            first = NULL;
12118
941
            next = xmlXPathNextPrecedingInternal;
12119
941
            break;
12120
611
        case AXIS_PRECEDING_SIBLING:
12121
611
            first = NULL;
12122
611
            next = xmlXPathNextPrecedingSibling;
12123
611
            break;
12124
600
        case AXIS_SELF:
12125
600
            first = NULL;
12126
600
      last = NULL;
12127
600
            next = xmlXPathNextSelf;
12128
600
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12129
600
            break;
12130
738k
    }
12131
12132
#ifdef DEBUG_STEP
12133
    xmlXPathDebugDumpStepAxis(op,
12134
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12135
#endif
12136
12137
738k
    if (next == NULL) {
12138
0
  xmlXPathReleaseObject(xpctxt, obj);
12139
0
        return(0);
12140
0
    }
12141
738k
    contextSeq = obj->nodesetval;
12142
738k
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12143
106k
  xmlXPathReleaseObject(xpctxt, obj);
12144
106k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12145
106k
        return(0);
12146
106k
    }
12147
    /*
12148
    * Predicate optimization ---------------------------------------------
12149
    * If this step has a last predicate, which contains a position(),
12150
    * then we'll optimize (although not exactly "position()", but only
12151
    * the  short-hand form, i.e., "[n]".
12152
    *
12153
    * Example - expression "/foo[parent::bar][1]":
12154
    *
12155
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12156
    *   ROOT                               -- op->ch1
12157
    *   PREDICATE                          -- op->ch2 (predOp)
12158
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12159
    *       SORT
12160
    *         COLLECT  'parent' 'name' 'node' bar
12161
    *           NODE
12162
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12163
    *
12164
    */
12165
632k
    maxPos = 0;
12166
632k
    predOp = NULL;
12167
632k
    hasPredicateRange = 0;
12168
632k
    hasAxisRange = 0;
12169
632k
    if (op->ch2 != -1) {
12170
  /*
12171
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12172
  */
12173
46.4k
  predOp = &ctxt->comp->steps[op->ch2];
12174
46.4k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12175
15.1k
      if (predOp->ch1 != -1) {
12176
    /*
12177
    * Use the next inner predicate operator.
12178
    */
12179
442
    predOp = &ctxt->comp->steps[predOp->ch1];
12180
442
    hasPredicateRange = 1;
12181
14.6k
      } else {
12182
    /*
12183
    * There's no other predicate than the [n] predicate.
12184
    */
12185
14.6k
    predOp = NULL;
12186
14.6k
    hasAxisRange = 1;
12187
14.6k
      }
12188
15.1k
  }
12189
46.4k
    }
12190
632k
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12191
    /*
12192
    * Axis traversal -----------------------------------------------------
12193
    */
12194
    /*
12195
     * 2.3 Node Tests
12196
     *  - For the attribute axis, the principal node type is attribute.
12197
     *  - For the namespace axis, the principal node type is namespace.
12198
     *  - For other axes, the principal node type is element.
12199
     *
12200
     * A node test * is true for any node of the
12201
     * principal node type. For example, child::* will
12202
     * select all element children of the context node
12203
     */
12204
632k
    oldContextNode = xpctxt->node;
12205
632k
    addNode = xmlXPathNodeSetAddUnique;
12206
632k
    outSeq = NULL;
12207
632k
    seq = NULL;
12208
632k
    contextNode = NULL;
12209
632k
    contextIdx = 0;
12210
12211
12212
4.14M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12213
4.14M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12214
3.52M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12215
12216
3.52M
  if (seq == NULL) {
12217
692k
      seq = xmlXPathNodeSetCreate(NULL);
12218
692k
      if (seq == NULL) {
12219
                /* TODO: Propagate memory error. */
12220
0
    total = 0;
12221
0
    goto error;
12222
0
      }
12223
692k
  }
12224
  /*
12225
  * Traverse the axis and test the nodes.
12226
  */
12227
3.52M
  pos = 0;
12228
3.52M
  cur = NULL;
12229
3.52M
  hasNsNodes = 0;
12230
25.2M
        do {
12231
25.2M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12232
23
                goto error;
12233
12234
25.2M
            cur = next(ctxt, cur);
12235
25.2M
            if (cur == NULL)
12236
3.46M
                break;
12237
12238
      /*
12239
      * QUESTION TODO: What does the "first" and "last" stuff do?
12240
      */
12241
21.8M
            if ((first != NULL) && (*first != NULL)) {
12242
49
    if (*first == cur)
12243
15
        break;
12244
34
    if (((total % 256) == 0) &&
12245
34
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12246
34
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12247
#else
12248
        (xmlXPathCmpNodes(*first, cur) >= 0))
12249
#endif
12250
1
    {
12251
1
        break;
12252
1
    }
12253
34
      }
12254
21.8M
      if ((last != NULL) && (*last != NULL)) {
12255
0
    if (*last == cur)
12256
0
        break;
12257
0
    if (((total % 256) == 0) &&
12258
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12259
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12260
#else
12261
        (xmlXPathCmpNodes(cur, *last) >= 0))
12262
#endif
12263
0
    {
12264
0
        break;
12265
0
    }
12266
0
      }
12267
12268
21.8M
            total++;
12269
12270
#ifdef DEBUG_STEP
12271
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12272
#endif
12273
12274
21.8M
      switch (test) {
12275
0
                case NODE_TEST_NONE:
12276
0
        total = 0;
12277
0
                    STRANGE
12278
0
        goto error;
12279
17.0M
                case NODE_TEST_TYPE:
12280
17.0M
        if (type == NODE_TYPE_NODE) {
12281
8.99M
      switch (cur->type) {
12282
51.3k
          case XML_DOCUMENT_NODE:
12283
51.3k
          case XML_HTML_DOCUMENT_NODE:
12284
4.13M
          case XML_ELEMENT_NODE:
12285
4.13M
          case XML_ATTRIBUTE_NODE:
12286
4.24M
          case XML_PI_NODE:
12287
4.36M
          case XML_COMMENT_NODE:
12288
4.43M
          case XML_CDATA_SECTION_NODE:
12289
8.92M
          case XML_TEXT_NODE:
12290
8.92M
        XP_TEST_HIT
12291
8.92M
        break;
12292
8.92M
          case XML_NAMESPACE_DECL: {
12293
68.1k
        if (axis == AXIS_NAMESPACE) {
12294
385
            XP_TEST_HIT_NS
12295
67.7k
        } else {
12296
67.7k
                              hasNsNodes = 1;
12297
67.7k
            XP_TEST_HIT
12298
67.7k
        }
12299
68.0k
        break;
12300
68.1k
                            }
12301
68.0k
          default:
12302
0
        break;
12303
8.99M
      }
12304
8.99M
        } else if (cur->type == (xmlElementType) type) {
12305
3.86M
      if (cur->type == XML_NAMESPACE_DECL)
12306
0
          XP_TEST_HIT_NS
12307
3.86M
      else
12308
3.86M
          XP_TEST_HIT
12309
4.17M
        } else if ((type == NODE_TYPE_TEXT) &&
12310
4.17M
       (cur->type == XML_CDATA_SECTION_NODE))
12311
2.31k
        {
12312
2.31k
      XP_TEST_HIT
12313
2.31k
        }
12314
17.0M
        break;
12315
17.0M
                case NODE_TEST_PI:
12316
41
                    if ((cur->type == XML_PI_NODE) &&
12317
41
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12318
0
        {
12319
0
      XP_TEST_HIT
12320
0
                    }
12321
41
                    break;
12322
1.53M
                case NODE_TEST_ALL:
12323
1.53M
                    if (axis == AXIS_ATTRIBUTE) {
12324
106k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12325
106k
      {
12326
106k
                            if (prefix == NULL)
12327
106k
          {
12328
106k
        XP_TEST_HIT
12329
106k
                            } else if ((cur->ns != NULL) &&
12330
221
        (xmlStrEqual(URI, cur->ns->href)))
12331
0
          {
12332
0
        XP_TEST_HIT
12333
0
                            }
12334
106k
                        }
12335
1.42M
                    } else if (axis == AXIS_NAMESPACE) {
12336
107k
                        if (cur->type == XML_NAMESPACE_DECL)
12337
107k
      {
12338
107k
          XP_TEST_HIT_NS
12339
107k
                        }
12340
1.31M
                    } else {
12341
1.31M
                        if (cur->type == XML_ELEMENT_NODE) {
12342
586k
                            if (prefix == NULL)
12343
581k
          {
12344
581k
        XP_TEST_HIT
12345
12346
581k
                            } else if ((cur->ns != NULL) &&
12347
5.00k
        (xmlStrEqual(URI, cur->ns->href)))
12348
1.62k
          {
12349
1.62k
        XP_TEST_HIT
12350
1.62k
                            }
12351
586k
                        }
12352
1.31M
                    }
12353
1.48M
                    break;
12354
1.48M
                case NODE_TEST_NS:{
12355
0
                        TODO;
12356
0
                        break;
12357
1.53M
                    }
12358
3.25M
                case NODE_TEST_NAME:
12359
3.25M
                    if (axis == AXIS_ATTRIBUTE) {
12360
24.0k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12361
0
          break;
12362
3.23M
        } else if (axis == AXIS_NAMESPACE) {
12363
25.2k
                        if (cur->type != XML_NAMESPACE_DECL)
12364
0
          break;
12365
3.20M
        } else {
12366
3.20M
            if (cur->type != XML_ELEMENT_NODE)
12367
2.10M
          break;
12368
3.20M
        }
12369
1.14M
                    switch (cur->type) {
12370
1.09M
                        case XML_ELEMENT_NODE:
12371
1.09M
                            if (xmlStrEqual(name, cur->name)) {
12372
101k
                                if (prefix == NULL) {
12373
88.9k
                                    if (cur->ns == NULL)
12374
54.1k
            {
12375
54.1k
          XP_TEST_HIT
12376
54.1k
                                    }
12377
88.9k
                                } else {
12378
12.7k
                                    if ((cur->ns != NULL) &&
12379
12.7k
                                        (xmlStrEqual(URI, cur->ns->href)))
12380
6.27k
            {
12381
6.27k
          XP_TEST_HIT
12382
6.27k
                                    }
12383
12.7k
                                }
12384
101k
                            }
12385
1.09M
                            break;
12386
1.09M
                        case XML_ATTRIBUTE_NODE:{
12387
24.0k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389
24.0k
                                if (xmlStrEqual(name, attr->name)) {
12390
9.08k
                                    if (prefix == NULL) {
12391
9.07k
                                        if ((attr->ns == NULL) ||
12392
9.07k
                                            (attr->ns->prefix == NULL))
12393
9.07k
          {
12394
9.07k
              XP_TEST_HIT
12395
9.07k
                                        }
12396
9.07k
                                    } else {
12397
15
                                        if ((attr->ns != NULL) &&
12398
15
                                            (xmlStrEqual(URI,
12399
0
                attr->ns->href)))
12400
0
          {
12401
0
              XP_TEST_HIT
12402
0
                                        }
12403
15
                                    }
12404
9.08k
                                }
12405
23.8k
                                break;
12406
24.0k
                            }
12407
25.2k
                        case XML_NAMESPACE_DECL:
12408
25.2k
                            if (cur->type == XML_NAMESPACE_DECL) {
12409
25.2k
                                xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411
25.2k
                                if ((ns->prefix != NULL) && (name != NULL)
12412
25.2k
                                    && (xmlStrEqual(ns->prefix, name)))
12413
2.94k
        {
12414
2.94k
            XP_TEST_HIT_NS
12415
2.94k
                                }
12416
25.2k
                            }
12417
25.1k
                            break;
12418
25.1k
                        default:
12419
0
                            break;
12420
1.14M
                    }
12421
1.14M
                    break;
12422
21.8M
      } /* switch(test) */
12423
21.8M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12424
12425
3.46M
  goto apply_predicates;
12426
12427
3.46M
axis_range_end: /* ----------------------------------------------------- */
12428
  /*
12429
  * We have a "/foo[n]", and position() = n was reached.
12430
  * Note that we can have as well "/foo/::parent::foo[1]", so
12431
  * a duplicate-aware merge is still needed.
12432
  * Merge with the result.
12433
  */
12434
46.1k
  if (outSeq == NULL) {
12435
7.85k
      outSeq = seq;
12436
7.85k
      seq = NULL;
12437
7.85k
  } else
12438
            /* TODO: Check memory error. */
12439
38.2k
      outSeq = mergeAndClear(outSeq, seq);
12440
  /*
12441
  * Break if only a true/false result was requested.
12442
  */
12443
46.1k
  if (toBool)
12444
133
      break;
12445
45.9k
  continue;
12446
12447
45.9k
first_hit: /* ---------------------------------------------------------- */
12448
  /*
12449
  * Break if only a true/false result was requested and
12450
  * no predicates existed and a node test succeeded.
12451
  */
12452
6.27k
  if (outSeq == NULL) {
12453
6.27k
      outSeq = seq;
12454
6.27k
      seq = NULL;
12455
6.27k
  } else
12456
            /* TODO: Check memory error. */
12457
0
      outSeq = mergeAndClear(outSeq, seq);
12458
6.27k
  break;
12459
12460
#ifdef DEBUG_STEP
12461
  if (seq != NULL)
12462
      nbMatches += seq->nodeNr;
12463
#endif
12464
12465
3.46M
apply_predicates: /* --------------------------------------------------- */
12466
3.46M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12467
0
      goto error;
12468
12469
        /*
12470
  * Apply predicates.
12471
  */
12472
3.46M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12473
      /*
12474
      * E.g. when we have a "/foo[some expression][n]".
12475
      */
12476
      /*
12477
      * QUESTION TODO: The old predicate evaluation took into
12478
      *  account location-sets.
12479
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12480
      *  Do we expect such a set here?
12481
      *  All what I learned now from the evaluation semantics
12482
      *  does not indicate that a location-set will be processed
12483
      *  here, so this looks OK.
12484
      */
12485
      /*
12486
      * Iterate over all predicates, starting with the outermost
12487
      * predicate.
12488
      * TODO: Problem: we cannot execute the inner predicates first
12489
      *  since we cannot go back *up* the operator tree!
12490
      *  Options we have:
12491
      *  1) Use of recursive functions (like is it currently done
12492
      *     via xmlXPathCompOpEval())
12493
      *  2) Add a predicate evaluation information stack to the
12494
      *     context struct
12495
      *  3) Change the way the operators are linked; we need a
12496
      *     "parent" field on xmlXPathStepOp
12497
      *
12498
      * For the moment, I'll try to solve this with a recursive
12499
      * function: xmlXPathCompOpEvalPredicate().
12500
      */
12501
108k
      if (hasPredicateRange != 0)
12502
2.63k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12503
2.63k
              hasNsNodes);
12504
105k
      else
12505
105k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12506
105k
              hasNsNodes);
12507
12508
108k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12509
241
    total = 0;
12510
241
    goto error;
12511
241
      }
12512
108k
        }
12513
12514
3.46M
        if (seq->nodeNr > 0) {
12515
      /*
12516
      * Add to result set.
12517
      */
12518
1.03M
      if (outSeq == NULL) {
12519
213k
    outSeq = seq;
12520
213k
    seq = NULL;
12521
824k
      } else {
12522
                /* TODO: Check memory error. */
12523
824k
    outSeq = mergeAndClear(outSeq, seq);
12524
824k
      }
12525
12526
1.03M
            if (toBool)
12527
623
                break;
12528
1.03M
  }
12529
3.46M
    }
12530
12531
632k
error:
12532
632k
    if ((obj->boolval) && (obj->user != NULL)) {
12533
  /*
12534
  * QUESTION TODO: What does this do and why?
12535
  * TODO: Do we have to do this also for the "error"
12536
  * cleanup further down?
12537
  */
12538
0
  ctxt->value->boolval = 1;
12539
0
  ctxt->value->user = obj->user;
12540
0
  obj->user = NULL;
12541
0
  obj->boolval = 0;
12542
0
    }
12543
632k
    xmlXPathReleaseObject(xpctxt, obj);
12544
12545
    /*
12546
    * Ensure we return at least an empty set.
12547
    */
12548
632k
    if (outSeq == NULL) {
12549
404k
  if ((seq != NULL) && (seq->nodeNr == 0))
12550
404k
      outSeq = seq;
12551
5
  else
12552
            /* TODO: Check memory error. */
12553
5
      outSeq = xmlXPathNodeSetCreate(NULL);
12554
404k
    }
12555
632k
    if ((seq != NULL) && (seq != outSeq)) {
12556
59.8k
   xmlXPathFreeNodeSet(seq);
12557
59.8k
    }
12558
    /*
12559
    * Hand over the result. Better to push the set also in
12560
    * case of errors.
12561
    */
12562
632k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563
    /*
12564
    * Reset the context node.
12565
    */
12566
632k
    xpctxt->node = oldContextNode;
12567
    /*
12568
    * When traversing the namespace axis in "toBool" mode, it's
12569
    * possible that tmpNsList wasn't freed.
12570
    */
12571
632k
    if (xpctxt->tmpNsList != NULL) {
12572
98
        xmlFree(xpctxt->tmpNsList);
12573
98
        xpctxt->tmpNsList = NULL;
12574
98
    }
12575
12576
#ifdef DEBUG_STEP
12577
    xmlGenericError(xmlGenericErrorContext,
12578
  "\nExamined %d nodes, found %d nodes at that step\n",
12579
  total, nbMatches);
12580
#endif
12581
12582
632k
    return(total);
12583
632k
}
12584
12585
static int
12586
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12587
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12588
12589
/**
12590
 * xmlXPathCompOpEvalFirst:
12591
 * @ctxt:  the XPath parser context with the compiled expression
12592
 * @op:  an XPath compiled operation
12593
 * @first:  the first elem found so far
12594
 *
12595
 * Evaluate the Precompiled XPath operation searching only the first
12596
 * element in document order
12597
 *
12598
 * Returns the number of examined objects.
12599
 */
12600
static int
12601
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12602
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12603
1.37k
{
12604
1.37k
    int total = 0, cur;
12605
1.37k
    xmlXPathCompExprPtr comp;
12606
1.37k
    xmlXPathObjectPtr arg1, arg2;
12607
12608
1.37k
    CHECK_ERROR0;
12609
1.37k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12610
0
        return(0);
12611
1.37k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12612
1.37k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12613
1.37k
    ctxt->context->depth += 1;
12614
1.37k
    comp = ctxt->comp;
12615
1.37k
    switch (op->op) {
12616
0
        case XPATH_OP_END:
12617
0
            break;
12618
111
        case XPATH_OP_UNION:
12619
111
            total =
12620
111
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12621
111
                                        first);
12622
111
      CHECK_ERROR0;
12623
79
            if ((ctxt->value != NULL)
12624
79
                && (ctxt->value->type == XPATH_NODESET)
12625
79
                && (ctxt->value->nodesetval != NULL)
12626
79
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12627
                /*
12628
                 * limit tree traversing to first node in the result
12629
                 */
12630
    /*
12631
    * OPTIMIZE TODO: This implicitly sorts
12632
    *  the result, even if not needed. E.g. if the argument
12633
    *  of the count() function, no sorting is needed.
12634
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12635
    *  already sorted?
12636
    */
12637
20
    if (ctxt->value->nodesetval->nodeNr > 1)
12638
13
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12639
20
                *first = ctxt->value->nodesetval->nodeTab[0];
12640
20
            }
12641
79
            cur =
12642
79
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12643
79
                                        first);
12644
79
      CHECK_ERROR0;
12645
12646
69
            arg2 = valuePop(ctxt);
12647
69
            arg1 = valuePop(ctxt);
12648
69
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12649
69
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12650
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12651
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12652
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12653
0
            }
12654
69
            if ((ctxt->context->opLimit != 0) &&
12655
69
                (((arg1->nodesetval != NULL) &&
12656
69
                  (xmlXPathCheckOpLimit(ctxt,
12657
52
                                        arg1->nodesetval->nodeNr) < 0)) ||
12658
69
                 ((arg2->nodesetval != NULL) &&
12659
69
                  (xmlXPathCheckOpLimit(ctxt,
12660
45
                                        arg2->nodesetval->nodeNr) < 0)))) {
12661
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12662
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12663
0
                break;
12664
0
            }
12665
12666
            /* TODO: Check memory error. */
12667
69
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668
69
                                                    arg2->nodesetval);
12669
69
            valuePush(ctxt, arg1);
12670
69
      xmlXPathReleaseObject(ctxt->context, arg2);
12671
            /* optimizer */
12672
69
      if (total > cur)
12673
40
    xmlXPathCompSwap(op);
12674
69
            total += cur;
12675
69
            break;
12676
4
        case XPATH_OP_ROOT:
12677
4
            xmlXPathRoot(ctxt);
12678
4
            break;
12679
5
        case XPATH_OP_NODE:
12680
5
            if (op->ch1 != -1)
12681
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12682
5
      CHECK_ERROR0;
12683
5
            if (op->ch2 != -1)
12684
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12685
5
      CHECK_ERROR0;
12686
5
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12687
5
    ctxt->context->node));
12688
5
            break;
12689
211
        case XPATH_OP_COLLECT:{
12690
211
                if (op->ch1 == -1)
12691
0
                    break;
12692
12693
211
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12694
211
    CHECK_ERROR0;
12695
12696
209
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12697
209
                break;
12698
211
            }
12699
3
        case XPATH_OP_VALUE:
12700
3
            valuePush(ctxt,
12701
3
                      xmlXPathCacheObjectCopy(ctxt->context,
12702
3
      (xmlXPathObjectPtr) op->value4));
12703
3
            break;
12704
482
        case XPATH_OP_SORT:
12705
482
            if (op->ch1 != -1)
12706
482
                total +=
12707
482
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12708
482
                                            first);
12709
482
      CHECK_ERROR0;
12710
455
            if ((ctxt->value != NULL)
12711
455
                && (ctxt->value->type == XPATH_NODESET)
12712
455
                && (ctxt->value->nodesetval != NULL)
12713
455
    && (ctxt->value->nodesetval->nodeNr > 1))
12714
34
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12715
455
            break;
12716
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12717
222
  case XPATH_OP_FILTER:
12718
222
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12719
222
            break;
12720
0
#endif
12721
338
        default:
12722
338
            total += xmlXPathCompOpEval(ctxt, op);
12723
338
            break;
12724
1.37k
    }
12725
12726
1.30k
    ctxt->context->depth -= 1;
12727
1.30k
    return(total);
12728
1.37k
}
12729
12730
/**
12731
 * xmlXPathCompOpEvalLast:
12732
 * @ctxt:  the XPath parser context with the compiled expression
12733
 * @op:  an XPath compiled operation
12734
 * @last:  the last elem found so far
12735
 *
12736
 * Evaluate the Precompiled XPath operation searching only the last
12737
 * element in document order
12738
 *
12739
 * Returns the number of nodes traversed
12740
 */
12741
static int
12742
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12743
                       xmlNodePtr * last)
12744
1.58k
{
12745
1.58k
    int total = 0, cur;
12746
1.58k
    xmlXPathCompExprPtr comp;
12747
1.58k
    xmlXPathObjectPtr arg1, arg2;
12748
12749
1.58k
    CHECK_ERROR0;
12750
1.58k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12751
0
        return(0);
12752
1.58k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12753
1.58k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12754
1.58k
    ctxt->context->depth += 1;
12755
1.58k
    comp = ctxt->comp;
12756
1.58k
    switch (op->op) {
12757
0
        case XPATH_OP_END:
12758
0
            break;
12759
80
        case XPATH_OP_UNION:
12760
80
            total =
12761
80
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12762
80
      CHECK_ERROR0;
12763
78
            if ((ctxt->value != NULL)
12764
78
                && (ctxt->value->type == XPATH_NODESET)
12765
78
                && (ctxt->value->nodesetval != NULL)
12766
78
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767
                /*
12768
                 * limit tree traversing to first node in the result
12769
                 */
12770
24
    if (ctxt->value->nodesetval->nodeNr > 1)
12771
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12772
24
                *last =
12773
24
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12774
24
                                                     nodesetval->nodeNr -
12775
24
                                                     1];
12776
24
            }
12777
78
            cur =
12778
78
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12779
78
      CHECK_ERROR0;
12780
77
            if ((ctxt->value != NULL)
12781
77
                && (ctxt->value->type == XPATH_NODESET)
12782
77
                && (ctxt->value->nodesetval != NULL)
12783
77
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12784
29
            }
12785
12786
77
            arg2 = valuePop(ctxt);
12787
77
            arg1 = valuePop(ctxt);
12788
77
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12789
77
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12790
2
          xmlXPathReleaseObject(ctxt->context, arg1);
12791
2
          xmlXPathReleaseObject(ctxt->context, arg2);
12792
2
                XP_ERROR0(XPATH_INVALID_TYPE);
12793
0
            }
12794
75
            if ((ctxt->context->opLimit != 0) &&
12795
75
                (((arg1->nodesetval != NULL) &&
12796
75
                  (xmlXPathCheckOpLimit(ctxt,
12797
55
                                        arg1->nodesetval->nodeNr) < 0)) ||
12798
75
                 ((arg2->nodesetval != NULL) &&
12799
75
                  (xmlXPathCheckOpLimit(ctxt,
12800
65
                                        arg2->nodesetval->nodeNr) < 0)))) {
12801
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12802
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12803
0
                break;
12804
0
            }
12805
12806
            /* TODO: Check memory error. */
12807
75
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12808
75
                                                    arg2->nodesetval);
12809
75
            valuePush(ctxt, arg1);
12810
75
      xmlXPathReleaseObject(ctxt->context, arg2);
12811
            /* optimizer */
12812
75
      if (total > cur)
12813
4
    xmlXPathCompSwap(op);
12814
75
            total += cur;
12815
75
            break;
12816
0
        case XPATH_OP_ROOT:
12817
0
            xmlXPathRoot(ctxt);
12818
0
            break;
12819
4
        case XPATH_OP_NODE:
12820
4
            if (op->ch1 != -1)
12821
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822
4
      CHECK_ERROR0;
12823
4
            if (op->ch2 != -1)
12824
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12825
4
      CHECK_ERROR0;
12826
4
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12827
4
    ctxt->context->node));
12828
4
            break;
12829
513
        case XPATH_OP_COLLECT:{
12830
513
                if (op->ch1 == -1)
12831
0
                    break;
12832
12833
513
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12834
513
    CHECK_ERROR0;
12835
12836
510
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12837
510
                break;
12838
513
            }
12839
1
        case XPATH_OP_VALUE:
12840
1
            valuePush(ctxt,
12841
1
                      xmlXPathCacheObjectCopy(ctxt->context,
12842
1
      (xmlXPathObjectPtr) op->value4));
12843
1
            break;
12844
713
        case XPATH_OP_SORT:
12845
713
            if (op->ch1 != -1)
12846
713
                total +=
12847
713
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12848
713
                                           last);
12849
713
      CHECK_ERROR0;
12850
694
            if ((ctxt->value != NULL)
12851
694
                && (ctxt->value->type == XPATH_NODESET)
12852
694
                && (ctxt->value->nodesetval != NULL)
12853
694
    && (ctxt->value->nodesetval->nodeNr > 1))
12854
52
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12855
694
            break;
12856
273
        default:
12857
273
            total += xmlXPathCompOpEval(ctxt, op);
12858
273
            break;
12859
1.58k
    }
12860
12861
1.55k
    ctxt->context->depth -= 1;
12862
1.55k
    return (total);
12863
1.58k
}
12864
12865
#ifdef XP_OPTIMIZED_FILTER_FIRST
12866
static int
12867
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12868
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12869
222
{
12870
222
    int total = 0;
12871
222
    xmlXPathCompExprPtr comp;
12872
222
    xmlNodeSetPtr set;
12873
12874
222
    CHECK_ERROR0;
12875
222
    comp = ctxt->comp;
12876
    /*
12877
    * Optimization for ()[last()] selection i.e. the last elem
12878
    */
12879
222
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12880
222
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12881
222
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12882
126
  int f = comp->steps[op->ch2].ch1;
12883
12884
126
  if ((f != -1) &&
12885
126
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12886
126
      (comp->steps[f].value5 == NULL) &&
12887
126
      (comp->steps[f].value == 0) &&
12888
126
      (comp->steps[f].value4 != NULL) &&
12889
126
      (xmlStrEqual
12890
116
      (comp->steps[f].value4, BAD_CAST "last"))) {
12891
71
      xmlNodePtr last = NULL;
12892
12893
71
      total +=
12894
71
    xmlXPathCompOpEvalLast(ctxt,
12895
71
        &comp->steps[op->ch1],
12896
71
        &last);
12897
71
      CHECK_ERROR0;
12898
      /*
12899
      * The nodeset should be in document order,
12900
      * Keep only the last value
12901
      */
12902
66
      if ((ctxt->value != NULL) &&
12903
66
    (ctxt->value->type == XPATH_NODESET) &&
12904
66
    (ctxt->value->nodesetval != NULL) &&
12905
66
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12906
66
    (ctxt->value->nodesetval->nodeNr > 1)) {
12907
1
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12908
1
    *first = *(ctxt->value->nodesetval->nodeTab);
12909
1
      }
12910
66
      return (total);
12911
71
  }
12912
126
    }
12913
12914
151
    if (op->ch1 != -1)
12915
151
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12916
151
    CHECK_ERROR0;
12917
119
    if (op->ch2 == -1)
12918
0
  return (total);
12919
119
    if (ctxt->value == NULL)
12920
0
  return (total);
12921
12922
#ifdef LIBXML_XPTR_LOCS_ENABLED
12923
    /*
12924
    * Hum are we filtering the result of an XPointer expression
12925
    */
12926
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12927
        xmlLocationSetPtr locset = ctxt->value->user;
12928
12929
        if (locset != NULL) {
12930
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12931
            if (locset->locNr > 0)
12932
                *first = (xmlNodePtr) locset->locTab[0]->user;
12933
        }
12934
12935
  return (total);
12936
    }
12937
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12938
12939
119
    CHECK_TYPE0(XPATH_NODESET);
12940
114
    set = ctxt->value->nodesetval;
12941
114
    if (set != NULL) {
12942
105
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12943
105
        if (set->nodeNr > 0)
12944
2
            *first = set->nodeTab[0];
12945
105
    }
12946
12947
114
    return (total);
12948
119
}
12949
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12950
12951
/**
12952
 * xmlXPathCompOpEval:
12953
 * @ctxt:  the XPath parser context with the compiled expression
12954
 * @op:  an XPath compiled operation
12955
 *
12956
 * Evaluate the Precompiled XPath operation
12957
 * Returns the number of nodes traversed
12958
 */
12959
static int
12960
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12961
2.33M
{
12962
2.33M
    int total = 0;
12963
2.33M
    int equal, ret;
12964
2.33M
    xmlXPathCompExprPtr comp;
12965
2.33M
    xmlXPathObjectPtr arg1, arg2;
12966
12967
2.33M
    CHECK_ERROR0;
12968
2.33M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12969
0
        return(0);
12970
2.33M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12971
2.33M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12972
2.33M
    ctxt->context->depth += 1;
12973
2.33M
    comp = ctxt->comp;
12974
2.33M
    switch (op->op) {
12975
0
        case XPATH_OP_END:
12976
0
            break;
12977
8.09k
        case XPATH_OP_AND:
12978
8.09k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12979
8.09k
      CHECK_ERROR0;
12980
7.39k
            xmlXPathBooleanFunction(ctxt, 1);
12981
7.39k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12982
660
                break;
12983
6.73k
            arg2 = valuePop(ctxt);
12984
6.73k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12985
6.73k
      if (ctxt->error) {
12986
11
    xmlXPathFreeObject(arg2);
12987
11
    break;
12988
11
      }
12989
6.72k
            xmlXPathBooleanFunction(ctxt, 1);
12990
6.72k
            if (ctxt->value != NULL)
12991
6.72k
                ctxt->value->boolval &= arg2->boolval;
12992
6.72k
      xmlXPathReleaseObject(ctxt->context, arg2);
12993
6.72k
            break;
12994
3.79k
        case XPATH_OP_OR:
12995
3.79k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996
3.79k
      CHECK_ERROR0;
12997
3.37k
            xmlXPathBooleanFunction(ctxt, 1);
12998
3.37k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12999
547
                break;
13000
2.82k
            arg2 = valuePop(ctxt);
13001
2.82k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13002
2.82k
      if (ctxt->error) {
13003
24
    xmlXPathFreeObject(arg2);
13004
24
    break;
13005
24
      }
13006
2.80k
            xmlXPathBooleanFunction(ctxt, 1);
13007
2.80k
            if (ctxt->value != NULL)
13008
2.80k
                ctxt->value->boolval |= arg2->boolval;
13009
2.80k
      xmlXPathReleaseObject(ctxt->context, arg2);
13010
2.80k
            break;
13011
216k
        case XPATH_OP_EQUAL:
13012
216k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013
216k
      CHECK_ERROR0;
13014
215k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13015
215k
      CHECK_ERROR0;
13016
214k
      if (op->value)
13017
210k
    equal = xmlXPathEqualValues(ctxt);
13018
4.06k
      else
13019
4.06k
    equal = xmlXPathNotEqualValues(ctxt);
13020
214k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13021
214k
            break;
13022
96.1k
        case XPATH_OP_CMP:
13023
96.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
96.1k
      CHECK_ERROR0;
13025
95.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13026
95.7k
      CHECK_ERROR0;
13027
95.6k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13028
95.6k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13029
95.6k
            break;
13030
27.5k
        case XPATH_OP_PLUS:
13031
27.5k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13032
27.5k
      CHECK_ERROR0;
13033
27.3k
            if (op->ch2 != -1) {
13034
18.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13035
18.1k
      }
13036
27.3k
      CHECK_ERROR0;
13037
27.2k
            if (op->value == 0)
13038
14.9k
                xmlXPathSubValues(ctxt);
13039
12.3k
            else if (op->value == 1)
13040
3.09k
                xmlXPathAddValues(ctxt);
13041
9.25k
            else if (op->value == 2)
13042
6.61k
                xmlXPathValueFlipSign(ctxt);
13043
2.63k
            else if (op->value == 3) {
13044
2.63k
                CAST_TO_NUMBER;
13045
2.63k
                CHECK_TYPE0(XPATH_NUMBER);
13046
2.63k
            }
13047
27.2k
            break;
13048
252k
        case XPATH_OP_MULT:
13049
252k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13050
252k
      CHECK_ERROR0;
13051
248k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13052
248k
      CHECK_ERROR0;
13053
247k
            if (op->value == 0)
13054
234k
                xmlXPathMultValues(ctxt);
13055
13.6k
            else if (op->value == 1)
13056
6.51k
                xmlXPathDivValues(ctxt);
13057
7.13k
            else if (op->value == 2)
13058
7.13k
                xmlXPathModValues(ctxt);
13059
247k
            break;
13060
43.4k
        case XPATH_OP_UNION:
13061
43.4k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13062
43.4k
      CHECK_ERROR0;
13063
40.2k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13064
40.2k
      CHECK_ERROR0;
13065
13066
40.1k
            arg2 = valuePop(ctxt);
13067
40.1k
            arg1 = valuePop(ctxt);
13068
40.1k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13069
40.1k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13070
38
          xmlXPathReleaseObject(ctxt->context, arg1);
13071
38
          xmlXPathReleaseObject(ctxt->context, arg2);
13072
38
                XP_ERROR0(XPATH_INVALID_TYPE);
13073
0
            }
13074
40.0k
            if ((ctxt->context->opLimit != 0) &&
13075
40.0k
                (((arg1->nodesetval != NULL) &&
13076
40.0k
                  (xmlXPathCheckOpLimit(ctxt,
13077
29.1k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13078
40.0k
                 ((arg2->nodesetval != NULL) &&
13079
40.0k
                  (xmlXPathCheckOpLimit(ctxt,
13080
35.1k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13081
2
          xmlXPathReleaseObject(ctxt->context, arg1);
13082
2
          xmlXPathReleaseObject(ctxt->context, arg2);
13083
2
                break;
13084
2
            }
13085
13086
40.0k
      if ((arg1->nodesetval == NULL) ||
13087
40.0k
    ((arg2->nodesetval != NULL) &&
13088
29.1k
     (arg2->nodesetval->nodeNr != 0)))
13089
25.9k
      {
13090
                /* TODO: Check memory error. */
13091
25.9k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13092
25.9k
              arg2->nodesetval);
13093
25.9k
      }
13094
13095
40.0k
            valuePush(ctxt, arg1);
13096
40.0k
      xmlXPathReleaseObject(ctxt->context, arg2);
13097
40.0k
            break;
13098
171k
        case XPATH_OP_ROOT:
13099
171k
            xmlXPathRoot(ctxt);
13100
171k
            break;
13101
364k
        case XPATH_OP_NODE:
13102
364k
            if (op->ch1 != -1)
13103
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104
364k
      CHECK_ERROR0;
13105
364k
            if (op->ch2 != -1)
13106
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13107
364k
      CHECK_ERROR0;
13108
364k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13109
364k
    ctxt->context->node));
13110
364k
            break;
13111
658k
        case XPATH_OP_COLLECT:{
13112
658k
                if (op->ch1 == -1)
13113
0
                    break;
13114
13115
658k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13116
658k
    CHECK_ERROR0;
13117
13118
658k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13119
658k
                break;
13120
658k
            }
13121
396k
        case XPATH_OP_VALUE:
13122
396k
            valuePush(ctxt,
13123
396k
                      xmlXPathCacheObjectCopy(ctxt->context,
13124
396k
      (xmlXPathObjectPtr) op->value4));
13125
396k
            break;
13126
192
        case XPATH_OP_VARIABLE:{
13127
192
    xmlXPathObjectPtr val;
13128
13129
192
                if (op->ch1 != -1)
13130
0
                    total +=
13131
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13132
192
                if (op->value5 == NULL) {
13133
183
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13134
183
        if (val == NULL)
13135
183
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13136
0
                    valuePush(ctxt, val);
13137
9
    } else {
13138
9
                    const xmlChar *URI;
13139
13140
9
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13141
9
                    if (URI == NULL) {
13142
4
                        xmlGenericError(xmlGenericErrorContext,
13143
4
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13144
4
                                    (char *) op->value4, (char *)op->value5);
13145
4
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13146
4
                        break;
13147
4
                    }
13148
5
        val = xmlXPathVariableLookupNS(ctxt->context,
13149
5
                                                       op->value4, URI);
13150
5
        if (val == NULL)
13151
5
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13152
0
                    valuePush(ctxt, val);
13153
0
                }
13154
0
                break;
13155
192
            }
13156
15.6k
        case XPATH_OP_FUNCTION:{
13157
15.6k
                xmlXPathFunction func;
13158
15.6k
                const xmlChar *oldFunc, *oldFuncURI;
13159
15.6k
    int i;
13160
15.6k
                int frame;
13161
13162
15.6k
                frame = xmlXPathSetFrame(ctxt);
13163
15.6k
                if (op->ch1 != -1) {
13164
10.6k
                    total +=
13165
10.6k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13166
10.6k
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13167
155
                        xmlXPathPopFrame(ctxt, frame);
13168
155
                        break;
13169
155
                    }
13170
10.6k
                }
13171
15.5k
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13172
0
        xmlGenericError(xmlGenericErrorContext,
13173
0
          "xmlXPathCompOpEval: parameter error\n");
13174
0
        ctxt->error = XPATH_INVALID_OPERAND;
13175
0
                    xmlXPathPopFrame(ctxt, frame);
13176
0
        break;
13177
0
    }
13178
35.1k
    for (i = 0; i < op->value; i++) {
13179
19.6k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13180
0
      xmlGenericError(xmlGenericErrorContext,
13181
0
        "xmlXPathCompOpEval: parameter error\n");
13182
0
      ctxt->error = XPATH_INVALID_OPERAND;
13183
0
                        xmlXPathPopFrame(ctxt, frame);
13184
0
      break;
13185
0
        }
13186
19.6k
                }
13187
15.5k
                if (op->cache != NULL)
13188
4.98k
                    func = op->cache;
13189
10.5k
                else {
13190
10.5k
                    const xmlChar *URI = NULL;
13191
13192
10.5k
                    if (op->value5 == NULL)
13193
6.31k
                        func =
13194
6.31k
                            xmlXPathFunctionLookup(ctxt->context,
13195
6.31k
                                                   op->value4);
13196
4.21k
                    else {
13197
4.21k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13198
4.21k
                        if (URI == NULL) {
13199
99
                            xmlGenericError(xmlGenericErrorContext,
13200
99
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13201
99
                                    (char *)op->value4, (char *)op->value5);
13202
99
                            xmlXPathPopFrame(ctxt, frame);
13203
99
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13204
99
                            break;
13205
99
                        }
13206
4.11k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13207
4.11k
                                                        op->value4, URI);
13208
4.11k
                    }
13209
10.4k
                    if (func == NULL) {
13210
414
                        xmlGenericError(xmlGenericErrorContext,
13211
414
                                "xmlXPathCompOpEval: function %s not found\n",
13212
414
                                        (char *)op->value4);
13213
414
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13214
0
                    }
13215
10.0k
                    op->cache = func;
13216
10.0k
                    op->cacheURI = (void *) URI;
13217
10.0k
                }
13218
15.0k
                oldFunc = ctxt->context->function;
13219
15.0k
                oldFuncURI = ctxt->context->functionURI;
13220
15.0k
                ctxt->context->function = op->value4;
13221
15.0k
                ctxt->context->functionURI = op->cacheURI;
13222
15.0k
                func(ctxt, op->value);
13223
15.0k
                ctxt->context->function = oldFunc;
13224
15.0k
                ctxt->context->functionURI = oldFuncURI;
13225
15.0k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13226
15.0k
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13227
14.9k
                    XP_ERROR0(XPATH_STACK_ERROR);
13228
14.9k
                xmlXPathPopFrame(ctxt, frame);
13229
14.9k
                break;
13230
15.0k
            }
13231
20.2k
        case XPATH_OP_ARG:
13232
20.2k
            if (op->ch1 != -1) {
13233
9.55k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13234
9.55k
          CHECK_ERROR0;
13235
9.55k
            }
13236
19.9k
            if (op->ch2 != -1) {
13237
19.9k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238
19.9k
          CHECK_ERROR0;
13239
19.9k
      }
13240
19.7k
            break;
13241
19.7k
        case XPATH_OP_PREDICATE:
13242
6.08k
        case XPATH_OP_FILTER:{
13243
6.08k
                xmlNodeSetPtr set;
13244
13245
                /*
13246
                 * Optimization for ()[1] selection i.e. the first elem
13247
                 */
13248
6.08k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13249
6.08k
#ifdef XP_OPTIMIZED_FILTER_FIRST
13250
        /*
13251
        * FILTER TODO: Can we assume that the inner processing
13252
        *  will result in an ordered list if we have an
13253
        *  XPATH_OP_FILTER?
13254
        *  What about an additional field or flag on
13255
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13256
        *  to assume anything, so it would be more robust and
13257
        *  easier to optimize.
13258
        */
13259
6.08k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13260
6.08k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13261
#else
13262
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13263
#endif
13264
6.08k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13265
1.11k
                    xmlXPathObjectPtr val;
13266
13267
1.11k
                    val = comp->steps[op->ch2].value4;
13268
1.11k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13269
1.11k
                        (val->floatval == 1.0)) {
13270
704
                        xmlNodePtr first = NULL;
13271
13272
704
                        total +=
13273
704
                            xmlXPathCompOpEvalFirst(ctxt,
13274
704
                                                    &comp->steps[op->ch1],
13275
704
                                                    &first);
13276
704
      CHECK_ERROR0;
13277
                        /*
13278
                         * The nodeset should be in document order,
13279
                         * Keep only the first value
13280
                         */
13281
633
                        if ((ctxt->value != NULL) &&
13282
633
                            (ctxt->value->type == XPATH_NODESET) &&
13283
633
                            (ctxt->value->nodesetval != NULL) &&
13284
633
                            (ctxt->value->nodesetval->nodeNr > 1))
13285
34
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13286
34
                                                        1, 1);
13287
633
                        break;
13288
704
                    }
13289
1.11k
                }
13290
                /*
13291
                 * Optimization for ()[last()] selection i.e. the last elem
13292
                 */
13293
5.38k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13294
5.38k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13295
5.38k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13296
4.59k
                    int f = comp->steps[op->ch2].ch1;
13297
13298
4.59k
                    if ((f != -1) &&
13299
4.59k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13300
4.59k
                        (comp->steps[f].value5 == NULL) &&
13301
4.59k
                        (comp->steps[f].value == 0) &&
13302
4.59k
                        (comp->steps[f].value4 != NULL) &&
13303
4.59k
                        (xmlStrEqual
13304
777
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13305
642
                        xmlNodePtr last = NULL;
13306
13307
642
                        total +=
13308
642
                            xmlXPathCompOpEvalLast(ctxt,
13309
642
                                                   &comp->steps[op->ch1],
13310
642
                                                   &last);
13311
642
      CHECK_ERROR0;
13312
                        /*
13313
                         * The nodeset should be in document order,
13314
                         * Keep only the last value
13315
                         */
13316
628
                        if ((ctxt->value != NULL) &&
13317
628
                            (ctxt->value->type == XPATH_NODESET) &&
13318
628
                            (ctxt->value->nodesetval != NULL) &&
13319
628
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13320
628
                            (ctxt->value->nodesetval->nodeNr > 1))
13321
51
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13322
628
                        break;
13323
642
                    }
13324
4.59k
                }
13325
    /*
13326
    * Process inner predicates first.
13327
    * Example "index[parent::book][1]":
13328
    * ...
13329
    *   PREDICATE   <-- we are here "[1]"
13330
    *     PREDICATE <-- process "[parent::book]" first
13331
    *       SORT
13332
    *         COLLECT  'parent' 'name' 'node' book
13333
    *           NODE
13334
    *     ELEM Object is a number : 1
13335
    */
13336
4.73k
                if (op->ch1 != -1)
13337
4.73k
                    total +=
13338
4.73k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339
4.73k
    CHECK_ERROR0;
13340
4.65k
                if (op->ch2 == -1)
13341
0
                    break;
13342
4.65k
                if (ctxt->value == NULL)
13343
0
                    break;
13344
13345
#ifdef LIBXML_XPTR_LOCS_ENABLED
13346
                /*
13347
                 * Hum are we filtering the result of an XPointer expression
13348
                 */
13349
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13350
                    xmlLocationSetPtr locset = ctxt->value->user;
13351
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13352
                                              1, locset->locNr);
13353
                    break;
13354
                }
13355
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13356
13357
4.65k
                CHECK_TYPE0(XPATH_NODESET);
13358
4.61k
                set = ctxt->value->nodesetval;
13359
4.61k
                if (set != NULL)
13360
4.18k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13361
4.18k
                                          1, set->nodeNr, 1);
13362
4.61k
                break;
13363
4.65k
            }
13364
56.1k
        case XPATH_OP_SORT:
13365
56.1k
            if (op->ch1 != -1)
13366
56.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367
56.1k
      CHECK_ERROR0;
13368
54.4k
            if ((ctxt->value != NULL) &&
13369
54.4k
                (ctxt->value->type == XPATH_NODESET) &&
13370
54.4k
                (ctxt->value->nodesetval != NULL) &&
13371
54.4k
    (ctxt->value->nodesetval->nodeNr > 1))
13372
5.40k
      {
13373
5.40k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13374
5.40k
      }
13375
54.4k
            break;
13376
#ifdef LIBXML_XPTR_LOCS_ENABLED
13377
        case XPATH_OP_RANGETO:{
13378
                xmlXPathObjectPtr range;
13379
                xmlXPathObjectPtr res, obj;
13380
                xmlXPathObjectPtr tmp;
13381
                xmlLocationSetPtr newlocset = NULL;
13382
        xmlLocationSetPtr oldlocset;
13383
                xmlNodeSetPtr oldset;
13384
                xmlNodePtr oldnode = ctxt->context->node;
13385
                int oldcs = ctxt->context->contextSize;
13386
                int oldpp = ctxt->context->proximityPosition;
13387
                int i, j;
13388
13389
                if (op->ch1 != -1) {
13390
                    total +=
13391
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13392
                    CHECK_ERROR0;
13393
                }
13394
                if (ctxt->value == NULL) {
13395
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13396
                }
13397
                if (op->ch2 == -1)
13398
                    break;
13399
13400
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13401
                    /*
13402
                     * Extract the old locset, and then evaluate the result of the
13403
                     * expression for all the element in the locset. use it to grow
13404
                     * up a new locset.
13405
                     */
13406
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13407
13408
                    if ((ctxt->value->user == NULL) ||
13409
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13410
                        break;
13411
13412
                    obj = valuePop(ctxt);
13413
                    oldlocset = obj->user;
13414
13415
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13416
13417
                    for (i = 0; i < oldlocset->locNr; i++) {
13418
                        /*
13419
                         * Run the evaluation with a node list made of a
13420
                         * single item in the nodelocset.
13421
                         */
13422
                        ctxt->context->node = oldlocset->locTab[i]->user;
13423
                        ctxt->context->contextSize = oldlocset->locNr;
13424
                        ctxt->context->proximityPosition = i + 1;
13425
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13426
          ctxt->context->node);
13427
                        valuePush(ctxt, tmp);
13428
13429
                        if (op->ch2 != -1)
13430
                            total +=
13431
                                xmlXPathCompOpEval(ctxt,
13432
                                                   &comp->steps[op->ch2]);
13433
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13434
                            xmlXPtrFreeLocationSet(newlocset);
13435
                            goto rangeto_error;
13436
      }
13437
13438
                        res = valuePop(ctxt);
13439
      if (res->type == XPATH_LOCATIONSET) {
13440
          xmlLocationSetPtr rloc =
13441
              (xmlLocationSetPtr)res->user;
13442
          for (j=0; j<rloc->locNr; j++) {
13443
              range = xmlXPtrNewRange(
13444
          oldlocset->locTab[i]->user,
13445
          oldlocset->locTab[i]->index,
13446
          rloc->locTab[j]->user2,
13447
          rloc->locTab[j]->index2);
13448
        if (range != NULL) {
13449
            xmlXPtrLocationSetAdd(newlocset, range);
13450
        }
13451
          }
13452
      } else {
13453
          range = xmlXPtrNewRangeNodeObject(
13454
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13455
                            if (range != NULL) {
13456
                                xmlXPtrLocationSetAdd(newlocset,range);
13457
          }
13458
                        }
13459
13460
                        /*
13461
                         * Cleanup
13462
                         */
13463
                        if (res != NULL) {
13464
          xmlXPathReleaseObject(ctxt->context, res);
13465
      }
13466
                        if (ctxt->value == tmp) {
13467
                            res = valuePop(ctxt);
13468
          xmlXPathReleaseObject(ctxt->context, res);
13469
                        }
13470
                    }
13471
    } else {  /* Not a location set */
13472
                    CHECK_TYPE0(XPATH_NODESET);
13473
                    obj = valuePop(ctxt);
13474
                    oldset = obj->nodesetval;
13475
13476
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13477
13478
                    if (oldset != NULL) {
13479
                        for (i = 0; i < oldset->nodeNr; i++) {
13480
                            /*
13481
                             * Run the evaluation with a node list made of a single item
13482
                             * in the nodeset.
13483
                             */
13484
                            ctxt->context->node = oldset->nodeTab[i];
13485
          /*
13486
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13487
          */
13488
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13489
        ctxt->context->node);
13490
                            valuePush(ctxt, tmp);
13491
13492
                            if (op->ch2 != -1)
13493
                                total +=
13494
                                    xmlXPathCompOpEval(ctxt,
13495
                                                   &comp->steps[op->ch2]);
13496
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13497
                                xmlXPtrFreeLocationSet(newlocset);
13498
                                goto rangeto_error;
13499
          }
13500
13501
                            res = valuePop(ctxt);
13502
                            range =
13503
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13504
                                                      res);
13505
                            if (range != NULL) {
13506
                                xmlXPtrLocationSetAdd(newlocset, range);
13507
                            }
13508
13509
                            /*
13510
                             * Cleanup
13511
                             */
13512
                            if (res != NULL) {
13513
        xmlXPathReleaseObject(ctxt->context, res);
13514
          }
13515
                            if (ctxt->value == tmp) {
13516
                                res = valuePop(ctxt);
13517
        xmlXPathReleaseObject(ctxt->context, res);
13518
                            }
13519
                        }
13520
                    }
13521
                }
13522
13523
                /*
13524
                 * The result is used as the new evaluation set.
13525
                 */
13526
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13527
rangeto_error:
13528
    xmlXPathReleaseObject(ctxt->context, obj);
13529
                ctxt->context->node = oldnode;
13530
                ctxt->context->contextSize = oldcs;
13531
                ctxt->context->proximityPosition = oldpp;
13532
                break;
13533
            }
13534
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13535
0
        default:
13536
0
            xmlGenericError(xmlGenericErrorContext,
13537
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13538
0
            ctxt->error = XPATH_INVALID_OPERAND;
13539
0
            break;
13540
2.33M
    }
13541
13542
2.32M
    ctxt->context->depth -= 1;
13543
2.32M
    return (total);
13544
2.33M
}
13545
13546
/**
13547
 * xmlXPathCompOpEvalToBoolean:
13548
 * @ctxt:  the XPath parser context
13549
 *
13550
 * Evaluates if the expression evaluates to true.
13551
 *
13552
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13553
 */
13554
static int
13555
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13556
          xmlXPathStepOpPtr op,
13557
          int isPredicate)
13558
294k
{
13559
294k
    xmlXPathObjectPtr resObj = NULL;
13560
13561
298k
start:
13562
298k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13563
0
        return(0);
13564
    /* comp = ctxt->comp; */
13565
298k
    switch (op->op) {
13566
0
        case XPATH_OP_END:
13567
0
            return (0);
13568
4.74k
  case XPATH_OP_VALUE:
13569
4.74k
      resObj = (xmlXPathObjectPtr) op->value4;
13570
4.74k
      if (isPredicate)
13571
4.74k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13572
0
      return(xmlXPathCastToBoolean(resObj));
13573
3.51k
  case XPATH_OP_SORT:
13574
      /*
13575
      * We don't need sorting for boolean results. Skip this one.
13576
      */
13577
3.51k
            if (op->ch1 != -1) {
13578
3.51k
    op = &ctxt->comp->steps[op->ch1];
13579
3.51k
    goto start;
13580
3.51k
      }
13581
0
      return(0);
13582
80.1k
  case XPATH_OP_COLLECT:
13583
80.1k
      if (op->ch1 == -1)
13584
0
    return(0);
13585
13586
80.1k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13587
80.1k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13588
22
    return(-1);
13589
13590
80.1k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13591
80.1k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13592
36
    return(-1);
13593
13594
80.1k
      resObj = valuePop(ctxt);
13595
80.1k
      if (resObj == NULL)
13596
0
    return(-1);
13597
80.1k
      break;
13598
209k
  default:
13599
      /*
13600
      * Fallback to call xmlXPathCompOpEval().
13601
      */
13602
209k
      xmlXPathCompOpEval(ctxt, op);
13603
209k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13604
215
    return(-1);
13605
13606
209k
      resObj = valuePop(ctxt);
13607
209k
      if (resObj == NULL)
13608
0
    return(-1);
13609
209k
      break;
13610
298k
    }
13611
13612
289k
    if (resObj) {
13613
289k
  int res;
13614
13615
289k
  if (resObj->type == XPATH_BOOLEAN) {
13616
190k
      res = resObj->boolval;
13617
190k
  } else if (isPredicate) {
13618
      /*
13619
      * For predicates a result of type "number" is handled
13620
      * differently:
13621
      * SPEC XPath 1.0:
13622
      * "If the result is a number, the result will be converted
13623
      *  to true if the number is equal to the context position
13624
      *  and will be converted to false otherwise;"
13625
      */
13626
98.9k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13627
98.9k
  } else {
13628
0
      res = xmlXPathCastToBoolean(resObj);
13629
0
  }
13630
289k
  xmlXPathReleaseObject(ctxt->context, resObj);
13631
289k
  return(res);
13632
289k
    }
13633
13634
0
    return(0);
13635
289k
}
13636
13637
#ifdef XPATH_STREAMING
13638
/**
13639
 * xmlXPathRunStreamEval:
13640
 * @ctxt:  the XPath parser context with the compiled expression
13641
 *
13642
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13643
 */
13644
static int
13645
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13646
          xmlXPathObjectPtr *resultSeq, int toBool)
13647
665
{
13648
665
    int max_depth, min_depth;
13649
665
    int from_root;
13650
665
    int ret, depth;
13651
665
    int eval_all_nodes;
13652
665
    xmlNodePtr cur = NULL, limit = NULL;
13653
665
    xmlStreamCtxtPtr patstream = NULL;
13654
13655
665
    if ((ctxt == NULL) || (comp == NULL))
13656
0
        return(-1);
13657
665
    max_depth = xmlPatternMaxDepth(comp);
13658
665
    if (max_depth == -1)
13659
0
        return(-1);
13660
665
    if (max_depth == -2)
13661
375
        max_depth = 10000;
13662
665
    min_depth = xmlPatternMinDepth(comp);
13663
665
    if (min_depth == -1)
13664
0
        return(-1);
13665
665
    from_root = xmlPatternFromRoot(comp);
13666
665
    if (from_root < 0)
13667
0
        return(-1);
13668
#if 0
13669
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13670
#endif
13671
13672
665
    if (! toBool) {
13673
665
  if (resultSeq == NULL)
13674
0
      return(-1);
13675
665
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13676
665
  if (*resultSeq == NULL)
13677
0
      return(-1);
13678
665
    }
13679
13680
    /*
13681
     * handle the special cases of "/" amd "." being matched
13682
     */
13683
665
    if (min_depth == 0) {
13684
109
  if (from_root) {
13685
      /* Select "/" */
13686
0
      if (toBool)
13687
0
    return(1);
13688
            /* TODO: Check memory error. */
13689
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13690
0
                         (xmlNodePtr) ctxt->doc);
13691
109
  } else {
13692
      /* Select "self::node()" */
13693
109
      if (toBool)
13694
0
    return(1);
13695
            /* TODO: Check memory error. */
13696
109
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13697
109
  }
13698
109
    }
13699
665
    if (max_depth == 0) {
13700
46
  return(0);
13701
46
    }
13702
13703
619
    if (from_root) {
13704
312
        cur = (xmlNodePtr)ctxt->doc;
13705
312
    } else if (ctxt->node != NULL) {
13706
307
        switch (ctxt->node->type) {
13707
13
            case XML_ELEMENT_NODE:
13708
307
            case XML_DOCUMENT_NODE:
13709
307
            case XML_DOCUMENT_FRAG_NODE:
13710
307
            case XML_HTML_DOCUMENT_NODE:
13711
307
          cur = ctxt->node;
13712
307
    break;
13713
0
            case XML_ATTRIBUTE_NODE:
13714
0
            case XML_TEXT_NODE:
13715
0
            case XML_CDATA_SECTION_NODE:
13716
0
            case XML_ENTITY_REF_NODE:
13717
0
            case XML_ENTITY_NODE:
13718
0
            case XML_PI_NODE:
13719
0
            case XML_COMMENT_NODE:
13720
0
            case XML_NOTATION_NODE:
13721
0
            case XML_DTD_NODE:
13722
0
            case XML_DOCUMENT_TYPE_NODE:
13723
0
            case XML_ELEMENT_DECL:
13724
0
            case XML_ATTRIBUTE_DECL:
13725
0
            case XML_ENTITY_DECL:
13726
0
            case XML_NAMESPACE_DECL:
13727
0
            case XML_XINCLUDE_START:
13728
0
            case XML_XINCLUDE_END:
13729
0
    break;
13730
307
  }
13731
307
  limit = cur;
13732
307
    }
13733
619
    if (cur == NULL) {
13734
0
        return(0);
13735
0
    }
13736
13737
619
    patstream = xmlPatternGetStreamCtxt(comp);
13738
619
    if (patstream == NULL) {
13739
  /*
13740
  * QUESTION TODO: Is this an error?
13741
  */
13742
0
  return(0);
13743
0
    }
13744
13745
619
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746
13747
619
    if (from_root) {
13748
312
  ret = xmlStreamPush(patstream, NULL, NULL);
13749
312
  if (ret < 0) {
13750
312
  } else if (ret == 1) {
13751
10
      if (toBool)
13752
0
    goto return_1;
13753
            /* TODO: Check memory error. */
13754
10
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755
10
  }
13756
312
    }
13757
619
    depth = 0;
13758
619
    goto scan_children;
13759
9.96k
next_node:
13760
17.6k
    do {
13761
17.6k
        if (ctxt->opLimit != 0) {
13762
17.6k
            if (ctxt->opCount >= ctxt->opLimit) {
13763
0
                xmlGenericError(xmlGenericErrorContext,
13764
0
                        "XPath operation limit exceeded\n");
13765
0
                xmlFreeStreamCtxt(patstream);
13766
0
                return(-1);
13767
0
            }
13768
17.6k
            ctxt->opCount++;
13769
17.6k
        }
13770
13771
17.6k
  switch (cur->type) {
13772
5.52k
      case XML_ELEMENT_NODE:
13773
15.2k
      case XML_TEXT_NODE:
13774
15.6k
      case XML_CDATA_SECTION_NODE:
13775
16.5k
      case XML_COMMENT_NODE:
13776
17.6k
      case XML_PI_NODE:
13777
17.6k
    if (cur->type == XML_ELEMENT_NODE) {
13778
5.52k
        ret = xmlStreamPush(patstream, cur->name,
13779
5.52k
        (cur->ns ? cur->ns->href : NULL));
13780
12.0k
    } else if (eval_all_nodes)
13781
2.75k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13782
9.33k
    else
13783
9.33k
        break;
13784
13785
8.27k
    if (ret < 0) {
13786
        /* NOP. */
13787
8.27k
    } else if (ret == 1) {
13788
1.89k
        if (toBool)
13789
0
      goto return_1;
13790
1.89k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13791
1.89k
            < 0) {
13792
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13793
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13794
0
        }
13795
1.89k
    }
13796
8.27k
    if ((cur->children == NULL) || (depth >= max_depth)) {
13797
4.52k
        ret = xmlStreamPop(patstream);
13798
4.52k
        while (cur->next != NULL) {
13799
3.53k
      cur = cur->next;
13800
3.53k
      if ((cur->type != XML_ENTITY_DECL) &&
13801
3.53k
          (cur->type != XML_DTD_NODE))
13802
3.53k
          goto next_node;
13803
3.53k
        }
13804
4.52k
    }
13805
4.74k
      default:
13806
4.74k
    break;
13807
17.6k
  }
13808
13809
14.6k
scan_children:
13810
14.6k
  if (cur->type == XML_NAMESPACE_DECL) break;
13811
14.6k
  if ((cur->children != NULL) && (depth < max_depth)) {
13812
      /*
13813
       * Do not descend on entities declarations
13814
       */
13815
4.37k
      if (cur->children->type != XML_ENTITY_DECL) {
13816
4.37k
    cur = cur->children;
13817
4.37k
    depth++;
13818
    /*
13819
     * Skip DTDs
13820
     */
13821
4.37k
    if (cur->type != XML_DTD_NODE)
13822
4.37k
        continue;
13823
4.37k
      }
13824
4.37k
  }
13825
13826
10.3k
  if (cur == limit)
13827
3
      break;
13828
13829
10.3k
  while (cur->next != NULL) {
13830
6.43k
      cur = cur->next;
13831
6.43k
      if ((cur->type != XML_ENTITY_DECL) &&
13832
6.43k
    (cur->type != XML_DTD_NODE))
13833
6.43k
    goto next_node;
13834
6.43k
  }
13835
13836
4.37k
  do {
13837
4.37k
      cur = cur->parent;
13838
4.37k
      depth--;
13839
4.37k
      if ((cur == NULL) || (cur == limit) ||
13840
4.37k
                (cur->type == XML_DOCUMENT_NODE))
13841
616
          goto done;
13842
3.75k
      if (cur->type == XML_ELEMENT_NODE) {
13843
3.75k
    ret = xmlStreamPop(patstream);
13844
3.75k
      } else if ((eval_all_nodes) &&
13845
0
    ((cur->type == XML_TEXT_NODE) ||
13846
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13847
0
     (cur->type == XML_COMMENT_NODE) ||
13848
0
     (cur->type == XML_PI_NODE)))
13849
0
      {
13850
0
    ret = xmlStreamPop(patstream);
13851
0
      }
13852
3.75k
      if (cur->next != NULL) {
13853
3.27k
    cur = cur->next;
13854
3.27k
    break;
13855
3.27k
      }
13856
3.75k
  } while (cur != NULL);
13857
13858
7.64k
    } while ((cur != NULL) && (depth >= 0));
13859
13860
619
done:
13861
13862
619
    if (patstream)
13863
619
  xmlFreeStreamCtxt(patstream);
13864
619
    return(0);
13865
13866
0
return_1:
13867
0
    if (patstream)
13868
0
  xmlFreeStreamCtxt(patstream);
13869
0
    return(1);
13870
9.96k
}
13871
#endif /* XPATH_STREAMING */
13872
13873
/**
13874
 * xmlXPathRunEval:
13875
 * @ctxt:  the XPath parser context with the compiled expression
13876
 * @toBool:  evaluate to a boolean result
13877
 *
13878
 * Evaluate the Precompiled XPath expression in the given context.
13879
 */
13880
static int
13881
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13882
12.6k
{
13883
12.6k
    xmlXPathCompExprPtr comp;
13884
12.6k
    int oldDepth;
13885
13886
12.6k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13887
0
  return(-1);
13888
13889
12.6k
    if (ctxt->valueTab == NULL) {
13890
  /* Allocate the value stack */
13891
91
  ctxt->valueTab = (xmlXPathObjectPtr *)
13892
91
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13893
91
  if (ctxt->valueTab == NULL) {
13894
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13895
0
      return(-1);
13896
0
  }
13897
91
  ctxt->valueNr = 0;
13898
91
  ctxt->valueMax = 10;
13899
91
  ctxt->value = NULL;
13900
91
        ctxt->valueFrame = 0;
13901
91
    }
13902
12.6k
#ifdef XPATH_STREAMING
13903
12.6k
    if (ctxt->comp->stream) {
13904
665
  int res;
13905
13906
665
  if (toBool) {
13907
      /*
13908
      * Evaluation to boolean result.
13909
      */
13910
0
      res = xmlXPathRunStreamEval(ctxt->context,
13911
0
    ctxt->comp->stream, NULL, 1);
13912
0
      if (res != -1)
13913
0
    return(res);
13914
665
  } else {
13915
665
      xmlXPathObjectPtr resObj = NULL;
13916
13917
      /*
13918
      * Evaluation to a sequence.
13919
      */
13920
665
      res = xmlXPathRunStreamEval(ctxt->context,
13921
665
    ctxt->comp->stream, &resObj, 0);
13922
13923
665
      if ((res != -1) && (resObj != NULL)) {
13924
665
    valuePush(ctxt, resObj);
13925
665
    return(0);
13926
665
      }
13927
0
      if (resObj != NULL)
13928
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13929
0
  }
13930
  /*
13931
  * QUESTION TODO: This falls back to normal XPath evaluation
13932
  * if res == -1. Is this intended?
13933
  */
13934
665
    }
13935
11.9k
#endif
13936
11.9k
    comp = ctxt->comp;
13937
11.9k
    if (comp->last < 0) {
13938
0
  xmlGenericError(xmlGenericErrorContext,
13939
0
      "xmlXPathRunEval: last is less than zero\n");
13940
0
  return(-1);
13941
0
    }
13942
11.9k
    oldDepth = ctxt->context->depth;
13943
11.9k
    if (toBool)
13944
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13945
0
      &comp->steps[comp->last], 0));
13946
11.9k
    else
13947
11.9k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13948
11.9k
    ctxt->context->depth = oldDepth;
13949
13950
11.9k
    return(0);
13951
11.9k
}
13952
13953
/************************************************************************
13954
 *                  *
13955
 *      Public interfaces       *
13956
 *                  *
13957
 ************************************************************************/
13958
13959
/**
13960
 * xmlXPathEvalPredicate:
13961
 * @ctxt:  the XPath context
13962
 * @res:  the Predicate Expression evaluation result
13963
 *
13964
 * Evaluate a predicate result for the current node.
13965
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13966
 * the result to a boolean. If the result is a number, the result will
13967
 * be converted to true if the number is equal to the position of the
13968
 * context node in the context node list (as returned by the position
13969
 * function) and will be converted to false otherwise; if the result
13970
 * is not a number, then the result will be converted as if by a call
13971
 * to the boolean function.
13972
 *
13973
 * Returns 1 if predicate is true, 0 otherwise
13974
 */
13975
int
13976
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13977
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13978
0
    switch (res->type) {
13979
0
        case XPATH_BOOLEAN:
13980
0
      return(res->boolval);
13981
0
        case XPATH_NUMBER:
13982
0
      return(res->floatval == ctxt->proximityPosition);
13983
0
        case XPATH_NODESET:
13984
0
        case XPATH_XSLT_TREE:
13985
0
      if (res->nodesetval == NULL)
13986
0
    return(0);
13987
0
      return(res->nodesetval->nodeNr != 0);
13988
0
        case XPATH_STRING:
13989
0
      return((res->stringval != NULL) &&
13990
0
             (xmlStrlen(res->stringval) != 0));
13991
0
        default:
13992
0
      STRANGE
13993
0
    }
13994
0
    return(0);
13995
0
}
13996
13997
/**
13998
 * xmlXPathEvaluatePredicateResult:
13999
 * @ctxt:  the XPath Parser context
14000
 * @res:  the Predicate Expression evaluation result
14001
 *
14002
 * Evaluate a predicate result for the current node.
14003
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14004
 * the result to a boolean. If the result is a number, the result will
14005
 * be converted to true if the number is equal to the position of the
14006
 * context node in the context node list (as returned by the position
14007
 * function) and will be converted to false otherwise; if the result
14008
 * is not a number, then the result will be converted as if by a call
14009
 * to the boolean function.
14010
 *
14011
 * Returns 1 if predicate is true, 0 otherwise
14012
 */
14013
int
14014
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14015
103k
                                xmlXPathObjectPtr res) {
14016
103k
    if ((ctxt == NULL) || (res == NULL)) return(0);
14017
103k
    switch (res->type) {
14018
0
        case XPATH_BOOLEAN:
14019
0
      return(res->boolval);
14020
22.2k
        case XPATH_NUMBER:
14021
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14022
      return((res->floatval == ctxt->context->proximityPosition) &&
14023
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14024
#else
14025
22.2k
      return(res->floatval == ctxt->context->proximityPosition);
14026
0
#endif
14027
80.2k
        case XPATH_NODESET:
14028
80.2k
        case XPATH_XSLT_TREE:
14029
80.2k
      if (res->nodesetval == NULL)
14030
2.40k
    return(0);
14031
77.8k
      return(res->nodesetval->nodeNr != 0);
14032
1.16k
        case XPATH_STRING:
14033
1.16k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14034
#ifdef LIBXML_XPTR_LOCS_ENABLED
14035
  case XPATH_LOCATIONSET:{
14036
      xmlLocationSetPtr ptr = res->user;
14037
      if (ptr == NULL)
14038
          return(0);
14039
      return (ptr->locNr != 0);
14040
      }
14041
#endif
14042
0
        default:
14043
0
      STRANGE
14044
103k
    }
14045
0
    return(0);
14046
103k
}
14047
14048
#ifdef XPATH_STREAMING
14049
/**
14050
 * xmlXPathTryStreamCompile:
14051
 * @ctxt: an XPath context
14052
 * @str:  the XPath expression
14053
 *
14054
 * Try to compile the XPath expression as a streamable subset.
14055
 *
14056
 * Returns the compiled expression or NULL if failed to compile.
14057
 */
14058
static xmlXPathCompExprPtr
14059
19.1k
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14060
    /*
14061
     * Optimization: use streaming patterns when the XPath expression can
14062
     * be compiled to a stream lookup
14063
     */
14064
19.1k
    xmlPatternPtr stream;
14065
19.1k
    xmlXPathCompExprPtr comp;
14066
19.1k
    xmlDictPtr dict = NULL;
14067
19.1k
    const xmlChar **namespaces = NULL;
14068
19.1k
    xmlNsPtr ns;
14069
19.1k
    int i, j;
14070
14071
19.1k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14072
19.1k
        (!xmlStrchr(str, '@'))) {
14073
4.67k
  const xmlChar *tmp;
14074
14075
  /*
14076
   * We don't try to handle expressions using the verbose axis
14077
   * specifiers ("::"), just the simplified form at this point.
14078
   * Additionally, if there is no list of namespaces available and
14079
   *  there's a ":" in the expression, indicating a prefixed QName,
14080
   *  then we won't try to compile either. xmlPatterncompile() needs
14081
   *  to have a list of namespaces at compilation time in order to
14082
   *  compile prefixed name tests.
14083
   */
14084
4.67k
  tmp = xmlStrchr(str, ':');
14085
4.67k
  if ((tmp != NULL) &&
14086
4.67k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14087
1.04k
      return(NULL);
14088
14089
3.63k
  if (ctxt != NULL) {
14090
3.63k
      dict = ctxt->dict;
14091
3.63k
      if (ctxt->nsNr > 0) {
14092
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14093
0
    if (namespaces == NULL) {
14094
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14095
0
        return(NULL);
14096
0
    }
14097
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14098
0
        ns = ctxt->namespaces[j];
14099
0
        namespaces[i++] = ns->href;
14100
0
        namespaces[i++] = ns->prefix;
14101
0
    }
14102
0
    namespaces[i++] = NULL;
14103
0
    namespaces[i] = NULL;
14104
0
      }
14105
3.63k
  }
14106
14107
3.63k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14108
3.63k
  if (namespaces != NULL) {
14109
0
      xmlFree((xmlChar **)namespaces);
14110
0
  }
14111
3.63k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14112
628
      comp = xmlXPathNewCompExpr();
14113
628
      if (comp == NULL) {
14114
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14115
0
    return(NULL);
14116
0
      }
14117
628
      comp->stream = stream;
14118
628
      comp->dict = dict;
14119
628
      if (comp->dict)
14120
0
    xmlDictReference(comp->dict);
14121
628
      return(comp);
14122
628
  }
14123
3.00k
  xmlFreePattern(stream);
14124
3.00k
    }
14125
17.4k
    return(NULL);
14126
19.1k
}
14127
#endif /* XPATH_STREAMING */
14128
14129
static void
14130
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14131
                           xmlXPathStepOpPtr op)
14132
422k
{
14133
422k
    xmlXPathCompExprPtr comp = pctxt->comp;
14134
422k
    xmlXPathContextPtr ctxt;
14135
14136
    /*
14137
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14138
    * internal representation.
14139
    */
14140
14141
422k
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14142
422k
        (op->ch1 != -1) &&
14143
422k
        (op->ch2 == -1 /* no predicate */))
14144
144k
    {
14145
144k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14146
14147
144k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14148
144k
            ((xmlXPathAxisVal) prevop->value ==
14149
74.2k
                AXIS_DESCENDANT_OR_SELF) &&
14150
144k
            (prevop->ch2 == -1) &&
14151
144k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14152
144k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14153
33.9k
        {
14154
            /*
14155
            * This is a "descendant-or-self::node()" without predicates.
14156
            * Try to eliminate it.
14157
            */
14158
14159
33.9k
            switch ((xmlXPathAxisVal) op->value) {
14160
29.6k
                case AXIS_CHILD:
14161
29.6k
                case AXIS_DESCENDANT:
14162
                    /*
14163
                    * Convert "descendant-or-self::node()/child::" or
14164
                    * "descendant-or-self::node()/descendant::" to
14165
                    * "descendant::"
14166
                    */
14167
29.6k
                    op->ch1   = prevop->ch1;
14168
29.6k
                    op->value = AXIS_DESCENDANT;
14169
29.6k
                    break;
14170
2
                case AXIS_SELF:
14171
1.10k
                case AXIS_DESCENDANT_OR_SELF:
14172
                    /*
14173
                    * Convert "descendant-or-self::node()/self::" or
14174
                    * "descendant-or-self::node()/descendant-or-self::" to
14175
                    * to "descendant-or-self::"
14176
                    */
14177
1.10k
                    op->ch1   = prevop->ch1;
14178
1.10k
                    op->value = AXIS_DESCENDANT_OR_SELF;
14179
1.10k
                    break;
14180
3.19k
                default:
14181
3.19k
                    break;
14182
33.9k
            }
14183
33.9k
  }
14184
144k
    }
14185
14186
    /* OP_VALUE has invalid ch1. */
14187
422k
    if (op->op == XPATH_OP_VALUE)
14188
29.8k
        return;
14189
14190
    /* Recurse */
14191
392k
    ctxt = pctxt->context;
14192
392k
    if (ctxt != NULL) {
14193
392k
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14194
50
            return;
14195
392k
        ctxt->depth += 1;
14196
392k
    }
14197
392k
    if (op->ch1 != -1)
14198
286k
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14199
392k
    if (op->ch2 != -1)
14200
124k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14201
392k
    if (ctxt != NULL)
14202
392k
        ctxt->depth -= 1;
14203
392k
}
14204
14205
/**
14206
 * xmlXPathCtxtCompile:
14207
 * @ctxt: an XPath context
14208
 * @str:  the XPath expression
14209
 *
14210
 * Compile an XPath expression
14211
 *
14212
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14213
 *         the caller has to free the object.
14214
 */
14215
xmlXPathCompExprPtr
14216
19.0k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14217
19.0k
    xmlXPathParserContextPtr pctxt;
14218
19.0k
    xmlXPathCompExprPtr comp;
14219
19.0k
    int oldDepth = 0;
14220
14221
19.0k
#ifdef XPATH_STREAMING
14222
19.0k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14223
19.0k
    if (comp != NULL)
14224
628
        return(comp);
14225
18.4k
#endif
14226
14227
18.4k
    xmlInitParser();
14228
14229
18.4k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14230
18.4k
    if (pctxt == NULL)
14231
0
        return NULL;
14232
18.4k
    if (ctxt != NULL)
14233
18.4k
        oldDepth = ctxt->depth;
14234
18.4k
    xmlXPathCompileExpr(pctxt, 1);
14235
18.4k
    if (ctxt != NULL)
14236
18.4k
        ctxt->depth = oldDepth;
14237
14238
18.4k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14239
4.81k
    {
14240
4.81k
        xmlXPathFreeParserContext(pctxt);
14241
4.81k
        return(NULL);
14242
4.81k
    }
14243
14244
13.5k
    if (*pctxt->cur != 0) {
14245
  /*
14246
   * aleksey: in some cases this line prints *second* error message
14247
   * (see bug #78858) and probably this should be fixed.
14248
   * However, we are not sure that all error messages are printed
14249
   * out in other places. It's not critical so we leave it as-is for now
14250
   */
14251
1.71k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14252
1.71k
  comp = NULL;
14253
11.8k
    } else {
14254
11.8k
  comp = pctxt->comp;
14255
11.8k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14256
11.8k
            if (ctxt != NULL)
14257
11.8k
                oldDepth = ctxt->depth;
14258
11.8k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14259
11.8k
            if (ctxt != NULL)
14260
11.8k
                ctxt->depth = oldDepth;
14261
11.8k
  }
14262
11.8k
  pctxt->comp = NULL;
14263
11.8k
    }
14264
13.5k
    xmlXPathFreeParserContext(pctxt);
14265
14266
13.5k
    if (comp != NULL) {
14267
11.8k
  comp->expr = xmlStrdup(str);
14268
#ifdef DEBUG_EVAL_COUNTS
14269
  comp->string = xmlStrdup(str);
14270
  comp->nb = 0;
14271
#endif
14272
11.8k
    }
14273
13.5k
    return(comp);
14274
18.4k
}
14275
14276
/**
14277
 * xmlXPathCompile:
14278
 * @str:  the XPath expression
14279
 *
14280
 * Compile an XPath expression
14281
 *
14282
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14283
 *         the caller has to free the object.
14284
 */
14285
xmlXPathCompExprPtr
14286
0
xmlXPathCompile(const xmlChar *str) {
14287
0
    return(xmlXPathCtxtCompile(NULL, str));
14288
0
}
14289
14290
/**
14291
 * xmlXPathCompiledEvalInternal:
14292
 * @comp:  the compiled XPath expression
14293
 * @ctxt:  the XPath context
14294
 * @resObj: the resulting XPath object or NULL
14295
 * @toBool: 1 if only a boolean result is requested
14296
 *
14297
 * Evaluate the Precompiled XPath expression in the given context.
14298
 * The caller has to free @resObj.
14299
 *
14300
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14301
 *         the caller has to free the object.
14302
 */
14303
static int
14304
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14305
           xmlXPathContextPtr ctxt,
14306
           xmlXPathObjectPtr *resObjPtr,
14307
           int toBool)
14308
12.5k
{
14309
12.5k
    xmlXPathParserContextPtr pctxt;
14310
12.5k
    xmlXPathObjectPtr resObj;
14311
#ifndef LIBXML_THREAD_ENABLED
14312
    static int reentance = 0;
14313
#endif
14314
12.5k
    int res;
14315
14316
12.5k
    CHECK_CTXT_NEG(ctxt)
14317
14318
12.5k
    if (comp == NULL)
14319
0
  return(-1);
14320
12.5k
    xmlInitParser();
14321
14322
#ifndef LIBXML_THREAD_ENABLED
14323
    reentance++;
14324
    if (reentance > 1)
14325
  xmlXPathDisableOptimizer = 1;
14326
#endif
14327
14328
#ifdef DEBUG_EVAL_COUNTS
14329
    comp->nb++;
14330
    if ((comp->string != NULL) && (comp->nb > 100)) {
14331
  fprintf(stderr, "100 x %s\n", comp->string);
14332
  comp->nb = 0;
14333
    }
14334
#endif
14335
12.5k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14336
12.5k
    res = xmlXPathRunEval(pctxt, toBool);
14337
14338
12.5k
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14339
1.49k
        resObj = NULL;
14340
11.0k
    } else {
14341
11.0k
        resObj = valuePop(pctxt);
14342
11.0k
        if (resObj == NULL) {
14343
0
            if (!toBool)
14344
0
                xmlGenericError(xmlGenericErrorContext,
14345
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14346
11.0k
        } else if (pctxt->valueNr > 0) {
14347
0
            xmlGenericError(xmlGenericErrorContext,
14348
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14349
0
                pctxt->valueNr);
14350
0
        }
14351
11.0k
    }
14352
14353
12.5k
    if (resObjPtr)
14354
12.5k
        *resObjPtr = resObj;
14355
0
    else
14356
0
        xmlXPathReleaseObject(ctxt, resObj);
14357
14358
12.5k
    pctxt->comp = NULL;
14359
12.5k
    xmlXPathFreeParserContext(pctxt);
14360
#ifndef LIBXML_THREAD_ENABLED
14361
    reentance--;
14362
#endif
14363
14364
12.5k
    return(res);
14365
12.5k
}
14366
14367
/**
14368
 * xmlXPathCompiledEval:
14369
 * @comp:  the compiled XPath expression
14370
 * @ctx:  the XPath context
14371
 *
14372
 * Evaluate the Precompiled XPath expression in the given context.
14373
 *
14374
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14375
 *         the caller has to free the object.
14376
 */
14377
xmlXPathObjectPtr
14378
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14379
12.5k
{
14380
12.5k
    xmlXPathObjectPtr res = NULL;
14381
14382
12.5k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14383
12.5k
    return(res);
14384
12.5k
}
14385
14386
/**
14387
 * xmlXPathCompiledEvalToBoolean:
14388
 * @comp:  the compiled XPath expression
14389
 * @ctxt:  the XPath context
14390
 *
14391
 * Applies the XPath boolean() function on the result of the given
14392
 * compiled expression.
14393
 *
14394
 * Returns 1 if the expression evaluated to true, 0 if to false and
14395
 *         -1 in API and internal errors.
14396
 */
14397
int
14398
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14399
            xmlXPathContextPtr ctxt)
14400
0
{
14401
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14402
0
}
14403
14404
/**
14405
 * xmlXPathEvalExpr:
14406
 * @ctxt:  the XPath Parser context
14407
 *
14408
 * Parse and evaluate an XPath expression in the given context,
14409
 * then push the result on the context stack
14410
 */
14411
void
14412
95
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14413
95
#ifdef XPATH_STREAMING
14414
95
    xmlXPathCompExprPtr comp;
14415
95
#endif
14416
95
    int oldDepth = 0;
14417
14418
95
    if (ctxt == NULL) return;
14419
14420
95
#ifdef XPATH_STREAMING
14421
95
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422
95
    if (comp != NULL) {
14423
0
        if (ctxt->comp != NULL)
14424
0
      xmlXPathFreeCompExpr(ctxt->comp);
14425
0
        ctxt->comp = comp;
14426
0
    } else
14427
95
#endif
14428
95
    {
14429
95
        if (ctxt->context != NULL)
14430
95
            oldDepth = ctxt->context->depth;
14431
95
  xmlXPathCompileExpr(ctxt, 1);
14432
95
        if (ctxt->context != NULL)
14433
95
            ctxt->context->depth = oldDepth;
14434
95
        CHECK_ERROR;
14435
14436
        /* Check for trailing characters. */
14437
93
        if (*ctxt->cur != 0)
14438
91
            XP_ERROR(XPATH_EXPR_ERROR);
14439
14440
91
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441
91
            if (ctxt->context != NULL)
14442
91
                oldDepth = ctxt->context->depth;
14443
91
      xmlXPathOptimizeExpression(ctxt,
14444
91
    &ctxt->comp->steps[ctxt->comp->last]);
14445
91
            if (ctxt->context != NULL)
14446
91
                ctxt->context->depth = oldDepth;
14447
91
        }
14448
91
    }
14449
14450
91
    xmlXPathRunEval(ctxt, 0);
14451
91
}
14452
14453
/**
14454
 * xmlXPathEval:
14455
 * @str:  the XPath expression
14456
 * @ctx:  the XPath context
14457
 *
14458
 * Evaluate the XPath Location Path in the given context.
14459
 *
14460
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14461
 *         the caller has to free the object.
14462
 */
14463
xmlXPathObjectPtr
14464
95
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14465
95
    xmlXPathParserContextPtr ctxt;
14466
95
    xmlXPathObjectPtr res;
14467
14468
95
    CHECK_CTXT(ctx)
14469
14470
95
    xmlInitParser();
14471
14472
95
    ctxt = xmlXPathNewParserContext(str, ctx);
14473
95
    if (ctxt == NULL)
14474
0
        return NULL;
14475
95
    xmlXPathEvalExpr(ctxt);
14476
14477
95
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14478
4
  res = NULL;
14479
91
    } else {
14480
91
  res = valuePop(ctxt);
14481
91
        if (res == NULL) {
14482
0
            xmlGenericError(xmlGenericErrorContext,
14483
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14484
91
        } else if (ctxt->valueNr > 0) {
14485
0
            xmlGenericError(xmlGenericErrorContext,
14486
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14487
0
                ctxt->valueNr);
14488
0
        }
14489
91
    }
14490
14491
95
    xmlXPathFreeParserContext(ctxt);
14492
95
    return(res);
14493
95
}
14494
14495
/**
14496
 * xmlXPathSetContextNode:
14497
 * @node: the node to to use as the context node
14498
 * @ctx:  the XPath context
14499
 *
14500
 * Sets 'node' as the context node. The node must be in the same
14501
 * document as that associated with the context.
14502
 *
14503
 * Returns -1 in case of error or 0 if successful
14504
 */
14505
int
14506
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14507
0
    if ((node == NULL) || (ctx == NULL))
14508
0
        return(-1);
14509
14510
0
    if (node->doc == ctx->doc) {
14511
0
        ctx->node = node;
14512
0
  return(0);
14513
0
    }
14514
0
    return(-1);
14515
0
}
14516
14517
/**
14518
 * xmlXPathNodeEval:
14519
 * @node: the node to to use as the context node
14520
 * @str:  the XPath expression
14521
 * @ctx:  the XPath context
14522
 *
14523
 * Evaluate the XPath Location Path in the given context. The node 'node'
14524
 * is set as the context node. The context node is not restored.
14525
 *
14526
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14527
 *         the caller has to free the object.
14528
 */
14529
xmlXPathObjectPtr
14530
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14531
0
    if (str == NULL)
14532
0
        return(NULL);
14533
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14534
0
        return(NULL);
14535
0
    return(xmlXPathEval(str, ctx));
14536
0
}
14537
14538
/**
14539
 * xmlXPathEvalExpression:
14540
 * @str:  the XPath expression
14541
 * @ctxt:  the XPath context
14542
 *
14543
 * Alias for xmlXPathEval().
14544
 *
14545
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14546
 *         the caller has to free the object.
14547
 */
14548
xmlXPathObjectPtr
14549
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14550
0
    return(xmlXPathEval(str, ctxt));
14551
0
}
14552
14553
/************************************************************************
14554
 *                  *
14555
 *  Extra functions not pertaining to the XPath spec    *
14556
 *                  *
14557
 ************************************************************************/
14558
/**
14559
 * xmlXPathEscapeUriFunction:
14560
 * @ctxt:  the XPath Parser context
14561
 * @nargs:  the number of arguments
14562
 *
14563
 * Implement the escape-uri() XPath function
14564
 *    string escape-uri(string $str, bool $escape-reserved)
14565
 *
14566
 * This function applies the URI escaping rules defined in section 2 of [RFC
14567
 * 2396] to the string supplied as $uri-part, which typically represents all
14568
 * or part of a URI. The effect of the function is to replace any special
14569
 * character in the string by an escape sequence of the form %xx%yy...,
14570
 * where xxyy... is the hexadecimal representation of the octets used to
14571
 * represent the character in UTF-8.
14572
 *
14573
 * The set of characters that are escaped depends on the setting of the
14574
 * boolean argument $escape-reserved.
14575
 *
14576
 * If $escape-reserved is true, all characters are escaped other than lower
14577
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14578
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14579
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14580
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14581
 * A-F).
14582
 *
14583
 * If $escape-reserved is false, the behavior differs in that characters
14584
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14585
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14586
 *
14587
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14588
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14589
 * compared using string comparison functions, this function must always use
14590
 * the upper-case letters A-F.
14591
 *
14592
 * Generally, $escape-reserved should be set to true when escaping a string
14593
 * that is to form a single part of a URI, and to false when escaping an
14594
 * entire URI or URI reference.
14595
 *
14596
 * In the case of non-ascii characters, the string is encoded according to
14597
 * utf-8 and then converted according to RFC 2396.
14598
 *
14599
 * Examples
14600
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14601
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14602
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14603
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14604
 *
14605
 */
14606
static void
14607
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14608
0
    xmlXPathObjectPtr str;
14609
0
    int escape_reserved;
14610
0
    xmlBufPtr target;
14611
0
    xmlChar *cptr;
14612
0
    xmlChar escape[4];
14613
14614
0
    CHECK_ARITY(2);
14615
14616
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14617
14618
0
    CAST_TO_STRING;
14619
0
    str = valuePop(ctxt);
14620
14621
0
    target = xmlBufCreate();
14622
14623
0
    escape[0] = '%';
14624
0
    escape[3] = 0;
14625
14626
0
    if (target) {
14627
0
  for (cptr = str->stringval; *cptr; cptr++) {
14628
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14629
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14630
0
    (*cptr >= '0' && *cptr <= '9') ||
14631
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14632
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14633
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14634
0
    (*cptr == '%' &&
14635
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14636
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14637
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14638
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14639
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14640
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14641
0
    (!escape_reserved &&
14642
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14643
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14644
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14645
0
      *cptr == ','))) {
14646
0
    xmlBufAdd(target, cptr, 1);
14647
0
      } else {
14648
0
    if ((*cptr >> 4) < 10)
14649
0
        escape[1] = '0' + (*cptr >> 4);
14650
0
    else
14651
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14652
0
    if ((*cptr & 0xF) < 10)
14653
0
        escape[2] = '0' + (*cptr & 0xF);
14654
0
    else
14655
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14656
14657
0
    xmlBufAdd(target, &escape[0], 3);
14658
0
      }
14659
0
  }
14660
0
    }
14661
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14662
0
  xmlBufContent(target)));
14663
0
    xmlBufFree(target);
14664
0
    xmlXPathReleaseObject(ctxt->context, str);
14665
0
}
14666
14667
/**
14668
 * xmlXPathRegisterAllFunctions:
14669
 * @ctxt:  the XPath context
14670
 *
14671
 * Registers all default XPath functions in this context
14672
 */
14673
void
14674
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14675
347k
{
14676
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14677
347k
                         xmlXPathBooleanFunction);
14678
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14679
347k
                         xmlXPathCeilingFunction);
14680
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14681
347k
                         xmlXPathCountFunction);
14682
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14683
347k
                         xmlXPathConcatFunction);
14684
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14685
347k
                         xmlXPathContainsFunction);
14686
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14687
347k
                         xmlXPathIdFunction);
14688
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14689
347k
                         xmlXPathFalseFunction);
14690
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14691
347k
                         xmlXPathFloorFunction);
14692
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14693
347k
                         xmlXPathLastFunction);
14694
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14695
347k
                         xmlXPathLangFunction);
14696
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14697
347k
                         xmlXPathLocalNameFunction);
14698
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14699
347k
                         xmlXPathNotFunction);
14700
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14701
347k
                         xmlXPathNameFunction);
14702
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14703
347k
                         xmlXPathNamespaceURIFunction);
14704
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14705
347k
                         xmlXPathNormalizeFunction);
14706
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14707
347k
                         xmlXPathNumberFunction);
14708
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14709
347k
                         xmlXPathPositionFunction);
14710
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14711
347k
                         xmlXPathRoundFunction);
14712
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14713
347k
                         xmlXPathStringFunction);
14714
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14715
347k
                         xmlXPathStringLengthFunction);
14716
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14717
347k
                         xmlXPathStartsWithFunction);
14718
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14719
347k
                         xmlXPathSubstringFunction);
14720
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14721
347k
                         xmlXPathSubstringBeforeFunction);
14722
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14723
347k
                         xmlXPathSubstringAfterFunction);
14724
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14725
347k
                         xmlXPathSumFunction);
14726
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14727
347k
                         xmlXPathTrueFunction);
14728
347k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14729
347k
                         xmlXPathTranslateFunction);
14730
14731
347k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14732
347k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14733
347k
                         xmlXPathEscapeUriFunction);
14734
347k
}
14735
14736
#endif /* LIBXML_XPATH_ENABLED */