Coverage Report

Created: 2024-05-08 16:10

/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
170
    xmlGenericError(xmlGenericErrorContext,       \
62
170
      "Unimplemented block at %s:%d\n",       \
63
170
            __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
326k
#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
274
#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
226k
#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
14.6M
#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.66M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
162
1.66M
    int depth1, depth2;
163
1.66M
    int misc = 0, precedence1 = 0, precedence2 = 0;
164
1.66M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
165
1.66M
    xmlNodePtr cur, root;
166
1.66M
    ptrdiff_t l1, l2;
167
168
1.66M
    if ((node1 == NULL) || (node2 == NULL))
169
0
  return(-2);
170
171
1.66M
    if (node1 == node2)
172
0
  return(0);
173
174
    /*
175
     * a couple of optimizations which will avoid computations in most cases
176
     */
177
1.66M
    switch (node1->type) {
178
1.01M
  case XML_ELEMENT_NODE:
179
1.01M
      if (node2->type == XML_ELEMENT_NODE) {
180
817k
    if ((0 > (ptrdiff_t) node1->content) &&
181
817k
        (0 > (ptrdiff_t) node2->content) &&
182
817k
        (node1->doc == node2->doc))
183
604k
    {
184
604k
        l1 = -((ptrdiff_t) node1->content);
185
604k
        l2 = -((ptrdiff_t) node2->content);
186
604k
        if (l1 < l2)
187
493k
      return(1);
188
111k
        if (l1 > l2)
189
111k
      return(-1);
190
111k
    } else
191
213k
        goto turtle_comparison;
192
817k
      }
193
202k
      break;
194
202k
  case XML_ATTRIBUTE_NODE:
195
29.0k
      precedence1 = 1; /* element is owner */
196
29.0k
      miscNode1 = node1;
197
29.0k
      node1 = node1->parent;
198
29.0k
      misc = 1;
199
29.0k
      break;
200
496k
  case XML_TEXT_NODE:
201
520k
  case XML_CDATA_SECTION_NODE:
202
555k
  case XML_COMMENT_NODE:
203
591k
  case XML_PI_NODE: {
204
591k
      miscNode1 = node1;
205
      /*
206
      * Find nearest element node.
207
      */
208
591k
      if (node1->prev != NULL) {
209
538k
    do {
210
538k
        node1 = node1->prev;
211
538k
        if (node1->type == XML_ELEMENT_NODE) {
212
358k
      precedence1 = 3; /* element in prev-sibl axis */
213
358k
      break;
214
358k
        }
215
179k
        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
179k
    } while (1);
225
358k
      } else {
226
232k
    precedence1 = 2; /* element is parent */
227
232k
    node1 = node1->parent;
228
232k
      }
229
591k
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
230
591k
    (0 <= (ptrdiff_t) node1->content)) {
231
    /*
232
    * Fallback for whatever case.
233
    */
234
18.6k
    node1 = miscNode1;
235
18.6k
    precedence1 = 0;
236
18.6k
      } else
237
572k
    misc = 1;
238
591k
  }
239
0
      break;
240
13.3k
  case XML_NAMESPACE_DECL:
241
      /*
242
      * TODO: why do we return 1 for namespace nodes?
243
      */
244
13.3k
      return(1);
245
16.4k
  default:
246
16.4k
      break;
247
1.66M
    }
248
838k
    switch (node2->type) {
249
239k
  case XML_ELEMENT_NODE:
250
239k
      break;
251
28.4k
  case XML_ATTRIBUTE_NODE:
252
28.4k
      precedence2 = 1; /* element is owner */
253
28.4k
      miscNode2 = node2;
254
28.4k
      node2 = node2->parent;
255
28.4k
      misc = 1;
256
28.4k
      break;
257
454k
  case XML_TEXT_NODE:
258
474k
  case XML_CDATA_SECTION_NODE:
259
508k
  case XML_COMMENT_NODE:
260
540k
  case XML_PI_NODE: {
261
540k
      miscNode2 = node2;
262
540k
      if (node2->prev != NULL) {
263
532k
    do {
264
532k
        node2 = node2->prev;
265
532k
        if (node2->type == XML_ELEMENT_NODE) {
266
340k
      precedence2 = 3; /* element in prev-sibl axis */
267
340k
      break;
268
340k
        }
269
191k
        if (node2->prev == NULL) {
270
0
      precedence2 = 2; /* element is parent */
271
0
      node2 = node2->parent;
272
0
      break;
273
0
        }
274
191k
    } while (1);
275
340k
      } else {
276
200k
    precedence2 = 2; /* element is parent */
277
200k
    node2 = node2->parent;
278
200k
      }
279
540k
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
280
540k
    (0 <= (ptrdiff_t) node2->content))
281
16.6k
      {
282
16.6k
    node2 = miscNode2;
283
16.6k
    precedence2 = 0;
284
16.6k
      } else
285
524k
    misc = 1;
286
540k
  }
287
0
      break;
288
693
  case XML_NAMESPACE_DECL:
289
693
      return(1);
290
29.1k
  default:
291
29.1k
      break;
292
838k
    }
293
837k
    if (misc) {
294
794k
  if (node1 == node2) {
295
346k
      if (precedence1 == precedence2) {
296
    /*
297
    * The ugly case; but normally there aren't many
298
    * adjacent non-element nodes around.
299
    */
300
88.1k
    cur = miscNode2->prev;
301
99.2k
    while (cur != NULL) {
302
99.0k
        if (cur == miscNode1)
303
81.5k
      return(1);
304
17.4k
        if (cur->type == XML_ELEMENT_NODE)
305
6.43k
      return(-1);
306
11.0k
        cur = cur->prev;
307
11.0k
    }
308
161
    return (-1);
309
258k
      } 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
258k
    if (precedence1 < precedence2)
316
228k
        return(1);
317
29.8k
    else
318
29.8k
        return(-1);
319
258k
      }
320
346k
  }
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
447k
  if ((precedence2 == 3) && (precedence1 > 1)) {
331
95.4k
      cur = node1->parent;
332
257k
      while (cur) {
333
192k
    if (cur == node2)
334
31.1k
        return(1);
335
161k
    cur = cur->parent;
336
161k
      }
337
95.4k
  }
338
416k
  if ((precedence1 == 3) && (precedence2 > 1)) {
339
75.0k
      cur = node2->parent;
340
243k
      while (cur) {
341
177k
    if (cur == node1)
342
8.24k
        return(-1);
343
168k
    cur = cur->parent;
344
168k
      }
345
75.0k
  }
346
416k
    }
347
348
    /*
349
     * Speedup using document order if available.
350
     */
351
451k
    if ((node1->type == XML_ELEMENT_NODE) &&
352
451k
  (node2->type == XML_ELEMENT_NODE) &&
353
451k
  (0 > (ptrdiff_t) node1->content) &&
354
451k
  (0 > (ptrdiff_t) node2->content) &&
355
451k
  (node1->doc == node2->doc)) {
356
357
381k
  l1 = -((ptrdiff_t) node1->content);
358
381k
  l2 = -((ptrdiff_t) node2->content);
359
381k
  if (l1 < l2)
360
252k
      return(1);
361
128k
  if (l1 > l2)
362
128k
      return(-1);
363
128k
    }
364
365
283k
turtle_comparison:
366
367
283k
    if (node1 == node2->prev)
368
224k
  return(1);
369
59.2k
    if (node1 == node2->next)
370
1.67k
  return(-1);
371
    /*
372
     * compute depth to root
373
     */
374
79.5k
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
375
38.9k
  if (cur->parent == node1)
376
16.9k
      return(1);
377
22.0k
  depth2++;
378
22.0k
    }
379
40.6k
    root = cur;
380
104k
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
381
92.8k
  if (cur->parent == node2)
382
29.1k
      return(-1);
383
63.6k
  depth1++;
384
63.6k
    }
385
    /*
386
     * Distinct document (or distinct entities :-( ) case.
387
     */
388
11.5k
    if (root != cur) {
389
213
  return(-2);
390
213
    }
391
    /*
392
     * get the nearest common ancestor.
393
     */
394
21.4k
    while (depth1 > depth2) {
395
10.1k
  depth1--;
396
10.1k
  node1 = node1->parent;
397
10.1k
    }
398
16.8k
    while (depth2 > depth1) {
399
5.55k
  depth2--;
400
5.55k
  node2 = node2->parent;
401
5.55k
    }
402
12.3k
    while (node1->parent != node2->parent) {
403
987
  node1 = node1->parent;
404
987
  node2 = node2->parent;
405
  /* should not happen but just in case ... */
406
987
  if ((node1 == NULL) || (node2 == NULL))
407
0
      return(-2);
408
987
    }
409
    /*
410
     * Find who's first.
411
     */
412
11.3k
    if (node1 == node2->prev)
413
5.34k
  return(1);
414
5.98k
    if (node1 == node2->next)
415
5.68k
  return(-1);
416
    /*
417
     * Speedup using document order if available.
418
     */
419
301
    if ((node1->type == XML_ELEMENT_NODE) &&
420
301
  (node2->type == XML_ELEMENT_NODE) &&
421
301
  (0 > (ptrdiff_t) node1->content) &&
422
301
  (0 > (ptrdiff_t) node2->content) &&
423
301
  (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
821
    for (cur = node1->next;cur != NULL;cur = cur->next)
434
821
  if (cur == node2)
435
301
      return(1);
436
0
    return(-1); /* assume there is no sibling list corruption */
437
301
}
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
1.30M
#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.66M
    {
461
1.66M
        int res = xmlXPathCmpNodesExt(x, y);
462
1.66M
        return res == -2 ? res : -res;
463
1.66M
    }
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.66M
#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
390
xmlInitXPathInternal(void) {
505
390
#if defined(NAN) && defined(INFINITY)
506
390
    xmlXPathNAN = NAN;
507
390
    xmlXPathPINF = INFINITY;
508
390
    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
390
}
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
607k
xmlXPathIsNaN(double val) {
526
607k
#ifdef isnan
527
607k
    return isnan(val);
528
#else
529
    return !(val == val);
530
#endif
531
607k
}
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
261k
xmlXPathIsInf(double val) {
541
261k
#ifdef isinf
542
261k
    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
261k
}
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
143k
    { 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.43M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
632
2.43M
       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.43M
{
704
2.43M
    if ((error < 0) || (error > MAXERRNO))
705
0
  error = MAXERRNO;
706
2.43M
    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.43M
    ctxt->error = error;
716
2.43M
    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.43M
    xmlResetError(&ctxt->context->lastError);
729
730
2.43M
    ctxt->context->lastError.domain = XML_FROM_XPATH;
731
2.43M
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732
2.43M
                           XPATH_EXPRESSION_OK;
733
2.43M
    ctxt->context->lastError.level = XML_ERR_ERROR;
734
2.43M
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735
2.43M
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736
2.43M
    ctxt->context->lastError.node = ctxt->context->debugNode;
737
2.43M
    if (ctxt->context->error != NULL) {
738
0
  ctxt->context->error(ctxt->context->userData,
739
0
                       &ctxt->context->lastError);
740
2.43M
    } else {
741
2.43M
  __xmlRaiseError(NULL, NULL, NULL,
742
2.43M
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743
2.43M
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744
2.43M
      XML_ERR_ERROR, NULL, 0,
745
2.43M
      (const char *) ctxt->base, NULL, NULL,
746
2.43M
      ctxt->cur - ctxt->base, 0,
747
2.43M
      "%s", xmlXPathErrorMessages[error]);
748
2.43M
    }
749
750
2.43M
}
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
233k
              int line ATTRIBUTE_UNUSED, int no) {
764
233k
    xmlXPathErr(ctxt, no);
765
233k
}
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
20.1M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
777
20.1M
    xmlXPathContextPtr xpctxt = ctxt->context;
778
779
20.1M
    if ((opCount > xpctxt->opLimit) ||
780
20.1M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
781
0
        xpctxt->opCount = xpctxt->opLimit;
782
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
783
0
        return(-1);
784
0
    }
785
786
20.1M
    xpctxt->opCount += opCount;
787
20.1M
    return(0);
788
20.1M
}
789
790
#define OP_LIMIT_EXCEEDED(ctxt, n) \
791
19.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
4.76M
{
820
4.76M
    if (list->items == NULL) {
821
796k
  if (initialSize <= 0)
822
0
      initialSize = 1;
823
796k
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
824
796k
  if (list->items == NULL) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListCreate: allocating item\n");
827
0
      return(-1);
828
0
  }
829
796k
  list->number = 0;
830
796k
  list->size = initialSize;
831
3.97M
    } else if (list->size <= list->number) {
832
31.4k
        if (list->size > 50000000) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
            return(-1);
836
0
        }
837
31.4k
  list->size *= 2;
838
31.4k
  list->items = (void **) xmlRealloc(list->items,
839
31.4k
      list->size * sizeof(void *));
840
31.4k
  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
31.4k
    }
847
4.76M
    list->items[list->number++] = item;
848
4.76M
    return(0);
849
4.76M
}
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
796k
{
861
796k
    xmlPointerListPtr ret;
862
863
796k
    ret = xmlMalloc(sizeof(xmlPointerList));
864
796k
    if (ret == NULL) {
865
0
  xmlXPathErrMemory(NULL,
866
0
      "xmlPointerListCreate: allocating item\n");
867
0
  return (NULL);
868
0
    }
869
796k
    memset(ret, 0, sizeof(xmlPointerList));
870
796k
    if (initialSize > 0) {
871
796k
  xmlPointerListAddSize(ret, NULL, initialSize);
872
796k
  ret->number = 0;
873
796k
    }
874
796k
    return (ret);
875
796k
}
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
796k
{
886
796k
    if (list == NULL)
887
0
  return;
888
796k
    if (list->items != NULL)
889
796k
  xmlFree(list->items);
890
796k
    xmlFree(list);
891
796k
}
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
2.65M
xmlXPathNewCompExpr(void) {
1024
2.65M
    xmlXPathCompExprPtr cur;
1025
1026
2.65M
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1027
2.65M
    if (cur == NULL) {
1028
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1029
0
  return(NULL);
1030
0
    }
1031
2.65M
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1032
2.65M
    cur->maxStep = 10;
1033
2.65M
    cur->nbStep = 0;
1034
2.65M
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1035
2.65M
                                     sizeof(xmlXPathStepOp));
1036
2.65M
    if (cur->steps == NULL) {
1037
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1038
0
  xmlFree(cur);
1039
0
  return(NULL);
1040
0
    }
1041
2.65M
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1042
2.65M
    cur->last = -1;
1043
#ifdef DEBUG_EVAL_COUNTS
1044
    cur->nb = 0;
1045
#endif
1046
2.65M
    return(cur);
1047
2.65M
}
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
2.65M
{
1058
2.65M
    xmlXPathStepOpPtr op;
1059
2.65M
    int i;
1060
1061
2.65M
    if (comp == NULL)
1062
0
        return;
1063
2.65M
    if (comp->dict == NULL) {
1064
11.7M
  for (i = 0; i < comp->nbStep; i++) {
1065
9.13M
      op = &comp->steps[i];
1066
9.13M
      if (op->value4 != NULL) {
1067
1.47M
    if (op->op == XPATH_OP_VALUE)
1068
821k
        xmlXPathFreeObject(op->value4);
1069
653k
    else
1070
653k
        xmlFree(op->value4);
1071
1.47M
      }
1072
9.13M
      if (op->value5 != NULL)
1073
1.75M
    xmlFree(op->value5);
1074
9.13M
  }
1075
2.65M
    } 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
2.65M
    if (comp->steps != NULL) {
1086
2.65M
        xmlFree(comp->steps);
1087
2.65M
    }
1088
#ifdef DEBUG_EVAL_COUNTS
1089
    if (comp->string != NULL) {
1090
        xmlFree(comp->string);
1091
    }
1092
#endif
1093
2.65M
#ifdef XPATH_STREAMING
1094
2.65M
    if (comp->stream != NULL) {
1095
66.2k
        xmlFreePatternList(comp->stream);
1096
66.2k
    }
1097
2.65M
#endif
1098
2.65M
    if (comp->expr != NULL) {
1099
561k
        xmlFree(comp->expr);
1100
561k
    }
1101
1102
2.65M
    xmlFree(comp);
1103
2.65M
}
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
9.14M
   int value2, int value3, void *value4, void *value5) {
1125
9.14M
    xmlXPathCompExprPtr comp = ctxt->comp;
1126
9.14M
    if (comp->nbStep >= comp->maxStep) {
1127
326k
  xmlXPathStepOp *real;
1128
1129
326k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
        }
1133
326k
  comp->maxStep *= 2;
1134
326k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1135
326k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1136
326k
  if (real == NULL) {
1137
0
      comp->maxStep /= 2;
1138
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1139
0
      return(-1);
1140
0
  }
1141
326k
  comp->steps = real;
1142
326k
    }
1143
9.14M
    comp->last = comp->nbStep;
1144
9.14M
    comp->steps[comp->nbStep].ch1 = ch1;
1145
9.14M
    comp->steps[comp->nbStep].ch2 = ch2;
1146
9.14M
    comp->steps[comp->nbStep].op = op;
1147
9.14M
    comp->steps[comp->nbStep].value = value;
1148
9.14M
    comp->steps[comp->nbStep].value2 = value2;
1149
9.14M
    comp->steps[comp->nbStep].value3 = value3;
1150
9.14M
    if ((comp->dict != NULL) &&
1151
9.14M
        ((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
9.14M
    } else {
1166
9.14M
  comp->steps[comp->nbStep].value4 = value4;
1167
9.14M
  comp->steps[comp->nbStep].value5 = value5;
1168
9.14M
    }
1169
9.14M
    comp->steps[comp->nbStep].cache = NULL;
1170
9.14M
    return(comp->nbStep++);
1171
9.14M
}
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
2.83k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1182
2.83k
    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
2.83k
    tmp = op->ch1;
1195
2.83k
    op->ch1 = op->ch2;
1196
2.83k
    op->ch2 = tmp;
1197
2.83k
}
1198
1199
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1200
1.95M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1201
1.95M
                  (op), (val), (val2), (val3), (val4), (val5))
1202
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1203
1.81M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1204
1.81M
                  (op), (val), (val2), (val3), (val4), (val5))
1205
1206
2.17M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1207
2.17M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1208
1209
1.25M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1210
1.25M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1211
1212
1.94M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1213
1.94M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1214
1.94M
      (val), (val2), 0 ,NULL ,NULL)
1215
1216
/************************************************************************
1217
 *                  *
1218
 *    XPath object cache structures       *
1219
 *                  *
1220
 ************************************************************************/
1221
1222
/* #define XP_DEFAULT_CACHE_ON */
1223
1224
712k
#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
624k
{
2212
624k
    xmlXPathContextCachePtr ret;
2213
2214
624k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2215
624k
    if (ret == NULL) {
2216
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2217
0
  return(NULL);
2218
0
    }
2219
624k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2220
624k
    ret->maxNodeset = 100;
2221
624k
    ret->maxString = 100;
2222
624k
    ret->maxBoolean = 100;
2223
624k
    ret->maxNumber = 100;
2224
624k
    ret->maxMisc = 100;
2225
624k
    return(ret);
2226
624k
}
2227
2228
static void
2229
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2230
796k
{
2231
796k
    int i;
2232
796k
    xmlXPathObjectPtr obj;
2233
2234
796k
    if (list == NULL)
2235
0
  return;
2236
2237
2.76M
    for (i = 0; i < list->number; i++) {
2238
1.96M
  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
1.96M
  if (obj->nodesetval != NULL) {
2244
1.33M
      if (obj->nodesetval->nodeTab != NULL)
2245
1.09M
    xmlFree(obj->nodesetval->nodeTab);
2246
1.33M
      xmlFree(obj->nodesetval);
2247
1.33M
  }
2248
1.96M
  xmlFree(obj);
2249
#ifdef XP_DEBUG_OBJ_USAGE
2250
  xmlXPathDebugObjCounterAll--;
2251
#endif
2252
1.96M
    }
2253
796k
    xmlPointerListFree(list);
2254
796k
}
2255
2256
static void
2257
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2258
624k
{
2259
624k
    if (cache == NULL)
2260
0
  return;
2261
624k
    if (cache->nodesetObjs)
2262
307k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2263
624k
    if (cache->stringObjs)
2264
187k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2265
624k
    if (cache->booleanObjs)
2266
79.1k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2267
624k
    if (cache->numberObjs)
2268
134k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2269
624k
    if (cache->miscObjs)
2270
88.1k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2271
624k
    xmlFree(cache);
2272
624k
}
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
1.24M
{
2302
1.24M
    if (ctxt == NULL)
2303
0
  return(-1);
2304
1.24M
    if (active) {
2305
624k
  xmlXPathContextCachePtr cache;
2306
2307
624k
  if (ctxt->cache == NULL) {
2308
624k
      ctxt->cache = xmlXPathNewCache();
2309
624k
      if (ctxt->cache == NULL)
2310
0
    return(-1);
2311
624k
  }
2312
624k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2313
624k
  if (options == 0) {
2314
624k
      if (value < 0)
2315
624k
    value = 100;
2316
624k
      cache->maxNodeset = value;
2317
624k
      cache->maxString = value;
2318
624k
      cache->maxNumber = value;
2319
624k
      cache->maxBoolean = value;
2320
624k
      cache->maxMisc = value;
2321
624k
  }
2322
624k
    } else if (ctxt->cache != NULL) {
2323
624k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2324
624k
  ctxt->cache = NULL;
2325
624k
    }
2326
1.24M
    return(0);
2327
1.24M
}
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
1.42M
{
2342
1.42M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2343
1.42M
  xmlXPathContextCachePtr cache =
2344
1.42M
      (xmlXPathContextCachePtr) ctxt->cache;
2345
2346
1.42M
  if ((cache->miscObjs != NULL) &&
2347
1.42M
      (cache->miscObjs->number != 0))
2348
197k
  {
2349
197k
      xmlXPathObjectPtr ret;
2350
2351
197k
      ret = (xmlXPathObjectPtr)
2352
197k
    cache->miscObjs->items[--cache->miscObjs->number];
2353
197k
      ret->type = XPATH_NODESET;
2354
197k
      ret->nodesetval = val;
2355
#ifdef XP_DEBUG_OBJ_USAGE
2356
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2357
#endif
2358
197k
      return(ret);
2359
197k
  }
2360
1.42M
    }
2361
2362
1.22M
    return(xmlXPathWrapNodeSet(val));
2363
2364
1.42M
}
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
28.4k
{
2379
28.4k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2380
28.4k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2381
2382
28.4k
  if ((cache->stringObjs != NULL) &&
2383
28.4k
      (cache->stringObjs->number != 0))
2384
4.11k
  {
2385
2386
4.11k
      xmlXPathObjectPtr ret;
2387
2388
4.11k
      ret = (xmlXPathObjectPtr)
2389
4.11k
    cache->stringObjs->items[--cache->stringObjs->number];
2390
4.11k
      ret->type = XPATH_STRING;
2391
4.11k
      ret->stringval = val;
2392
#ifdef XP_DEBUG_OBJ_USAGE
2393
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394
#endif
2395
4.11k
      return(ret);
2396
24.2k
  } else if ((cache->miscObjs != NULL) &&
2397
24.2k
      (cache->miscObjs->number != 0))
2398
766
  {
2399
766
      xmlXPathObjectPtr ret;
2400
      /*
2401
      * Fallback to misc-cache.
2402
      */
2403
766
      ret = (xmlXPathObjectPtr)
2404
766
    cache->miscObjs->items[--cache->miscObjs->number];
2405
2406
766
      ret->type = XPATH_STRING;
2407
766
      ret->stringval = val;
2408
#ifdef XP_DEBUG_OBJ_USAGE
2409
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2410
#endif
2411
766
      return(ret);
2412
766
  }
2413
28.4k
    }
2414
23.5k
    return(xmlXPathWrapString(val));
2415
28.4k
}
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
1.28M
{
2431
1.28M
    if ((ctxt != NULL) && (ctxt->cache)) {
2432
1.28M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2433
2434
1.28M
  if ((cache->nodesetObjs != NULL) &&
2435
1.28M
      (cache->nodesetObjs->number != 0))
2436
869k
  {
2437
869k
      xmlXPathObjectPtr ret;
2438
      /*
2439
      * Use the nodeset-cache.
2440
      */
2441
869k
      ret = (xmlXPathObjectPtr)
2442
869k
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2443
869k
      ret->type = XPATH_NODESET;
2444
869k
      ret->boolval = 0;
2445
869k
      if (val) {
2446
866k
    if ((ret->nodesetval->nodeMax == 0) ||
2447
866k
        (val->type == XML_NAMESPACE_DECL))
2448
370k
    {
2449
                    /* TODO: Check memory error. */
2450
370k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2451
495k
    } else {
2452
495k
        ret->nodesetval->nodeTab[0] = val;
2453
495k
        ret->nodesetval->nodeNr = 1;
2454
495k
    }
2455
866k
      }
2456
#ifdef XP_DEBUG_OBJ_USAGE
2457
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458
#endif
2459
869k
      return(ret);
2460
869k
  } else if ((cache->miscObjs != NULL) &&
2461
416k
      (cache->miscObjs->number != 0))
2462
1.64k
  {
2463
1.64k
      xmlXPathObjectPtr ret;
2464
      /*
2465
      * Fallback to misc-cache.
2466
      */
2467
2468
1.64k
      ret = (xmlXPathObjectPtr)
2469
1.64k
    cache->miscObjs->items[--cache->miscObjs->number];
2470
2471
1.64k
      ret->type = XPATH_NODESET;
2472
1.64k
      ret->boolval = 0;
2473
1.64k
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2474
1.64k
      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
1.64k
      return(ret);
2483
1.64k
  }
2484
1.28M
    }
2485
414k
    return(xmlXPathNewNodeSet(val));
2486
1.28M
}
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
4.31k
{
2501
4.31k
    if ((ctxt != NULL) && (ctxt->cache)) {
2502
4.31k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504
4.31k
  if ((cache->stringObjs != NULL) &&
2505
4.31k
      (cache->stringObjs->number != 0))
2506
458
  {
2507
458
      xmlXPathObjectPtr ret;
2508
2509
458
      ret = (xmlXPathObjectPtr)
2510
458
    cache->stringObjs->items[--cache->stringObjs->number];
2511
2512
458
      ret->type = XPATH_STRING;
2513
458
      ret->stringval = xmlStrdup(BAD_CAST val);
2514
#ifdef XP_DEBUG_OBJ_USAGE
2515
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516
#endif
2517
458
      return(ret);
2518
3.85k
  } else if ((cache->miscObjs != NULL) &&
2519
3.85k
      (cache->miscObjs->number != 0))
2520
100
  {
2521
100
      xmlXPathObjectPtr ret;
2522
2523
100
      ret = (xmlXPathObjectPtr)
2524
100
    cache->miscObjs->items[--cache->miscObjs->number];
2525
2526
100
      ret->type = XPATH_STRING;
2527
100
      ret->stringval = xmlStrdup(BAD_CAST val);
2528
#ifdef XP_DEBUG_OBJ_USAGE
2529
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2530
#endif
2531
100
      return(ret);
2532
100
  }
2533
4.31k
    }
2534
3.75k
    return(xmlXPathNewCString(val));
2535
4.31k
}
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
872k
{
2550
872k
    if ((ctxt != NULL) && (ctxt->cache)) {
2551
872k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2552
2553
872k
  if ((cache->stringObjs != NULL) &&
2554
872k
      (cache->stringObjs->number != 0))
2555
156k
  {
2556
156k
      xmlXPathObjectPtr ret;
2557
2558
156k
      ret = (xmlXPathObjectPtr)
2559
156k
    cache->stringObjs->items[--cache->stringObjs->number];
2560
156k
      ret->type = XPATH_STRING;
2561
156k
      if (val != NULL)
2562
156k
    ret->stringval = xmlStrdup(val);
2563
7
      else
2564
7
    ret->stringval = xmlStrdup((const xmlChar *)"");
2565
#ifdef XP_DEBUG_OBJ_USAGE
2566
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2567
#endif
2568
156k
      return(ret);
2569
716k
  } else if ((cache->miscObjs != NULL) &&
2570
716k
      (cache->miscObjs->number != 0))
2571
1.05k
  {
2572
1.05k
      xmlXPathObjectPtr ret;
2573
2574
1.05k
      ret = (xmlXPathObjectPtr)
2575
1.05k
    cache->miscObjs->items[--cache->miscObjs->number];
2576
2577
1.05k
      ret->type = XPATH_STRING;
2578
1.05k
      if (val != NULL)
2579
1.05k
    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
1.05k
      return(ret);
2586
1.05k
  }
2587
872k
    }
2588
715k
    return(xmlXPathNewString(val));
2589
872k
}
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
403k
{
2604
403k
    if ((ctxt != NULL) && (ctxt->cache)) {
2605
403k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607
403k
  if ((cache->booleanObjs != NULL) &&
2608
403k
      (cache->booleanObjs->number != 0))
2609
246k
  {
2610
246k
      xmlXPathObjectPtr ret;
2611
2612
246k
      ret = (xmlXPathObjectPtr)
2613
246k
    cache->booleanObjs->items[--cache->booleanObjs->number];
2614
246k
      ret->type = XPATH_BOOLEAN;
2615
246k
      ret->boolval = (val != 0);
2616
#ifdef XP_DEBUG_OBJ_USAGE
2617
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2618
#endif
2619
246k
      return(ret);
2620
246k
  } else if ((cache->miscObjs != NULL) &&
2621
157k
      (cache->miscObjs->number != 0))
2622
8.36k
  {
2623
8.36k
      xmlXPathObjectPtr ret;
2624
2625
8.36k
      ret = (xmlXPathObjectPtr)
2626
8.36k
    cache->miscObjs->items[--cache->miscObjs->number];
2627
2628
8.36k
      ret->type = XPATH_BOOLEAN;
2629
8.36k
      ret->boolval = (val != 0);
2630
#ifdef XP_DEBUG_OBJ_USAGE
2631
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2632
#endif
2633
8.36k
      return(ret);
2634
8.36k
  }
2635
403k
    }
2636
148k
    return(xmlXPathNewBoolean(val));
2637
403k
}
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
1.23M
{
2652
1.23M
     if ((ctxt != NULL) && (ctxt->cache)) {
2653
1.23M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2654
2655
1.23M
  if ((cache->numberObjs != NULL) &&
2656
1.23M
      (cache->numberObjs->number != 0))
2657
505k
  {
2658
505k
      xmlXPathObjectPtr ret;
2659
2660
505k
      ret = (xmlXPathObjectPtr)
2661
505k
    cache->numberObjs->items[--cache->numberObjs->number];
2662
505k
      ret->type = XPATH_NUMBER;
2663
505k
      ret->floatval = val;
2664
#ifdef XP_DEBUG_OBJ_USAGE
2665
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2666
#endif
2667
505k
      return(ret);
2668
732k
  } else if ((cache->miscObjs != NULL) &&
2669
732k
      (cache->miscObjs->number != 0))
2670
9.68k
  {
2671
9.68k
      xmlXPathObjectPtr ret;
2672
2673
9.68k
      ret = (xmlXPathObjectPtr)
2674
9.68k
    cache->miscObjs->items[--cache->miscObjs->number];
2675
2676
9.68k
      ret->type = XPATH_NUMBER;
2677
9.68k
      ret->floatval = val;
2678
#ifdef XP_DEBUG_OBJ_USAGE
2679
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2680
#endif
2681
9.68k
      return(ret);
2682
9.68k
  }
2683
1.23M
    }
2684
723k
    return(xmlXPathNewFloat(val));
2685
1.23M
}
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
79.3k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2701
79.3k
    xmlChar *res = NULL;
2702
2703
79.3k
    if (val == NULL)
2704
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2705
2706
79.3k
    switch (val->type) {
2707
0
    case XPATH_UNDEFINED:
2708
#ifdef DEBUG_EXPR
2709
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2710
#endif
2711
0
  break;
2712
19.8k
    case XPATH_NODESET:
2713
19.8k
    case XPATH_XSLT_TREE:
2714
19.8k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2715
19.8k
  break;
2716
51.8k
    case XPATH_STRING:
2717
51.8k
  return(val);
2718
1.59k
    case XPATH_BOOLEAN:
2719
1.59k
  res = xmlXPathCastBooleanToString(val->boolval);
2720
1.59k
  break;
2721
5.97k
    case XPATH_NUMBER:
2722
5.97k
  res = xmlXPathCastNumberToString(val->floatval);
2723
5.97k
  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
79.3k
    }
2733
27.4k
    xmlXPathReleaseObject(ctxt, val);
2734
27.4k
    if (res == NULL)
2735
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2736
27.4k
    return(xmlXPathCacheWrapString(ctxt, res));
2737
27.4k
}
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
713k
{
2752
713k
    if (val == NULL)
2753
660
  return(NULL);
2754
2755
712k
    if (XP_HAS_CACHE(ctxt)) {
2756
712k
  switch (val->type) {
2757
0
      case XPATH_NODESET:
2758
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2759
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2760
361k
      case XPATH_STRING:
2761
361k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2762
0
      case XPATH_BOOLEAN:
2763
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2764
351k
      case XPATH_NUMBER:
2765
351k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2766
0
      default:
2767
0
    break;
2768
712k
  }
2769
712k
    }
2770
0
    return(xmlXPathObjectCopy(val));
2771
712k
}
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
97.4k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2786
97.4k
    xmlXPathObjectPtr ret;
2787
2788
97.4k
    if (val == NULL)
2789
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2790
97.4k
    if (val->type == XPATH_BOOLEAN)
2791
18.2k
  return(val);
2792
79.2k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2793
79.2k
    xmlXPathReleaseObject(ctxt, val);
2794
79.2k
    return(ret);
2795
97.4k
}
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
432k
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2810
432k
    xmlXPathObjectPtr ret;
2811
2812
432k
    if (val == NULL)
2813
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2814
432k
    if (val->type == XPATH_NUMBER)
2815
391
  return(val);
2816
432k
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2817
432k
    xmlXPathReleaseObject(ctxt, val);
2818
432k
    return(ret);
2819
432k
}
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
404k
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2837
404k
    int ret;
2838
2839
404k
    if (ctxt == NULL)
2840
0
        return(0);
2841
404k
    ret = ctxt->valueFrame;
2842
404k
    ctxt->valueFrame = ctxt->valueNr;
2843
404k
    return(ret);
2844
404k
}
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
357k
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2855
357k
    if (ctxt == NULL)
2856
0
        return;
2857
357k
    if (ctxt->valueNr < ctxt->valueFrame) {
2858
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859
0
    }
2860
357k
    ctxt->valueFrame = frame;
2861
357k
}
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
5.01M
{
2874
5.01M
    xmlXPathObjectPtr ret;
2875
2876
5.01M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2877
60
        return (NULL);
2878
2879
5.01M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2880
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2881
0
        return (NULL);
2882
0
    }
2883
2884
5.01M
    ctxt->valueNr--;
2885
5.01M
    if (ctxt->valueNr > 0)
2886
2.38M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2887
2.62M
    else
2888
2.62M
        ctxt->value = NULL;
2889
5.01M
    ret = ctxt->valueTab[ctxt->valueNr];
2890
5.01M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2891
5.01M
    return (ret);
2892
5.01M
}
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
5.17M
{
2906
5.17M
    if (ctxt == NULL) return(-1);
2907
5.17M
    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
253
  ctxt->error = XPATH_MEMORY_ERROR;
2913
253
        return(-1);
2914
253
    }
2915
5.17M
    if (ctxt->valueNr >= ctxt->valueMax) {
2916
274
        xmlXPathObjectPtr *tmp;
2917
2918
274
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2919
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2920
0
            return (-1);
2921
0
        }
2922
274
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2923
274
                                             2 * ctxt->valueMax *
2924
274
                                             sizeof(ctxt->valueTab[0]));
2925
274
        if (tmp == NULL) {
2926
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2927
0
            return (-1);
2928
0
        }
2929
274
        ctxt->valueMax *= 2;
2930
274
  ctxt->valueTab = tmp;
2931
274
    }
2932
5.17M
    ctxt->valueTab[ctxt->valueNr] = value;
2933
5.17M
    ctxt->value = value;
2934
5.17M
    return (ctxt->valueNr++);
2935
5.17M
}
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
10.6k
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2948
10.6k
    xmlXPathObjectPtr obj;
2949
10.6k
    int ret;
2950
2951
10.6k
    obj = valuePop(ctxt);
2952
10.6k
    if (obj == NULL) {
2953
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2954
0
  return(0);
2955
0
    }
2956
10.6k
    if (obj->type != XPATH_BOOLEAN)
2957
1.77k
  ret = xmlXPathCastToBoolean(obj);
2958
8.88k
    else
2959
8.88k
        ret = obj->boolval;
2960
10.6k
    xmlXPathReleaseObject(ctxt->context, obj);
2961
10.6k
    return(ret);
2962
10.6k
}
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
11.4k
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2975
11.4k
    xmlXPathObjectPtr obj;
2976
11.4k
    double ret;
2977
2978
11.4k
    obj = valuePop(ctxt);
2979
11.4k
    if (obj == NULL) {
2980
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2981
0
  return(0);
2982
0
    }
2983
11.4k
    if (obj->type != XPATH_NUMBER)
2984
3.19k
  ret = xmlXPathCastToNumber(obj);
2985
8.21k
    else
2986
8.21k
        ret = obj->floatval;
2987
11.4k
    xmlXPathReleaseObject(ctxt->context, obj);
2988
11.4k
    return(ret);
2989
11.4k
}
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
205k
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
3002
205k
    xmlXPathObjectPtr obj;
3003
205k
    xmlChar * ret;
3004
3005
205k
    obj = valuePop(ctxt);
3006
205k
    if (obj == NULL) {
3007
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3008
0
  return(NULL);
3009
0
    }
3010
205k
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3011
    /* TODO: needs refactoring somewhere else */
3012
205k
    if (obj->stringval == ret)
3013
0
  obj->stringval = NULL;
3014
205k
    xmlXPathReleaseObject(ctxt->context, obj);
3015
205k
    return(ret);
3016
205k
}
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
57.4k
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3029
57.4k
    xmlXPathObjectPtr obj;
3030
57.4k
    xmlNodeSetPtr ret;
3031
3032
57.4k
    if (ctxt == NULL) return(NULL);
3033
57.4k
    if (ctxt->value == NULL) {
3034
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3035
0
  return(NULL);
3036
0
    }
3037
57.4k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3038
3.84k
  xmlXPathSetTypeError(ctxt);
3039
3.84k
  return(NULL);
3040
3.84k
    }
3041
53.6k
    obj = valuePop(ctxt);
3042
53.6k
    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
53.6k
    obj->nodesetval = NULL;
3049
53.6k
    xmlXPathReleaseObject(ctxt->context, obj);
3050
53.6k
    return(ret);
3051
57.4k
}
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
2.03k
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3064
2.03k
    xmlXPathObjectPtr obj;
3065
2.03k
    void * ret;
3066
3067
2.03k
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3068
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3069
0
  return(NULL);
3070
0
    }
3071
2.03k
    if (ctxt->value->type != XPATH_USERS) {
3072
0
  xmlXPathSetTypeError(ctxt);
3073
0
  return(NULL);
3074
0
    }
3075
2.03k
    obj = valuePop(ctxt);
3076
2.03k
    ret = obj->user;
3077
2.03k
    obj->user = NULL;
3078
2.03k
    xmlXPathReleaseObject(ctxt->context, obj);
3079
2.03k
    return(ret);
3080
2.03k
}
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
126M
#define CUR (*ctxt->cur)
3106
611k
#define SKIP(val) ctxt->cur += (val)
3107
13.4M
#define NXT(val) ctxt->cur[(val)]
3108
789k
#define CUR_PTR ctxt->cur
3109
24.5M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3110
3111
#define COPY_BUF(l,b,i,v)                                              \
3112
8.31M
    if (l == 1) b[i++] = v;                                            \
3113
8.31M
    else i += xmlCopyChar(l,&b[i],v)
3114
3115
19.3M
#define NEXTL(l)  ctxt->cur += l
3116
3117
#define SKIP_BLANKS             \
3118
57.1M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3119
3120
#define CURRENT (*ctxt->cur)
3121
69.2M
#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
2.96k
#define UPPER_DOUBLE 1E9
3132
2.02k
#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
982
#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
8.43k
{
3150
8.43k
    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
8.43k
    default:
3160
8.43k
  if (xmlXPathIsNaN(number)) {
3161
0
      if (buffersize > (int)sizeof("NaN"))
3162
0
    snprintf(buffer, buffersize, "NaN");
3163
8.43k
  } else if (number == 0) {
3164
            /* Omit sign for negative zero. */
3165
0
      snprintf(buffer, buffersize, "0");
3166
8.43k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3167
8.43k
                   (number == (int) number)) {
3168
5.46k
      char work[30];
3169
5.46k
      char *ptr, *cur;
3170
5.46k
      int value = (int) number;
3171
3172
5.46k
            ptr = &buffer[0];
3173
5.46k
      if (value == 0) {
3174
0
    *ptr++ = '0';
3175
5.46k
      } else {
3176
5.46k
    snprintf(work, 29, "%d", value);
3177
5.46k
    cur = &work[0];
3178
18.2k
    while ((*cur) && (ptr - buffer < buffersize)) {
3179
12.8k
        *ptr++ = *cur++;
3180
12.8k
    }
3181
5.46k
      }
3182
5.46k
      if (ptr - buffer < buffersize) {
3183
5.46k
    *ptr = 0;
3184
5.46k
      } else if (buffersize > 0) {
3185
0
    ptr--;
3186
0
    *ptr = 0;
3187
0
      }
3188
5.46k
  } 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
2.96k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3199
2.96k
      int integer_place, fraction_place;
3200
2.96k
      char *ptr;
3201
2.96k
      char *after_fraction;
3202
2.96k
      double absolute_value;
3203
2.96k
      int size;
3204
3205
2.96k
      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
2.96k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3213
2.96k
      (absolute_value < LOWER_DOUBLE)) &&
3214
2.96k
     (absolute_value != 0.0) ) {
3215
    /* Use scientific notation */
3216
982
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3217
982
    fraction_place = DBL_DIG - 1;
3218
982
    size = snprintf(work, sizeof(work),"%*.*e",
3219
982
       integer_place, fraction_place, number);
3220
4.91k
    while ((size > 0) && (work[size] != 'e')) size--;
3221
3222
982
      }
3223
1.98k
      else {
3224
    /* Use regular notation */
3225
1.98k
    if (absolute_value > 0.0) {
3226
1.98k
        integer_place = (int)log10(absolute_value);
3227
1.98k
        if (integer_place > 0)
3228
490
            fraction_place = DBL_DIG - integer_place - 1;
3229
1.49k
        else
3230
1.49k
            fraction_place = DBL_DIG - integer_place;
3231
1.98k
    } else {
3232
0
        fraction_place = 1;
3233
0
    }
3234
1.98k
    size = snprintf(work, sizeof(work), "%0.*f",
3235
1.98k
        fraction_place, number);
3236
1.98k
      }
3237
3238
      /* Remove leading spaces sometimes inserted by snprintf */
3239
3.77k
      while (work[0] == ' ') {
3240
17.0k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3241
810
    size--;
3242
810
      }
3243
3244
      /* Remove fractional trailing zeroes */
3245
2.96k
      after_fraction = work + size;
3246
2.96k
      ptr = after_fraction;
3247
29.0k
      while (*(--ptr) == '0')
3248
26.0k
    ;
3249
2.96k
      if (*ptr != '.')
3250
2.76k
          ptr++;
3251
6.89k
      while ((*ptr++ = *after_fraction++) != 0);
3252
3253
      /* Finally copy result back to caller */
3254
2.96k
      size = strlen(work) + 1;
3255
2.96k
      if (size > buffersize) {
3256
0
    work[buffersize - 1] = 0;
3257
0
    size = buffersize;
3258
0
      }
3259
2.96k
      memmove(buffer, work, size);
3260
2.96k
  }
3261
8.43k
  break;
3262
8.43k
    }
3263
8.43k
}
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
390
xmlXPathOrderDocElems(xmlDocPtr doc) {
3287
390
    ptrdiff_t count = 0;
3288
390
    xmlNodePtr cur;
3289
3290
390
    if (doc == NULL)
3291
0
  return(-1);
3292
390
    cur = doc->children;
3293
15.6k
    while (cur != NULL) {
3294
15.2k
  if (cur->type == XML_ELEMENT_NODE) {
3295
4.68k
      cur->content = (void *) (-(++count));
3296
4.68k
      if (cur->children != NULL) {
3297
3.51k
    cur = cur->children;
3298
3.51k
    continue;
3299
3.51k
      }
3300
4.68k
  }
3301
11.7k
  if (cur->next != NULL) {
3302
8.19k
      cur = cur->next;
3303
8.19k
      continue;
3304
8.19k
  }
3305
3.90k
  do {
3306
3.90k
      cur = cur->parent;
3307
3.90k
      if (cur == NULL)
3308
0
    break;
3309
3.90k
      if (cur == (xmlNodePtr) doc) {
3310
390
    cur = NULL;
3311
390
    break;
3312
390
      }
3313
3.51k
      if (cur->next != NULL) {
3314
3.12k
    cur = cur->next;
3315
3.12k
    break;
3316
3.12k
      }
3317
3.51k
  } while (cur != NULL);
3318
3.51k
    }
3319
390
    return(count);
3320
390
}
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
1.17k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3334
1.17k
    int depth1, depth2;
3335
1.17k
    int attr1 = 0, attr2 = 0;
3336
1.17k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3337
1.17k
    xmlNodePtr cur, root;
3338
3339
1.17k
    if ((node1 == NULL) || (node2 == NULL))
3340
0
  return(-2);
3341
    /*
3342
     * a couple of optimizations which will avoid computations in most cases
3343
     */
3344
1.17k
    if (node1 == node2)    /* trivial case */
3345
0
  return(0);
3346
1.17k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3347
0
  attr1 = 1;
3348
0
  attrNode1 = node1;
3349
0
  node1 = node1->parent;
3350
0
    }
3351
1.17k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3352
0
  attr2 = 1;
3353
0
  attrNode2 = node2;
3354
0
  node2 = node2->parent;
3355
0
    }
3356
1.17k
    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
1.17k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3375
1.17k
        (node2->type == XML_NAMESPACE_DECL))
3376
0
  return(1);
3377
1.17k
    if (node1 == node2->prev)
3378
6
  return(1);
3379
1.16k
    if (node1 == node2->next)
3380
0
  return(-1);
3381
3382
    /*
3383
     * Speedup using document order if available.
3384
     */
3385
1.16k
    if ((node1->type == XML_ELEMENT_NODE) &&
3386
1.16k
  (node2->type == XML_ELEMENT_NODE) &&
3387
1.16k
  (0 > (ptrdiff_t) node1->content) &&
3388
1.16k
  (0 > (ptrdiff_t) node2->content) &&
3389
1.16k
  (node1->doc == node2->doc)) {
3390
240
  ptrdiff_t l1, l2;
3391
3392
240
  l1 = -((ptrdiff_t) node1->content);
3393
240
  l2 = -((ptrdiff_t) node2->content);
3394
240
  if (l1 < l2)
3395
240
      return(1);
3396
0
  if (l1 > l2)
3397
0
      return(-1);
3398
0
    }
3399
3400
    /*
3401
     * compute depth to root
3402
     */
3403
2.74k
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3404
2.44k
  if (cur->parent == node1)
3405
632
      return(1);
3406
1.81k
  depth2++;
3407
1.81k
    }
3408
292
    root = cur;
3409
734
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3410
442
  if (cur->parent == node2)
3411
0
      return(-1);
3412
442
  depth1++;
3413
442
    }
3414
    /*
3415
     * Distinct document (or distinct entities :-( ) case.
3416
     */
3417
292
    if (root != cur) {
3418
0
  return(-2);
3419
0
    }
3420
    /*
3421
     * get the nearest common ancestor.
3422
     */
3423
295
    while (depth1 > depth2) {
3424
3
  depth1--;
3425
3
  node1 = node1->parent;
3426
3
    }
3427
680
    while (depth2 > depth1) {
3428
388
  depth2--;
3429
388
  node2 = node2->parent;
3430
388
    }
3431
292
    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
292
    if (node1 == node2->prev)
3442
205
  return(1);
3443
87
    if (node1 == node2->next)
3444
0
  return(-1);
3445
    /*
3446
     * Speedup using document order if available.
3447
     */
3448
87
    if ((node1->type == XML_ELEMENT_NODE) &&
3449
87
  (node2->type == XML_ELEMENT_NODE) &&
3450
87
  (0 > (ptrdiff_t) node1->content) &&
3451
87
  (0 > (ptrdiff_t) node2->content) &&
3452
87
  (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
547
    for (cur = node1->next;cur != NULL;cur = cur->next)
3464
547
  if (cur == node2)
3465
87
      return(1);
3466
0
    return(-1); /* assume there is no sibling list corruption */
3467
87
}
3468
3469
/**
3470
 * xmlXPathNodeSetSort:
3471
 * @set:  the node set
3472
 *
3473
 * Sort the node set in document order
3474
 */
3475
void
3476
142k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3477
#ifndef WITH_TIM_SORT
3478
    int i, j, incr, len;
3479
    xmlNodePtr tmp;
3480
#endif
3481
3482
142k
    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
142k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3514
142k
#endif /* WITH_TIM_SORT */
3515
142k
}
3516
3517
4.09M
#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
30.5k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3531
30.5k
    xmlNsPtr cur;
3532
3533
30.5k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3534
0
  return(NULL);
3535
30.5k
    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
30.5k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3542
30.5k
    if (cur == NULL) {
3543
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3544
0
  return(NULL);
3545
0
    }
3546
30.5k
    memset(cur, 0, sizeof(xmlNs));
3547
30.5k
    cur->type = XML_NAMESPACE_DECL;
3548
30.5k
    if (ns->href != NULL)
3549
30.5k
  cur->href = xmlStrdup(ns->href);
3550
30.5k
    if (ns->prefix != NULL)
3551
30.5k
  cur->prefix = xmlStrdup(ns->prefix);
3552
30.5k
    cur->next = (xmlNsPtr) node;
3553
30.5k
    return((xmlNodePtr) cur);
3554
30.5k
}
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
26.6k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3566
26.6k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3567
0
  return;
3568
3569
26.6k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3570
26.6k
  if (ns->href != NULL)
3571
26.6k
      xmlFree((xmlChar *)ns->href);
3572
26.6k
  if (ns->prefix != NULL)
3573
26.6k
      xmlFree((xmlChar *)ns->prefix);
3574
26.6k
  xmlFree(ns);
3575
26.6k
    }
3576
26.6k
}
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
1.81M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3588
1.81M
    xmlNodeSetPtr ret;
3589
3590
1.81M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3591
1.81M
    if (ret == NULL) {
3592
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
  return(NULL);
3594
0
    }
3595
1.81M
    memset(ret, 0 , sizeof(xmlNodeSet));
3596
1.81M
    if (val != NULL) {
3597
348k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3598
348k
               sizeof(xmlNodePtr));
3599
348k
  if (ret->nodeTab == NULL) {
3600
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3601
0
      xmlFree(ret);
3602
0
      return(NULL);
3603
0
  }
3604
348k
  memset(ret->nodeTab, 0 ,
3605
348k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3606
348k
        ret->nodeMax = XML_NODESET_DEFAULT;
3607
348k
  if (val->type == XML_NAMESPACE_DECL) {
3608
3
      xmlNsPtr ns = (xmlNsPtr) val;
3609
3610
            /* TODO: Check memory error. */
3611
3
      ret->nodeTab[ret->nodeNr++] =
3612
3
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3613
3
  } else
3614
348k
      ret->nodeTab[ret->nodeNr++] = val;
3615
348k
    }
3616
1.81M
    return(ret);
3617
1.81M
}
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
20.9k
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3630
20.9k
    int i;
3631
3632
20.9k
    if ((cur == NULL) || (val == NULL)) return(0);
3633
20.9k
    if (val->type == XML_NAMESPACE_DECL) {
3634
332
  for (i = 0; i < cur->nodeNr; i++) {
3635
265
      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
265
  }
3647
20.8k
    } else {
3648
111k
  for (i = 0; i < cur->nodeNr; i++) {
3649
96.5k
      if (cur->nodeTab[i] == val)
3650
6.23k
    return(1);
3651
96.5k
  }
3652
20.8k
    }
3653
14.7k
    return(0);
3654
20.9k
}
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
22.7k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3668
22.7k
    int i;
3669
3670
3671
22.7k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3672
22.7k
        (ns->type != XML_NAMESPACE_DECL) ||
3673
22.7k
  (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
39.2k
    for (i = 0;i < cur->nodeNr;i++) {
3681
16.5k
        if ((cur->nodeTab[i] != NULL) &&
3682
16.5k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3683
16.5k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3684
16.5k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3685
0
      return(0);
3686
16.5k
    }
3687
3688
    /*
3689
     * grow the nodeTab if needed
3690
     */
3691
22.7k
    if (cur->nodeMax == 0) {
3692
2.77k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3693
2.77k
               sizeof(xmlNodePtr));
3694
2.77k
  if (cur->nodeTab == NULL) {
3695
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3696
0
      return(-1);
3697
0
  }
3698
2.77k
  memset(cur->nodeTab, 0 ,
3699
2.77k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3700
2.77k
        cur->nodeMax = XML_NODESET_DEFAULT;
3701
19.9k
    } 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
22.7k
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3719
22.7k
    return(0);
3720
22.7k
}
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
25.4k
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3733
25.4k
    int i;
3734
3735
25.4k
    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
326k
    for (i = 0;i < cur->nodeNr;i++)
3742
314k
        if (cur->nodeTab[i] == val) return(0);
3743
3744
    /*
3745
     * grow the nodeTab if needed
3746
     */
3747
11.5k
    if (cur->nodeMax == 0) {
3748
1.16k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3749
1.16k
               sizeof(xmlNodePtr));
3750
1.16k
  if (cur->nodeTab == NULL) {
3751
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3752
0
      return(-1);
3753
0
  }
3754
1.16k
  memset(cur->nodeTab, 0 ,
3755
1.16k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3756
1.16k
        cur->nodeMax = XML_NODESET_DEFAULT;
3757
10.4k
    } else if (cur->nodeNr == cur->nodeMax) {
3758
684
        xmlNodePtr *temp;
3759
3760
684
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3761
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3762
0
            return(-1);
3763
0
        }
3764
684
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3765
684
              sizeof(xmlNodePtr));
3766
684
  if (temp == NULL) {
3767
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3768
0
      return(-1);
3769
0
  }
3770
684
        cur->nodeMax *= 2;
3771
684
  cur->nodeTab = temp;
3772
684
    }
3773
11.5k
    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
11.5k
  cur->nodeTab[cur->nodeNr++] = val;
3781
11.5k
    return(0);
3782
11.5k
}
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
5.46M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3796
5.46M
    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
5.46M
    if (cur->nodeMax == 0) {
3803
963k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3804
963k
               sizeof(xmlNodePtr));
3805
963k
  if (cur->nodeTab == NULL) {
3806
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3807
0
      return(-1);
3808
0
  }
3809
963k
  memset(cur->nodeTab, 0 ,
3810
963k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3811
963k
        cur->nodeMax = XML_NODESET_DEFAULT;
3812
4.49M
    } else if (cur->nodeNr == cur->nodeMax) {
3813
202k
        xmlNodePtr *temp;
3814
3815
202k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3816
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3817
0
            return(-1);
3818
0
        }
3819
202k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3820
202k
              sizeof(xmlNodePtr));
3821
202k
  if (temp == NULL) {
3822
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3823
0
      return(-1);
3824
0
  }
3825
202k
  cur->nodeTab = temp;
3826
202k
        cur->nodeMax *= 2;
3827
202k
    }
3828
5.46M
    if (val->type == XML_NAMESPACE_DECL) {
3829
2.15k
  xmlNsPtr ns = (xmlNsPtr) val;
3830
3831
        /* TODO: Check memory error. */
3832
2.15k
  cur->nodeTab[cur->nodeNr++] =
3833
2.15k
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3834
2.15k
    } else
3835
5.45M
  cur->nodeTab[cur->nodeNr++] = val;
3836
5.46M
    return(0);
3837
5.46M
}
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
74.4k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3851
74.4k
    int i, j, initNr, skip;
3852
74.4k
    xmlNodePtr n1, n2;
3853
3854
74.4k
    if (val2 == NULL) return(val1);
3855
63.8k
    if (val1 == NULL) {
3856
11.0k
  val1 = xmlXPathNodeSetCreate(NULL);
3857
11.0k
    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
11.0k
    }
3887
3888
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3889
63.8k
    initNr = val1->nodeNr;
3890
3891
384k
    for (i = 0;i < val2->nodeNr;i++) {
3892
320k
  n2 = val2->nodeTab[i];
3893
  /*
3894
   * check against duplicates
3895
   */
3896
320k
  skip = 0;
3897
2.22M
  for (j = 0; j < initNr; j++) {
3898
2.00M
      n1 = val1->nodeTab[j];
3899
2.00M
      if (n1 == n2) {
3900
99.2k
    skip = 1;
3901
99.2k
    break;
3902
1.90M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3903
1.90M
           (n2->type == XML_NAMESPACE_DECL)) {
3904
2.51k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3905
2.51k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3906
297
      ((xmlNsPtr) n2)->prefix)))
3907
186
    {
3908
186
        skip = 1;
3909
186
        break;
3910
186
    }
3911
2.51k
      }
3912
2.00M
  }
3913
320k
  if (skip)
3914
99.4k
      continue;
3915
3916
  /*
3917
   * grow the nodeTab if needed
3918
   */
3919
220k
  if (val1->nodeMax == 0) {
3920
16.2k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3921
16.2k
                sizeof(xmlNodePtr));
3922
16.2k
      if (val1->nodeTab == NULL) {
3923
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3924
0
    return(NULL);
3925
0
      }
3926
16.2k
      memset(val1->nodeTab, 0 ,
3927
16.2k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3928
16.2k
      val1->nodeMax = XML_NODESET_DEFAULT;
3929
204k
  } else if (val1->nodeNr == val1->nodeMax) {
3930
10.9k
      xmlNodePtr *temp;
3931
3932
10.9k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3933
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3934
0
                return(NULL);
3935
0
            }
3936
10.9k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3937
10.9k
               sizeof(xmlNodePtr));
3938
10.9k
      if (temp == NULL) {
3939
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3940
0
    return(NULL);
3941
0
      }
3942
10.9k
      val1->nodeTab = temp;
3943
10.9k
      val1->nodeMax *= 2;
3944
10.9k
  }
3945
220k
  if (n2->type == XML_NAMESPACE_DECL) {
3946
5.69k
      xmlNsPtr ns = (xmlNsPtr) n2;
3947
3948
            /* TODO: Check memory error. */
3949
5.69k
      val1->nodeTab[val1->nodeNr++] =
3950
5.69k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3951
5.69k
  } else
3952
215k
      val1->nodeTab[val1->nodeNr++] = n2;
3953
220k
    }
3954
3955
63.8k
    return(val1);
3956
63.8k
}
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
319k
{
3972
319k
    {
3973
319k
  int i, j, initNbSet1;
3974
319k
  xmlNodePtr n1, n2;
3975
3976
319k
  initNbSet1 = set1->nodeNr;
3977
1.02M
  for (i = 0;i < set2->nodeNr;i++) {
3978
708k
      n2 = set2->nodeTab[i];
3979
      /*
3980
      * Skip duplicates.
3981
      */
3982
8.16M
      for (j = 0; j < initNbSet1; j++) {
3983
8.05M
    n1 = set1->nodeTab[j];
3984
8.05M
    if (n1 == n2) {
3985
601k
        goto skip_node;
3986
7.45M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987
7.45M
        (n2->type == XML_NAMESPACE_DECL))
3988
10.8k
    {
3989
10.8k
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990
10.8k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991
592
      ((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
10.8k
    }
4001
8.05M
      }
4002
      /*
4003
      * grow the nodeTab if needed
4004
      */
4005
106k
      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
106k
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
3.64k
    xmlNodePtr *temp;
4017
4018
3.64k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    return(NULL);
4021
0
                }
4022
3.64k
    temp = (xmlNodePtr *) xmlRealloc(
4023
3.64k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
3.64k
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        return(NULL);
4027
0
    }
4028
3.64k
    set1->nodeTab = temp;
4029
3.64k
    set1->nodeMax *= 2;
4030
3.64k
      }
4031
106k
      set1->nodeTab[set1->nodeNr++] = n2;
4032
708k
skip_node:
4033
708k
      {}
4034
708k
  }
4035
319k
    }
4036
319k
    set2->nodeNr = 0;
4037
319k
    return(set1);
4038
319k
}
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
82.1k
{
4053
82.1k
    {
4054
82.1k
  int i;
4055
82.1k
  xmlNodePtr n2;
4056
4057
230k
  for (i = 0;i < set2->nodeNr;i++) {
4058
147k
      n2 = set2->nodeTab[i];
4059
147k
      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
147k
      } else if (set1->nodeNr >= set1->nodeMax) {
4070
8.26k
    xmlNodePtr *temp;
4071
4072
8.26k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4073
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4074
0
                    return(NULL);
4075
0
                }
4076
8.26k
    temp = (xmlNodePtr *) xmlRealloc(
4077
8.26k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4078
8.26k
    if (temp == NULL) {
4079
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4080
0
        return(NULL);
4081
0
    }
4082
8.26k
    set1->nodeTab = temp;
4083
8.26k
    set1->nodeMax *= 2;
4084
8.26k
      }
4085
147k
      set1->nodeTab[set1->nodeNr++] = n2;
4086
147k
  }
4087
82.1k
    }
4088
82.1k
    set2->nodeNr = 0;
4089
82.1k
    return(set1);
4090
82.1k
}
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
480k
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4157
480k
    if (obj == NULL) return;
4158
477k
    if (obj->nodeTab != NULL) {
4159
231k
  int i;
4160
4161
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4162
1.36M
  for (i = 0;i < obj->nodeNr;i++)
4163
1.13M
      if ((obj->nodeTab[i] != NULL) &&
4164
1.13M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4165
5.97k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4166
231k
  xmlFree(obj->nodeTab);
4167
231k
    }
4168
477k
    xmlFree(obj);
4169
477k
}
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
3.84k
{
4183
3.84k
    if ((set == NULL) || (pos >= set->nodeNr))
4184
0
  return;
4185
3.84k
    else if ((hasNsNodes)) {
4186
1.73k
  int i;
4187
1.73k
  xmlNodePtr node;
4188
4189
11.2k
  for (i = pos; i < set->nodeNr; i++) {
4190
9.50k
      node = set->nodeTab[i];
4191
9.50k
      if ((node != NULL) &&
4192
9.50k
    (node->type == XML_NAMESPACE_DECL))
4193
12
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4194
9.50k
  }
4195
1.73k
    }
4196
3.84k
    set->nodeNr = pos;
4197
3.84k
}
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
2.12k
{
4210
2.12k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4211
2.12k
}
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
59
{
4224
59
    int i;
4225
59
    xmlNodePtr node;
4226
4227
59
    if ((set == NULL) || (set->nodeNr <= 1))
4228
0
  return;
4229
586
    for (i = 0; i < set->nodeNr - 1; i++) {
4230
527
        node = set->nodeTab[i];
4231
527
        if ((node != NULL) &&
4232
527
            (node->type == XML_NAMESPACE_DECL))
4233
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4234
527
    }
4235
59
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4236
59
    set->nodeNr = 1;
4237
59
}
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
532k
xmlXPathNewNodeSet(xmlNodePtr val) {
4319
532k
    xmlXPathObjectPtr ret;
4320
4321
532k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4322
532k
    if (ret == NULL) {
4323
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4324
0
  return(NULL);
4325
0
    }
4326
532k
    memset(ret, 0 , sizeof(xmlXPathObject));
4327
532k
    ret->type = XPATH_NODESET;
4328
532k
    ret->boolval = 0;
4329
    /* TODO: Check memory error. */
4330
532k
    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
532k
    return(ret);
4336
532k
}
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
1.24M
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4410
1.24M
    xmlXPathObjectPtr ret;
4411
4412
1.24M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4413
1.24M
    if (ret == NULL) {
4414
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4415
0
  return(NULL);
4416
0
    }
4417
1.24M
    memset(ret, 0 , sizeof(xmlXPathObject));
4418
1.24M
    ret->type = XPATH_NODESET;
4419
1.24M
    ret->nodesetval = val;
4420
#ifdef XP_DEBUG_OBJ_USAGE
4421
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4422
#endif
4423
1.24M
    return(ret);
4424
1.24M
}
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
1.55k
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4455
1.55k
    xmlNodeSetPtr ret;
4456
1.55k
    int i, l1;
4457
1.55k
    xmlNodePtr cur;
4458
4459
1.55k
    if (xmlXPathNodeSetIsEmpty(nodes2))
4460
529
  return(nodes1);
4461
4462
    /* TODO: Check memory error. */
4463
1.02k
    ret = xmlXPathNodeSetCreate(NULL);
4464
1.02k
    if (xmlXPathNodeSetIsEmpty(nodes1))
4465
367
  return(ret);
4466
4467
662
    l1 = xmlXPathNodeSetGetLength(nodes1);
4468
4469
8.91k
    for (i = 0; i < l1; i++) {
4470
8.25k
  cur = xmlXPathNodeSetItem(nodes1, i);
4471
8.25k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4472
            /* TODO: Propagate memory error. */
4473
5.79k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4474
0
          break;
4475
5.79k
  }
4476
8.25k
    }
4477
662
    return(ret);
4478
1.02k
}
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
1.45k
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4493
1.45k
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4494
1.45k
    int i, l1;
4495
1.45k
    xmlNodePtr cur;
4496
4497
1.45k
    if (ret == NULL)
4498
0
        return(ret);
4499
1.45k
    if (xmlXPathNodeSetIsEmpty(nodes1))
4500
464
  return(ret);
4501
994
    if (xmlXPathNodeSetIsEmpty(nodes2))
4502
400
  return(ret);
4503
4504
594
    l1 = xmlXPathNodeSetGetLength(nodes1);
4505
4506
8.22k
    for (i = 0; i < l1; i++) {
4507
7.62k
  cur = xmlXPathNodeSetItem(nodes1, i);
4508
7.62k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4509
            /* TODO: Propagate memory error. */
4510
2.31k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4511
0
          break;
4512
2.31k
  }
4513
7.62k
    }
4514
594
    return(ret);
4515
994
}
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
845
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4529
845
    xmlNodeSetPtr ret;
4530
845
    xmlHashTablePtr hash;
4531
845
    int i, l;
4532
845
    xmlChar * strval;
4533
845
    xmlNodePtr cur;
4534
4535
845
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
344
  return(nodes);
4537
4538
501
    ret = xmlXPathNodeSetCreate(NULL);
4539
501
    if (ret == NULL)
4540
0
        return(ret);
4541
501
    l = xmlXPathNodeSetGetLength(nodes);
4542
501
    hash = xmlHashCreate (l);
4543
6.67k
    for (i = 0; i < l; i++) {
4544
6.17k
  cur = xmlXPathNodeSetItem(nodes, i);
4545
6.17k
  strval = xmlXPathCastNodeToString(cur);
4546
6.17k
  if (xmlHashLookup(hash, strval) == NULL) {
4547
3.27k
      xmlHashAddEntry(hash, strval, strval);
4548
            /* TODO: Propagate memory error. */
4549
3.27k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4550
0
          break;
4551
3.27k
  } else {
4552
2.89k
      xmlFree(strval);
4553
2.89k
  }
4554
6.17k
    }
4555
501
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4556
501
    return(ret);
4557
501
}
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
1.46k
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4593
1.46k
    int i, l;
4594
1.46k
    xmlNodePtr cur;
4595
4596
1.46k
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4597
1.46k
  xmlXPathNodeSetIsEmpty(nodes2))
4598
905
  return(0);
4599
4600
564
    l = xmlXPathNodeSetGetLength(nodes1);
4601
3.63k
    for (i = 0; i < l; i++) {
4602
3.40k
  cur = xmlXPathNodeSetItem(nodes1, i);
4603
3.40k
  if (xmlXPathNodeSetContains(nodes2, cur))
4604
335
      return(1);
4605
3.40k
    }
4606
229
    return(0);
4607
564
}
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
1.06k
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4623
1.06k
    int i, l;
4624
1.06k
    xmlNodePtr cur;
4625
1.06k
    xmlNodeSetPtr ret;
4626
4627
1.06k
    if (node == NULL)
4628
0
  return(nodes);
4629
4630
1.06k
    ret = xmlXPathNodeSetCreate(NULL);
4631
1.06k
    if (ret == NULL)
4632
0
        return(ret);
4633
1.06k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4634
1.06k
  (!xmlXPathNodeSetContains(nodes, node)))
4635
634
  return(ret);
4636
4637
428
    l = xmlXPathNodeSetGetLength(nodes);
4638
7.08k
    for (i = 0; i < l; i++) {
4639
7.08k
  cur = xmlXPathNodeSetItem(nodes, i);
4640
7.08k
  if (cur == node)
4641
428
      break;
4642
        /* TODO: Propagate memory error. */
4643
6.65k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4644
0
      break;
4645
6.65k
    }
4646
428
    return(ret);
4647
1.06k
}
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
1.38k
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4729
1.38k
    int i, l;
4730
1.38k
    xmlNodePtr cur;
4731
1.38k
    xmlNodeSetPtr ret;
4732
4733
1.38k
    if (node == NULL)
4734
0
  return(nodes);
4735
4736
1.38k
    ret = xmlXPathNodeSetCreate(NULL);
4737
1.38k
    if (ret == NULL)
4738
0
        return(ret);
4739
1.38k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4740
1.38k
  (!xmlXPathNodeSetContains(nodes, node)))
4741
687
  return(ret);
4742
4743
697
    l = xmlXPathNodeSetGetLength(nodes);
4744
8.42k
    for (i = l - 1; i >= 0; i--) {
4745
8.42k
  cur = xmlXPathNodeSetItem(nodes, i);
4746
8.42k
  if (cur == node)
4747
697
      break;
4748
        /* TODO: Propagate memory error. */
4749
7.72k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4750
0
      break;
4751
7.72k
    }
4752
697
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4753
697
    return(ret);
4754
1.38k
}
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
25.6k
         xmlXPathFunction f) {
4841
25.6k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4842
25.6k
}
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
26.4k
           const xmlChar *ns_uri, xmlXPathFunction f) {
4858
26.4k
    if (ctxt == NULL)
4859
0
  return(-1);
4860
26.4k
    if (name == NULL)
4861
0
  return(-1);
4862
4863
26.4k
    if (ctxt->funcHash == NULL)
4864
0
  ctxt->funcHash = xmlHashCreate(0);
4865
26.4k
    if (ctxt->funcHash == NULL)
4866
0
  return(-1);
4867
26.4k
    if (f == NULL)
4868
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4869
26.4k
XML_IGNORE_FPTR_CAST_WARNINGS
4870
26.4k
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4871
26.4k
XML_POP_WARNINGS
4872
26.4k
}
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
390
          void *funcCtxt) {
4886
390
    if (ctxt == NULL)
4887
0
  return;
4888
390
    ctxt->funcLookupFunc = f;
4889
390
    ctxt->funcLookupData = funcCtxt;
4890
390
}
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
151k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4904
151k
    if (ctxt == NULL)
4905
0
  return (NULL);
4906
4907
151k
    if (ctxt->funcLookupFunc != NULL) {
4908
151k
  xmlXPathFunction ret;
4909
151k
  xmlXPathFuncLookupFunc f;
4910
4911
151k
  f = ctxt->funcLookupFunc;
4912
151k
  ret = f(ctxt->funcLookupData, name, NULL);
4913
151k
  if (ret != NULL)
4914
0
      return(ret);
4915
151k
    }
4916
151k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4917
151k
}
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
378k
       const xmlChar *ns_uri) {
4933
378k
    xmlXPathFunction ret;
4934
4935
378k
    if (ctxt == NULL)
4936
0
  return(NULL);
4937
378k
    if (name == NULL)
4938
0
  return(NULL);
4939
4940
378k
    if (ctxt->funcLookupFunc != NULL) {
4941
378k
  xmlXPathFuncLookupFunc f;
4942
4943
378k
  f = ctxt->funcLookupFunc;
4944
378k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4945
378k
  if (ret != NULL)
4946
212k
      return(ret);
4947
378k
    }
4948
4949
165k
    if (ctxt->funcHash == NULL)
4950
0
  return(NULL);
4951
4952
165k
XML_IGNORE_FPTR_CAST_WARNINGS
4953
165k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4954
165k
XML_POP_WARNINGS
4955
165k
    return(ret);
4956
165k
}
4957
4958
/**
4959
 * xmlXPathRegisteredFuncsCleanup:
4960
 * @ctxt:  the XPath context
4961
 *
4962
 * Cleanup the XPath context data associated to registered functions
4963
 */
4964
void
4965
40
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4966
40
    if (ctxt == NULL)
4967
0
  return;
4968
4969
40
    xmlHashFree(ctxt->funcHash, NULL);
4970
40
    ctxt->funcHash = NULL;
4971
40
}
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
1.56k
       xmlXPathObjectPtr value) {
4993
1.56k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4994
1.56k
}
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
1.56k
         xmlXPathObjectPtr value) {
5012
1.56k
    if (ctxt == NULL)
5013
0
  return(-1);
5014
1.56k
    if (name == NULL)
5015
0
  return(-1);
5016
5017
1.56k
    if (ctxt->varHash == NULL)
5018
390
  ctxt->varHash = xmlHashCreate(0);
5019
1.56k
    if (ctxt->varHash == NULL)
5020
0
  return(-1);
5021
1.56k
    if (value == NULL)
5022
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5023
0
                             xmlXPathFreeObjectEntry));
5024
1.56k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5025
1.56k
             (void *) value, xmlXPathFreeObjectEntry));
5026
1.56k
}
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
390
   xmlXPathVariableLookupFunc f, void *data) {
5039
390
    if (ctxt == NULL)
5040
0
  return;
5041
390
    ctxt->varLookupFunc = f;
5042
390
    ctxt->varLookupData = data;
5043
390
}
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
7.62k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5057
7.62k
    if (ctxt == NULL)
5058
0
  return(NULL);
5059
5060
7.62k
    if (ctxt->varLookupFunc != NULL) {
5061
7.62k
  xmlXPathObjectPtr ret;
5062
5063
7.62k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5064
7.62k
          (ctxt->varLookupData, name, NULL);
5065
7.62k
  return(ret);
5066
7.62k
    }
5067
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5068
7.62k
}
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
660
       const xmlChar *ns_uri) {
5084
660
    if (ctxt == NULL)
5085
0
  return(NULL);
5086
5087
660
    if (ctxt->varLookupFunc != NULL) {
5088
660
  xmlXPathObjectPtr ret;
5089
5090
660
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5091
660
          (ctxt->varLookupData, name, ns_uri);
5092
660
  if (ret != NULL) return(ret);
5093
660
    }
5094
5095
660
    if (ctxt->varHash == NULL)
5096
0
  return(NULL);
5097
660
    if (name == NULL)
5098
0
  return(NULL);
5099
5100
660
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5101
660
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5102
660
}
5103
5104
/**
5105
 * xmlXPathRegisteredVariablesCleanup:
5106
 * @ctxt:  the XPath context
5107
 *
5108
 * Cleanup the XPath context data associated to registered variables
5109
 */
5110
void
5111
40
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5112
40
    if (ctxt == NULL)
5113
0
  return;
5114
5115
40
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5116
40
    ctxt->varHash = NULL;
5117
40
}
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
4.29k
         const xmlChar *ns_uri) {
5133
4.29k
    if (ctxt == NULL)
5134
0
  return(-1);
5135
4.29k
    if (prefix == NULL)
5136
0
  return(-1);
5137
4.29k
    if (prefix[0] == 0)
5138
0
  return(-1);
5139
5140
4.29k
    if (ctxt->nsHash == NULL)
5141
390
  ctxt->nsHash = xmlHashCreate(10);
5142
4.29k
    if (ctxt->nsHash == NULL)
5143
0
  return(-1);
5144
4.29k
    if (ns_uri == NULL)
5145
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5146
0
                            xmlHashDefaultDeallocator));
5147
4.29k
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5148
4.29k
            xmlHashDefaultDeallocator));
5149
4.29k
}
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
305k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5163
305k
    if (ctxt == NULL)
5164
0
  return(NULL);
5165
305k
    if (prefix == NULL)
5166
0
  return(NULL);
5167
5168
305k
#ifdef XML_XML_NAMESPACE
5169
305k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5170
1.36k
  return(XML_XML_NAMESPACE);
5171
304k
#endif
5172
5173
304k
    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
304k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5184
304k
}
5185
5186
/**
5187
 * xmlXPathRegisteredNsCleanup:
5188
 * @ctxt:  the XPath context
5189
 *
5190
 * Cleanup the XPath context data associated to registered variables
5191
 */
5192
void
5193
40
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5194
40
    if (ctxt == NULL)
5195
0
  return;
5196
5197
40
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5198
40
    ctxt->nsHash = NULL;
5199
40
}
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
765k
xmlXPathNewFloat(double val) {
5219
765k
    xmlXPathObjectPtr ret;
5220
5221
765k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5222
765k
    if (ret == NULL) {
5223
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5224
0
  return(NULL);
5225
0
    }
5226
765k
    memset(ret, 0 , sizeof(xmlXPathObject));
5227
765k
    ret->type = XPATH_NUMBER;
5228
765k
    ret->floatval = val;
5229
#ifdef XP_DEBUG_OBJ_USAGE
5230
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5231
#endif
5232
765k
    return(ret);
5233
765k
}
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
153k
xmlXPathNewBoolean(int val) {
5245
153k
    xmlXPathObjectPtr ret;
5246
5247
153k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248
153k
    if (ret == NULL) {
5249
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5250
0
  return(NULL);
5251
0
    }
5252
153k
    memset(ret, 0 , sizeof(xmlXPathObject));
5253
153k
    ret->type = XPATH_BOOLEAN;
5254
153k
    ret->boolval = (val != 0);
5255
#ifdef XP_DEBUG_OBJ_USAGE
5256
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5257
#endif
5258
153k
    return(ret);
5259
153k
}
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
733k
xmlXPathNewString(const xmlChar *val) {
5271
733k
    xmlXPathObjectPtr ret;
5272
5273
733k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5274
733k
    if (ret == NULL) {
5275
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5276
0
  return(NULL);
5277
0
    }
5278
733k
    memset(ret, 0 , sizeof(xmlXPathObject));
5279
733k
    ret->type = XPATH_STRING;
5280
733k
    if (val != NULL)
5281
733k
  ret->stringval = xmlStrdup(val);
5282
451
    else
5283
451
  ret->stringval = xmlStrdup((const xmlChar *)"");
5284
#ifdef XP_DEBUG_OBJ_USAGE
5285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5286
#endif
5287
733k
    return(ret);
5288
733k
}
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
62.1k
xmlXPathWrapString (xmlChar *val) {
5300
62.1k
    xmlXPathObjectPtr ret;
5301
5302
62.1k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5303
62.1k
    if (ret == NULL) {
5304
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5305
0
  return(NULL);
5306
0
    }
5307
62.1k
    memset(ret, 0 , sizeof(xmlXPathObject));
5308
62.1k
    ret->type = XPATH_STRING;
5309
62.1k
    ret->stringval = val;
5310
#ifdef XP_DEBUG_OBJ_USAGE
5311
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5312
#endif
5313
62.1k
    return(ret);
5314
62.1k
}
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
29.3k
xmlXPathNewCString(const char *val) {
5326
29.3k
    xmlXPathObjectPtr ret;
5327
5328
29.3k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5329
29.3k
    if (ret == NULL) {
5330
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5331
0
  return(NULL);
5332
0
    }
5333
29.3k
    memset(ret, 0 , sizeof(xmlXPathObject));
5334
29.3k
    ret->type = XPATH_STRING;
5335
29.3k
    ret->stringval = xmlStrdup(BAD_CAST val);
5336
#ifdef XP_DEBUG_OBJ_USAGE
5337
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5338
#endif
5339
29.3k
    return(ret);
5340
29.3k
}
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
3.04k
xmlXPathWrapExternal (void *val) {
5365
3.04k
    xmlXPathObjectPtr ret;
5366
5367
3.04k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5368
3.04k
    if (ret == NULL) {
5369
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5370
0
  return(NULL);
5371
0
    }
5372
3.04k
    memset(ret, 0 , sizeof(xmlXPathObject));
5373
3.04k
    ret->type = XPATH_USERS;
5374
3.04k
    ret->user = val;
5375
#ifdef XP_DEBUG_OBJ_USAGE
5376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5377
#endif
5378
3.04k
    return(ret);
5379
3.04k
}
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
237
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5391
237
    xmlXPathObjectPtr ret;
5392
5393
237
    if (val == NULL)
5394
0
  return(NULL);
5395
5396
237
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5397
237
    if (ret == NULL) {
5398
0
        xmlXPathErrMemory(NULL, "copying object\n");
5399
0
  return(NULL);
5400
0
    }
5401
237
    memcpy(ret, val , sizeof(xmlXPathObject));
5402
#ifdef XP_DEBUG_OBJ_USAGE
5403
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5404
#endif
5405
237
    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
237
  case XPATH_NODESET:
5450
            /* TODO: Check memory error. */
5451
237
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452
      /* Do not deallocate the copied tree value */
5453
237
      ret->boolval = 0;
5454
237
      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
237
    }
5472
237
    return(ret);
5473
237
}
5474
5475
/**
5476
 * xmlXPathFreeObject:
5477
 * @obj:  the object to free
5478
 *
5479
 * Free up an xmlXPathObjectPtr object.
5480
 */
5481
void
5482
3.71M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483
3.71M
    if (obj == NULL) return;
5484
1.54M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485
346k
  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
346k
  } else {
5496
346k
      if (obj->nodesetval != NULL)
5497
322k
    xmlXPathFreeNodeSet(obj->nodesetval);
5498
346k
  }
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.20M
    } else if (obj->type == XPATH_STRING) {
5505
544k
  if (obj->stringval != NULL)
5506
544k
      xmlFree(obj->stringval);
5507
544k
    }
5508
#ifdef XP_DEBUG_OBJ_USAGE
5509
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510
#endif
5511
1.54M
    xmlFree(obj);
5512
1.54M
}
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.97M
{
5529
3.97M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5530
796k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5531
3.97M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5532
5533
4.01M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5534
5535
3.97M
    if (obj == NULL)
5536
0
  return;
5537
3.97M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5538
13
   xmlXPathFreeObject(obj);
5539
3.97M
    } else {
5540
3.97M
  xmlXPathContextCachePtr cache =
5541
3.97M
      (xmlXPathContextCachePtr) ctxt->cache;
5542
5543
3.97M
  switch (obj->type) {
5544
2.49M
      case XPATH_NODESET:
5545
2.49M
      case XPATH_XSLT_TREE:
5546
2.49M
    if (obj->nodesetval != NULL) {
5547
2.25M
        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.25M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5557
2.25M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5558
2.25M
          cache->maxNodeset)))
5559
2.20M
        {
5560
2.20M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5561
2.20M
      goto obj_cached;
5562
2.20M
        } else {
5563
47.2k
      xmlXPathFreeNodeSet(obj->nodesetval);
5564
47.2k
      obj->nodesetval = NULL;
5565
47.2k
        }
5566
2.25M
    }
5567
290k
    break;
5568
443k
      case XPATH_STRING:
5569
443k
    if (obj->stringval != NULL)
5570
443k
        xmlFree(obj->stringval);
5571
5572
443k
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5573
443k
        XP_CACHE_ADD(cache->stringObjs, obj);
5574
443k
        goto obj_cached;
5575
443k
    }
5576
0
    break;
5577
317k
      case XPATH_BOOLEAN:
5578
317k
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5579
317k
        XP_CACHE_ADD(cache->booleanObjs, obj);
5580
317k
        goto obj_cached;
5581
317k
    }
5582
0
    break;
5583
712k
      case XPATH_NUMBER:
5584
712k
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5585
712k
        XP_CACHE_ADD(cache->numberObjs, obj);
5586
712k
        goto obj_cached;
5587
712k
    }
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
3.02k
      default:
5597
3.02k
    goto free_obj;
5598
3.97M
  }
5599
5600
  /*
5601
  * Fallback to adding to the misc-objects slot.
5602
  */
5603
290k
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5604
290k
      XP_CACHE_ADD(cache->miscObjs, obj);
5605
290k
  } else
5606
0
      goto free_obj;
5607
5608
3.97M
obj_cached:
5609
5610
#ifdef XP_DEBUG_OBJ_USAGE
5611
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5612
#endif
5613
5614
3.97M
  if (obj->nodesetval != NULL) {
5615
2.20M
      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
2.20M
      if (tmpset->nodeNr > 1) {
5624
180k
    int i;
5625
180k
    xmlNodePtr node;
5626
5627
3.35M
    for (i = 0; i < tmpset->nodeNr; i++) {
5628
3.17M
        node = tmpset->nodeTab[i];
5629
3.17M
        if ((node != NULL) &&
5630
3.17M
      (node->type == XML_NAMESPACE_DECL))
5631
18.4k
        {
5632
18.4k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5633
18.4k
        }
5634
3.17M
    }
5635
2.02M
      } else if (tmpset->nodeNr == 1) {
5636
1.40M
    if ((tmpset->nodeTab[0] != NULL) &&
5637
1.40M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5638
1.45k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5639
1.40M
      }
5640
2.20M
      tmpset->nodeNr = 0;
5641
2.20M
      memset(obj, 0, sizeof(xmlXPathObject));
5642
2.20M
      obj->nodesetval = tmpset;
5643
2.20M
  } else
5644
1.76M
      memset(obj, 0, sizeof(xmlXPathObject));
5645
5646
3.97M
  return;
5647
5648
3.02k
free_obj:
5649
  /*
5650
  * Cache is full; free the object.
5651
  */
5652
3.02k
  if (obj->nodesetval != NULL)
5653
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5654
#ifdef XP_DEBUG_OBJ_USAGE
5655
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5656
#endif
5657
3.02k
  xmlFree(obj);
5658
3.02k
    }
5659
3.03k
    return;
5660
3.97M
}
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
3.97k
xmlXPathCastBooleanToString (int val) {
5679
3.97k
    xmlChar *ret;
5680
3.97k
    if (val)
5681
800
  ret = xmlStrdup((const xmlChar *) "true");
5682
3.17k
    else
5683
3.17k
  ret = xmlStrdup((const xmlChar *) "false");
5684
3.97k
    return(ret);
5685
3.97k
}
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
19.2k
xmlXPathCastNumberToString (double val) {
5697
19.2k
    xmlChar *ret;
5698
19.2k
    switch (xmlXPathIsInf(val)) {
5699
123
    case 1:
5700
123
  ret = xmlStrdup((const xmlChar *) "Infinity");
5701
123
  break;
5702
33
    case -1:
5703
33
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5704
33
  break;
5705
19.0k
    default:
5706
19.0k
  if (xmlXPathIsNaN(val)) {
5707
8.07k
      ret = xmlStrdup((const xmlChar *) "NaN");
5708
10.9k
  } else if (val == 0) {
5709
            /* Omit sign for negative zero. */
5710
2.56k
      ret = xmlStrdup((const xmlChar *) "0");
5711
8.43k
  } else {
5712
      /* could be improved */
5713
8.43k
      char buf[100];
5714
8.43k
      xmlXPathFormatNumber(val, buf, 99);
5715
8.43k
      buf[99] = 0;
5716
8.43k
      ret = xmlStrdup((const xmlChar *) buf);
5717
8.43k
  }
5718
19.2k
    }
5719
19.2k
    return(ret);
5720
19.2k
}
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
517k
xmlXPathCastNodeToString (xmlNodePtr node) {
5732
517k
xmlChar *ret;
5733
517k
    if ((ret = xmlNodeGetContent(node)) == NULL)
5734
0
  ret = xmlStrdup((const xmlChar *) "");
5735
517k
    return(ret);
5736
517k
}
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
417k
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5748
417k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5749
229k
  return(xmlStrdup((const xmlChar *) ""));
5750
5751
188k
    if (ns->nodeNr > 1)
5752
45.3k
  xmlXPathNodeSetSort(ns);
5753
188k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5754
417k
}
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
205k
xmlXPathCastToString(xmlXPathObjectPtr val) {
5767
205k
    xmlChar *ret = NULL;
5768
5769
205k
    if (val == NULL)
5770
0
  return(xmlStrdup((const xmlChar *) ""));
5771
205k
    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
5.96k
        case XPATH_NODESET:
5779
5.96k
        case XPATH_XSLT_TREE:
5780
5.96k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5781
5.96k
      break;
5782
192k
  case XPATH_STRING:
5783
192k
      return(xmlStrdup(val->stringval));
5784
2.34k
        case XPATH_BOOLEAN:
5785
2.34k
      ret = xmlXPathCastBooleanToString(val->boolval);
5786
2.34k
      break;
5787
4.87k
  case XPATH_NUMBER: {
5788
4.87k
      ret = xmlXPathCastNumberToString(val->floatval);
5789
4.87k
      break;
5790
5.96k
  }
5791
1
  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
1
      TODO
5798
1
      ret = xmlStrdup((const xmlChar *) "");
5799
1
      break;
5800
205k
    }
5801
13.1k
    return(ret);
5802
205k
}
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
439
xmlXPathConvertString(xmlXPathObjectPtr val) {
5815
439
    xmlChar *res = NULL;
5816
5817
439
    if (val == NULL)
5818
0
  return(xmlXPathNewCString(""));
5819
5820
439
    switch (val->type) {
5821
0
    case XPATH_UNDEFINED:
5822
#ifdef DEBUG_EXPR
5823
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5824
#endif
5825
0
  break;
5826
298
    case XPATH_NODESET:
5827
298
    case XPATH_XSLT_TREE:
5828
298
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5829
298
  break;
5830
0
    case XPATH_STRING:
5831
0
  return(val);
5832
38
    case XPATH_BOOLEAN:
5833
38
  res = xmlXPathCastBooleanToString(val->boolval);
5834
38
  break;
5835
103
    case XPATH_NUMBER:
5836
103
  res = xmlXPathCastNumberToString(val->floatval);
5837
103
  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
439
    }
5847
439
    xmlXPathFreeObject(val);
5848
439
    if (res == NULL)
5849
0
  return(xmlXPathNewCString(""));
5850
439
    return(xmlXPathWrapString(res));
5851
439
}
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
116k
xmlXPathCastBooleanToNumber(int val) {
5863
116k
    if (val)
5864
13.0k
  return(1.0);
5865
103k
    return(0.0);
5866
116k
}
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
721k
xmlXPathCastStringToNumber(const xmlChar * val) {
5878
721k
    return(xmlXPathStringEvalNumber(val));
5879
721k
}
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
152k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5891
152k
    xmlChar *strval;
5892
152k
    double ret;
5893
5894
152k
    if (node == NULL)
5895
0
  return(xmlXPathNAN);
5896
152k
    strval = xmlXPathCastNodeToString(node);
5897
152k
    if (strval == NULL)
5898
0
  return(xmlXPathNAN);
5899
152k
    ret = xmlXPathCastStringToNumber(strval);
5900
152k
    xmlFree(strval);
5901
5902
152k
    return(ret);
5903
152k
}
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
420k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5915
420k
    xmlChar *str;
5916
420k
    double ret;
5917
5918
420k
    if (ns == NULL)
5919
28.7k
  return(xmlXPathNAN);
5920
391k
    str = xmlXPathCastNodeSetToString(ns);
5921
391k
    ret = xmlXPathCastStringToNumber(str);
5922
391k
    xmlFree(str);
5923
391k
    return(ret);
5924
420k
}
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
800k
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5936
800k
    double ret = 0.0;
5937
5938
800k
    if (val == NULL)
5939
0
  return(xmlXPathNAN);
5940
800k
    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
420k
    case XPATH_NODESET:
5948
420k
    case XPATH_XSLT_TREE:
5949
420k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5950
420k
  break;
5951
173k
    case XPATH_STRING:
5952
173k
  ret = xmlXPathCastStringToNumber(val->stringval);
5953
173k
  break;
5954
90.1k
    case XPATH_NUMBER:
5955
90.1k
  ret = val->floatval;
5956
90.1k
  break;
5957
116k
    case XPATH_BOOLEAN:
5958
116k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5959
116k
  break;
5960
101
    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
101
  TODO;
5967
101
  ret = xmlXPathNAN;
5968
101
  break;
5969
800k
    }
5970
800k
    return(ret);
5971
800k
}
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
33.3k
xmlXPathCastNumberToBoolean (double val) {
6005
33.3k
     if (xmlXPathIsNaN(val) || (val == 0.0))
6006
10.9k
   return(0);
6007
22.3k
     return(1);
6008
33.3k
}
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
1.23k
xmlXPathCastStringToBoolean (const xmlChar *val) {
6020
1.23k
    if ((val == NULL) || (xmlStrlen(val) == 0))
6021
179
  return(0);
6022
1.05k
    return(1);
6023
1.23k
}
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
66.9k
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6035
66.9k
    if ((ns == NULL) || (ns->nodeNr == 0))
6036
58.9k
  return(0);
6037
8.03k
    return(1);
6038
66.9k
}
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
80.9k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6050
80.9k
    int ret = 0;
6051
6052
80.9k
    if (val == NULL)
6053
0
  return(0);
6054
80.9k
    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
66.9k
    case XPATH_NODESET:
6062
66.9k
    case XPATH_XSLT_TREE:
6063
66.9k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6064
66.9k
  break;
6065
1.23k
    case XPATH_STRING:
6066
1.23k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6067
1.23k
  break;
6068
12.7k
    case XPATH_NUMBER:
6069
12.7k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6070
12.7k
  break;
6071
0
    case XPATH_BOOLEAN:
6072
0
  ret = val->boolval;
6073
0
  break;
6074
9
    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
9
  TODO;
6081
9
  ret = 0;
6082
9
  break;
6083
80.9k
    }
6084
80.9k
    return(ret);
6085
80.9k
}
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
820
xmlXPathNewContext(xmlDocPtr doc) {
6126
820
    xmlXPathContextPtr ret;
6127
6128
820
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6129
820
    if (ret == NULL) {
6130
0
        xmlXPathErrMemory(NULL, "creating context\n");
6131
0
  return(NULL);
6132
0
    }
6133
820
    memset(ret, 0 , sizeof(xmlXPathContext));
6134
820
    ret->doc = doc;
6135
820
    ret->node = NULL;
6136
6137
820
    ret->varHash = NULL;
6138
6139
820
    ret->nb_types = 0;
6140
820
    ret->max_types = 0;
6141
820
    ret->types = NULL;
6142
6143
820
    ret->funcHash = xmlHashCreate(0);
6144
6145
820
    ret->nb_axis = 0;
6146
820
    ret->max_axis = 0;
6147
820
    ret->axis = NULL;
6148
6149
820
    ret->nsHash = NULL;
6150
820
    ret->user = NULL;
6151
6152
820
    ret->contextSize = -1;
6153
820
    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
820
    xmlXPathRegisterAllFunctions(ret);
6163
6164
820
    return(ret);
6165
820
}
6166
6167
/**
6168
 * xmlXPathFreeContext:
6169
 * @ctxt:  the context to free
6170
 *
6171
 * Free up an xmlXPathContext
6172
 */
6173
void
6174
40
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175
40
    if (ctxt == NULL) return;
6176
6177
40
    if (ctxt->cache != NULL)
6178
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179
40
    xmlXPathRegisteredNsCleanup(ctxt);
6180
40
    xmlXPathRegisteredFuncsCleanup(ctxt);
6181
40
    xmlXPathRegisteredVariablesCleanup(ctxt);
6182
40
    xmlResetError(&ctxt->lastError);
6183
40
    xmlFree(ctxt);
6184
40
}
6185
6186
/************************************************************************
6187
 *                  *
6188
 *    Routines to handle XPath parser contexts    *
6189
 *                  *
6190
 ************************************************************************/
6191
6192
#define CHECK_CTXT(ctxt)            \
6193
1.89k
    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
675k
    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
2.59M
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234
2.59M
    xmlXPathParserContextPtr ret;
6235
6236
2.59M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6237
2.59M
    if (ret == NULL) {
6238
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6239
0
  return(NULL);
6240
0
    }
6241
2.59M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6242
2.59M
    ret->cur = ret->base = str;
6243
2.59M
    ret->context = ctxt;
6244
6245
2.59M
    ret->comp = xmlXPathNewCompExpr();
6246
2.59M
    if (ret->comp == NULL) {
6247
0
  xmlFree(ret->valueTab);
6248
0
  xmlFree(ret);
6249
0
  return(NULL);
6250
0
    }
6251
2.59M
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252
0
        ret->comp->dict = ctxt->dict;
6253
0
  xmlDictReference(ret->comp->dict);
6254
0
    }
6255
6256
2.59M
    return(ret);
6257
2.59M
}
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
675k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270
675k
    xmlXPathParserContextPtr ret;
6271
6272
675k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6273
675k
    if (ret == NULL) {
6274
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6275
0
  return(NULL);
6276
0
    }
6277
675k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6278
6279
    /* Allocate the value stack */
6280
675k
    ret->valueTab = (xmlXPathObjectPtr *)
6281
675k
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282
675k
    if (ret->valueTab == NULL) {
6283
0
  xmlFree(ret);
6284
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285
0
  return(NULL);
6286
0
    }
6287
675k
    ret->valueNr = 0;
6288
675k
    ret->valueMax = 10;
6289
675k
    ret->value = NULL;
6290
675k
    ret->valueFrame = 0;
6291
6292
675k
    ret->context = ctxt;
6293
675k
    ret->comp = comp;
6294
6295
675k
    return(ret);
6296
675k
}
6297
6298
/**
6299
 * xmlXPathFreeParserContext:
6300
 * @ctxt:  the context to free
6301
 *
6302
 * Free up an xmlXPathParserContext
6303
 */
6304
void
6305
3.26M
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6306
3.26M
    int i;
6307
6308
3.26M
    if (ctxt->valueTab != NULL) {
6309
836k
        for (i = 0; i < ctxt->valueNr; i++) {
6310
160k
            if (ctxt->context)
6311
160k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6312
0
            else
6313
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6314
160k
        }
6315
676k
        xmlFree(ctxt->valueTab);
6316
676k
    }
6317
3.26M
    if (ctxt->comp != NULL) {
6318
2.02M
#ifdef XPATH_STREAMING
6319
2.02M
  if (ctxt->comp->stream != NULL) {
6320
223
      xmlFreePatternList(ctxt->comp->stream);
6321
223
      ctxt->comp->stream = NULL;
6322
223
  }
6323
2.02M
#endif
6324
2.02M
  xmlXPathFreeCompExpr(ctxt->comp);
6325
2.02M
    }
6326
3.26M
    xmlFree(ctxt);
6327
3.26M
}
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
46.4k
xmlXPathNodeValHash(xmlNodePtr node) {
6346
46.4k
    int len = 2;
6347
46.4k
    const xmlChar * string = NULL;
6348
46.4k
    xmlNodePtr tmp = NULL;
6349
46.4k
    unsigned int ret = 0;
6350
6351
46.4k
    if (node == NULL)
6352
0
  return(0);
6353
6354
46.4k
    if (node->type == XML_DOCUMENT_NODE) {
6355
4.55k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6356
4.55k
  if (tmp == NULL)
6357
0
      node = node->children;
6358
4.55k
  else
6359
4.55k
      node = tmp;
6360
6361
4.55k
  if (node == NULL)
6362
0
      return(0);
6363
4.55k
    }
6364
6365
46.4k
    switch (node->type) {
6366
816
  case XML_COMMENT_NODE:
6367
1.68k
  case XML_PI_NODE:
6368
2.26k
  case XML_CDATA_SECTION_NODE:
6369
14.8k
  case XML_TEXT_NODE:
6370
14.8k
      string = node->content;
6371
14.8k
      if (string == NULL)
6372
0
    return(0);
6373
14.8k
      if (string[0] == 0)
6374
1
    return(0);
6375
14.8k
      return(string[0] + (string[1] << 8));
6376
575
  case XML_NAMESPACE_DECL:
6377
575
      string = ((xmlNsPtr)node)->href;
6378
575
      if (string == NULL)
6379
0
    return(0);
6380
575
      if (string[0] == 0)
6381
0
    return(0);
6382
575
      return(string[0] + (string[1] << 8));
6383
2.01k
  case XML_ATTRIBUTE_NODE:
6384
2.01k
      tmp = ((xmlAttrPtr) node)->children;
6385
2.01k
      break;
6386
28.9k
  case XML_ELEMENT_NODE:
6387
28.9k
      tmp = node->children;
6388
28.9k
      break;
6389
0
  default:
6390
0
      return(0);
6391
46.4k
    }
6392
34.8k
    while (tmp != NULL) {
6393
25.8k
  switch (tmp->type) {
6394
1.32k
      case XML_CDATA_SECTION_NODE:
6395
25.8k
      case XML_TEXT_NODE:
6396
25.8k
    string = tmp->content;
6397
25.8k
    break;
6398
0
      default:
6399
0
                string = NULL;
6400
0
    break;
6401
25.8k
  }
6402
25.8k
  if ((string != NULL) && (string[0] != 0)) {
6403
25.8k
      if (len == 1) {
6404
0
    return(ret + (string[0] << 8));
6405
0
      }
6406
25.8k
      if (string[1] == 0) {
6407
3.83k
    len = 1;
6408
3.83k
    ret = string[0];
6409
22.0k
      } else {
6410
22.0k
    return(string[0] + (string[1] << 8));
6411
22.0k
      }
6412
25.8k
  }
6413
  /*
6414
   * Skip to next node
6415
   */
6416
3.85k
  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
3.85k
  if (tmp == node)
6423
0
      break;
6424
6425
3.85k
  if (tmp->next != NULL) {
6426
0
      tmp = tmp->next;
6427
0
      continue;
6428
0
  }
6429
6430
3.85k
  do {
6431
3.85k
      tmp = tmp->parent;
6432
3.85k
      if (tmp == NULL)
6433
0
    break;
6434
3.85k
      if (tmp == node) {
6435
3.85k
    tmp = NULL;
6436
3.85k
    break;
6437
3.85k
      }
6438
0
      if (tmp->next != NULL) {
6439
0
    tmp = tmp->next;
6440
0
    break;
6441
0
      }
6442
0
  } while (tmp != NULL);
6443
3.85k
    }
6444
8.96k
    return(ret);
6445
31.0k
}
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
2.83k
xmlXPathStringHash(const xmlChar * string) {
6458
2.83k
    if (string == NULL)
6459
0
  return(0);
6460
2.83k
    if (string[0] == 0)
6461
471
  return(0);
6462
2.36k
    return(string[0] + (string[1] << 8));
6463
2.83k
}
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
27.3k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6490
27.3k
    int i, ret = 0;
6491
27.3k
    xmlNodeSetPtr ns;
6492
27.3k
    xmlChar *str2;
6493
6494
27.3k
    if ((f == NULL) || (arg == NULL) ||
6495
27.3k
  ((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
27.3k
    ns = arg->nodesetval;
6501
27.3k
    if (ns != NULL) {
6502
79.7k
  for (i = 0;i < ns->nodeNr;i++) {
6503
56.5k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6504
56.5k
       if (str2 != NULL) {
6505
56.5k
     valuePush(ctxt,
6506
56.5k
         xmlXPathCacheNewString(ctxt->context, str2));
6507
56.5k
     xmlFree(str2);
6508
56.5k
     xmlXPathNumberFunction(ctxt, 1);
6509
56.5k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6510
56.5k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6511
56.5k
     if (ret)
6512
1.26k
         break;
6513
56.5k
       }
6514
56.5k
  }
6515
24.5k
    }
6516
27.3k
    xmlXPathReleaseObject(ctxt->context, arg);
6517
27.3k
    xmlXPathReleaseObject(ctxt->context, f);
6518
27.3k
    return(ret);
6519
27.3k
}
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
4.25k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6545
4.25k
    int i, ret = 0;
6546
4.25k
    xmlNodeSetPtr ns;
6547
4.25k
    xmlChar *str2;
6548
6549
4.25k
    if ((s == NULL) || (arg == NULL) ||
6550
4.25k
  ((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
4.25k
    ns = arg->nodesetval;
6556
4.25k
    if (ns != NULL) {
6557
28.8k
  for (i = 0;i < ns->nodeNr;i++) {
6558
25.1k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6559
25.1k
       if (str2 != NULL) {
6560
25.1k
     valuePush(ctxt,
6561
25.1k
         xmlXPathCacheNewString(ctxt->context, str2));
6562
25.1k
     xmlFree(str2);
6563
25.1k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6564
25.1k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6565
25.1k
     if (ret)
6566
61
         break;
6567
25.1k
       }
6568
25.1k
  }
6569
3.72k
    }
6570
4.25k
    xmlXPathReleaseObject(ctxt->context, arg);
6571
4.25k
    xmlXPathReleaseObject(ctxt->context, s);
6572
4.25k
    return(ret);
6573
4.25k
}
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
41.0k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6606
41.0k
    int i, j, init = 0;
6607
41.0k
    double val1;
6608
41.0k
    double *values2;
6609
41.0k
    int ret = 0;
6610
41.0k
    xmlNodeSetPtr ns1;
6611
41.0k
    xmlNodeSetPtr ns2;
6612
6613
41.0k
    if ((arg1 == NULL) ||
6614
41.0k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6615
0
  xmlXPathFreeObject(arg2);
6616
0
        return(0);
6617
0
    }
6618
41.0k
    if ((arg2 == NULL) ||
6619
41.0k
  ((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
41.0k
    ns1 = arg1->nodesetval;
6626
41.0k
    ns2 = arg2->nodesetval;
6627
6628
41.0k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6629
29.9k
  xmlXPathFreeObject(arg1);
6630
29.9k
  xmlXPathFreeObject(arg2);
6631
29.9k
  return(0);
6632
29.9k
    }
6633
11.0k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6634
5.22k
  xmlXPathFreeObject(arg1);
6635
5.22k
  xmlXPathFreeObject(arg2);
6636
5.22k
  return(0);
6637
5.22k
    }
6638
6639
5.87k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6640
5.87k
    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
71.3k
    for (i = 0;i < ns1->nodeNr;i++) {
6648
65.6k
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6649
65.6k
  if (xmlXPathIsNaN(val1))
6650
59.9k
      continue;
6651
53.7k
  for (j = 0;j < ns2->nodeNr;j++) {
6652
48.2k
      if (init == 0) {
6653
27.7k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6654
27.7k
      }
6655
48.2k
      if (xmlXPathIsNaN(values2[j]))
6656
44.3k
    continue;
6657
3.91k
      if (inf && strict)
6658
1.63k
    ret = (val1 < values2[j]);
6659
2.28k
      else if (inf && !strict)
6660
64
    ret = (val1 <= values2[j]);
6661
2.21k
      else if (!inf && strict)
6662
2.14k
    ret = (val1 > values2[j]);
6663
73
      else if (!inf && !strict)
6664
73
    ret = (val1 >= values2[j]);
6665
3.91k
      if (ret)
6666
233
    break;
6667
3.91k
  }
6668
5.78k
  if (ret)
6669
233
      break;
6670
5.55k
  init = 1;
6671
5.55k
    }
6672
5.87k
    xmlFree(values2);
6673
5.87k
    xmlXPathFreeObject(arg1);
6674
5.87k
    xmlXPathFreeObject(arg2);
6675
5.87k
    return(ret);
6676
5.87k
}
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
79.3k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6702
79.3k
    if ((val == NULL) || (arg == NULL) ||
6703
79.3k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6704
0
        return(0);
6705
6706
79.3k
    switch(val->type) {
6707
27.3k
        case XPATH_NUMBER:
6708
27.3k
      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
4.25k
        case XPATH_STRING:
6713
4.25k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6714
47.6k
        case XPATH_BOOLEAN:
6715
47.6k
      valuePush(ctxt, arg);
6716
47.6k
      xmlXPathBooleanFunction(ctxt, 1);
6717
47.6k
      valuePush(ctxt, val);
6718
47.6k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6719
54
  default:
6720
54
            xmlGenericError(xmlGenericErrorContext,
6721
54
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6722
54
                    "and object of type %d\n",
6723
54
                    val->type);
6724
54
            xmlXPathReleaseObject(ctxt->context, arg);
6725
54
            xmlXPathReleaseObject(ctxt->context, val);
6726
54
            XP_ERROR0(XPATH_INVALID_TYPE);
6727
79.3k
    }
6728
0
    return(0);
6729
79.3k
}
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
5.46k
{
6748
5.46k
    int i;
6749
5.46k
    xmlNodeSetPtr ns;
6750
5.46k
    xmlChar *str2;
6751
5.46k
    unsigned int hash;
6752
6753
5.46k
    if ((str == NULL) || (arg == NULL) ||
6754
5.46k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6755
0
        return (0);
6756
5.46k
    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
5.46k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6762
2.62k
        return (0);
6763
2.83k
    hash = xmlXPathStringHash(str);
6764
19.3k
    for (i = 0; i < ns->nodeNr; i++) {
6765
16.8k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6766
204
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6767
204
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6768
126
                xmlFree(str2);
6769
126
    if (neq)
6770
3
        continue;
6771
123
                return (1);
6772
126
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6773
0
    if (neq)
6774
0
        continue;
6775
0
                return (1);
6776
78
            } else if (neq) {
6777
0
    if (str2 != NULL)
6778
0
        xmlFree(str2);
6779
0
    return (1);
6780
0
      }
6781
78
            if (str2 != NULL)
6782
78
                xmlFree(str2);
6783
16.6k
        } else if (neq)
6784
186
      return (1);
6785
16.8k
    }
6786
2.53k
    return (0);
6787
2.83k
}
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
23.2k
    xmlXPathObjectPtr arg, double f, int neq) {
6807
23.2k
  int i, ret=0;
6808
23.2k
  xmlNodeSetPtr ns;
6809
23.2k
  xmlChar *str2;
6810
23.2k
  xmlXPathObjectPtr val;
6811
23.2k
  double v;
6812
6813
23.2k
    if ((arg == NULL) ||
6814
23.2k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6815
0
        return(0);
6816
6817
23.2k
    ns = arg->nodesetval;
6818
23.2k
    if (ns != NULL) {
6819
63.6k
  for (i=0;i<ns->nodeNr;i++) {
6820
43.2k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6821
43.2k
      if (str2 != NULL) {
6822
43.2k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6823
43.2k
    xmlFree(str2);
6824
43.2k
    xmlXPathNumberFunction(ctxt, 1);
6825
43.2k
    val = valuePop(ctxt);
6826
43.2k
    v = val->floatval;
6827
43.2k
    xmlXPathReleaseObject(ctxt->context, val);
6828
43.2k
    if (!xmlXPathIsNaN(v)) {
6829
3.90k
        if ((!neq) && (v==f)) {
6830
132
      ret = 1;
6831
132
      break;
6832
3.77k
        } else if ((neq) && (v!=f)) {
6833
536
      ret = 1;
6834
536
      break;
6835
536
        }
6836
39.3k
    } else { /* NaN is unequal to any value */
6837
39.3k
        if (neq)
6838
6.24k
      ret = 1;
6839
39.3k
    }
6840
43.2k
      }
6841
43.2k
  }
6842
20.9k
    }
6843
6844
23.2k
    return(ret);
6845
23.2k
}
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
25.4k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6867
25.4k
    int i, j;
6868
25.4k
    unsigned int *hashs1;
6869
25.4k
    unsigned int *hashs2;
6870
25.4k
    xmlChar **values1;
6871
25.4k
    xmlChar **values2;
6872
25.4k
    int ret = 0;
6873
25.4k
    xmlNodeSetPtr ns1;
6874
25.4k
    xmlNodeSetPtr ns2;
6875
6876
25.4k
    if ((arg1 == NULL) ||
6877
25.4k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6878
0
        return(0);
6879
25.4k
    if ((arg2 == NULL) ||
6880
25.4k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6881
0
        return(0);
6882
6883
25.4k
    ns1 = arg1->nodesetval;
6884
25.4k
    ns2 = arg2->nodesetval;
6885
6886
25.4k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6887
15.2k
  return(0);
6888
10.1k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6889
2.96k
  return(0);
6890
6891
    /*
6892
     * for equal, check if there is a node pertaining to both sets
6893
     */
6894
7.21k
    if (neq == 0)
6895
29.8k
  for (i = 0;i < ns1->nodeNr;i++)
6896
97.0k
      for (j = 0;j < ns2->nodeNr;j++)
6897
73.6k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6898
2.32k
        return(1);
6899
6900
4.88k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6901
4.88k
    if (values1 == NULL) {
6902
        /* TODO: Propagate memory error. */
6903
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6904
0
  return(0);
6905
0
    }
6906
4.88k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6907
4.88k
    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
4.88k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6914
4.88k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6915
4.88k
    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
4.88k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6923
4.88k
    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
4.88k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932
17.1k
    for (i = 0;i < ns1->nodeNr;i++) {
6933
14.0k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934
54.6k
  for (j = 0;j < ns2->nodeNr;j++) {
6935
42.3k
      if (i == 0)
6936
15.5k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937
42.3k
      if (hashs1[i] != hashs2[j]) {
6938
33.2k
    if (neq) {
6939
206
        ret = 1;
6940
206
        break;
6941
206
    }
6942
33.2k
      }
6943
9.10k
      else {
6944
9.10k
    if (values1[i] == NULL)
6945
5.90k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946
9.10k
    if (values2[j] == NULL)
6947
6.56k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948
9.10k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949
9.10k
    if (ret)
6950
1.56k
        break;
6951
9.10k
      }
6952
42.3k
  }
6953
14.0k
  if (ret)
6954
1.76k
      break;
6955
14.0k
    }
6956
27.4k
    for (i = 0;i < ns1->nodeNr;i++)
6957
22.6k
  if (values1[i] != NULL)
6958
5.90k
      xmlFree(values1[i]);
6959
28.0k
    for (j = 0;j < ns2->nodeNr;j++)
6960
23.2k
  if (values2[j] != NULL)
6961
6.56k
      xmlFree(values2[j]);
6962
4.88k
    xmlFree(values1);
6963
4.88k
    xmlFree(values2);
6964
4.88k
    xmlFree(hashs1);
6965
4.88k
    xmlFree(hashs2);
6966
4.88k
    return(ret);
6967
4.88k
}
6968
6969
static int
6970
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971
64.8k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972
64.8k
    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
64.8k
    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
33.2k
        case XPATH_BOOLEAN:
6985
33.2k
      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
13.1k
    case XPATH_BOOLEAN:
6993
#ifdef DEBUG_EXPR
6994
        xmlGenericError(xmlGenericErrorContext,
6995
          "Equal: %d boolean %d \n",
6996
          arg1->boolval, arg2->boolval);
6997
#endif
6998
13.1k
        ret = (arg1->boolval == arg2->boolval);
6999
13.1k
        break;
7000
17.9k
    case XPATH_NUMBER:
7001
17.9k
        ret = (arg1->boolval ==
7002
17.9k
         xmlXPathCastNumberToBoolean(arg2->floatval));
7003
17.9k
        break;
7004
2.07k
    case XPATH_STRING:
7005
2.07k
        if ((arg2->stringval == NULL) ||
7006
2.07k
      (arg2->stringval[0] == 0)) ret = 0;
7007
1.93k
        else
7008
1.93k
      ret = 1;
7009
2.07k
        ret = (arg1->boolval == ret);
7010
2.07k
        break;
7011
8
    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
8
        TODO
7018
8
        break;
7019
0
    case XPATH_NODESET:
7020
0
    case XPATH_XSLT_TREE:
7021
0
        break;
7022
33.2k
      }
7023
33.2k
      break;
7024
33.2k
        case XPATH_NUMBER:
7025
28.6k
      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
2.55k
    case XPATH_BOOLEAN:
7033
2.55k
        ret = (arg2->boolval==
7034
2.55k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7035
2.55k
        break;
7036
2.34k
    case XPATH_STRING:
7037
2.34k
        valuePush(ctxt, arg2);
7038
2.34k
        xmlXPathNumberFunction(ctxt, 1);
7039
2.34k
        arg2 = valuePop(ctxt);
7040
                    /* Falls through. */
7041
26.1k
    case XPATH_NUMBER:
7042
        /* Hand check NaN and Infinity equalities */
7043
26.1k
        if (xmlXPathIsNaN(arg1->floatval) ||
7044
26.1k
          xmlXPathIsNaN(arg2->floatval)) {
7045
7.77k
            ret = 0;
7046
18.3k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047
276
            if (xmlXPathIsInf(arg2->floatval) == 1)
7048
26
          ret = 1;
7049
250
      else
7050
250
          ret = 0;
7051
18.0k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052
115
      if (xmlXPathIsInf(arg2->floatval) == -1)
7053
2
          ret = 1;
7054
113
      else
7055
113
          ret = 0;
7056
17.9k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057
195
      if (xmlXPathIsInf(arg1->floatval) == 1)
7058
0
          ret = 1;
7059
195
      else
7060
195
          ret = 0;
7061
17.7k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062
40
      if (xmlXPathIsInf(arg1->floatval) == -1)
7063
0
          ret = 1;
7064
40
      else
7065
40
          ret = 0;
7066
17.7k
        } else {
7067
17.7k
            ret = (arg1->floatval == arg2->floatval);
7068
17.7k
        }
7069
26.1k
        break;
7070
4
    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
4
        TODO
7077
4
        break;
7078
0
    case XPATH_NODESET:
7079
0
    case XPATH_XSLT_TREE:
7080
0
        break;
7081
28.6k
      }
7082
28.6k
      break;
7083
28.6k
        case XPATH_STRING:
7084
2.94k
      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
392
    case XPATH_BOOLEAN:
7092
392
        if ((arg1->stringval == NULL) ||
7093
392
      (arg1->stringval[0] == 0)) ret = 0;
7094
332
        else
7095
332
      ret = 1;
7096
392
        ret = (arg2->boolval == ret);
7097
392
        break;
7098
1.04k
    case XPATH_STRING:
7099
1.04k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7100
1.04k
        break;
7101
1.51k
    case XPATH_NUMBER:
7102
1.51k
        valuePush(ctxt, arg1);
7103
1.51k
        xmlXPathNumberFunction(ctxt, 1);
7104
1.51k
        arg1 = valuePop(ctxt);
7105
        /* Hand check NaN and Infinity equalities */
7106
1.51k
        if (xmlXPathIsNaN(arg1->floatval) ||
7107
1.51k
          xmlXPathIsNaN(arg2->floatval)) {
7108
1.32k
            ret = 0;
7109
1.32k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7110
2
      if (xmlXPathIsInf(arg2->floatval) == 1)
7111
0
          ret = 1;
7112
2
      else
7113
2
          ret = 0;
7114
188
        } 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
188
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7120
1
      if (xmlXPathIsInf(arg1->floatval) == 1)
7121
0
          ret = 1;
7122
1
      else
7123
1
          ret = 0;
7124
187
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7125
1
      if (xmlXPathIsInf(arg1->floatval) == -1)
7126
0
          ret = 1;
7127
1
      else
7128
1
          ret = 0;
7129
186
        } else {
7130
186
            ret = (arg1->floatval == arg2->floatval);
7131
186
        }
7132
1.51k
        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
2.94k
      }
7145
2.94k
      break;
7146
2.94k
        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
20
      TODO
7153
20
      break;
7154
0
  case XPATH_NODESET:
7155
0
  case XPATH_XSLT_TREE:
7156
0
      break;
7157
64.8k
    }
7158
64.8k
    xmlXPathReleaseObject(ctxt->context, arg1);
7159
64.8k
    xmlXPathReleaseObject(ctxt->context, arg2);
7160
64.8k
    return(ret);
7161
64.8k
}
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
130k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7173
130k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7174
130k
    int ret = 0;
7175
7176
130k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7177
130k
    arg2 = valuePop(ctxt);
7178
130k
    arg1 = valuePop(ctxt);
7179
130k
    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
130k
    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
130k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7200
130k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7201
  /*
7202
   *Hack it to assure arg1 is the nodeset
7203
   */
7204
74.4k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7205
32.8k
    argtmp = arg2;
7206
32.8k
    arg2 = arg1;
7207
32.8k
    arg1 = argtmp;
7208
32.8k
  }
7209
74.4k
  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
21.9k
      case XPATH_NODESET:
7217
21.9k
      case XPATH_XSLT_TREE:
7218
21.9k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7219
21.9k
    break;
7220
28.4k
      case XPATH_BOOLEAN:
7221
28.4k
    if ((arg1->nodesetval == NULL) ||
7222
28.4k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7223
4.53k
    else
7224
4.53k
        ret = 1;
7225
28.4k
    ret = (ret == arg2->boolval);
7226
28.4k
    break;
7227
19.1k
      case XPATH_NUMBER:
7228
19.1k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7229
19.1k
    break;
7230
4.93k
      case XPATH_STRING:
7231
4.93k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7232
4.93k
    break;
7233
24
      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
24
    TODO
7240
24
    break;
7241
74.4k
  }
7242
74.4k
  xmlXPathReleaseObject(ctxt->context, arg1);
7243
74.4k
  xmlXPathReleaseObject(ctxt->context, arg2);
7244
74.4k
  return(ret);
7245
74.4k
    }
7246
7247
55.6k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248
130k
}
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
24.7k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260
24.7k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7261
24.7k
    int ret = 0;
7262
7263
24.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264
24.7k
    arg2 = valuePop(ctxt);
7265
24.7k
    arg1 = valuePop(ctxt);
7266
24.7k
    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
24.7k
    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
24.7k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287
24.7k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288
  /*
7289
   *Hack it to assure arg1 is the nodeset
7290
   */
7291
15.5k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292
8.36k
    argtmp = arg2;
7293
8.36k
    arg2 = arg1;
7294
8.36k
    arg1 = argtmp;
7295
8.36k
  }
7296
15.5k
  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
3.51k
      case XPATH_NODESET:
7304
3.51k
      case XPATH_XSLT_TREE:
7305
3.51k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306
3.51k
    break;
7307
7.40k
      case XPATH_BOOLEAN:
7308
7.40k
    if ((arg1->nodesetval == NULL) ||
7309
7.40k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7310
449
    else
7311
449
        ret = 1;
7312
7.40k
    ret = (ret != arg2->boolval);
7313
7.40k
    break;
7314
4.11k
      case XPATH_NUMBER:
7315
4.11k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316
4.11k
    break;
7317
533
      case XPATH_STRING:
7318
533
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319
533
    break;
7320
3
      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
3
    TODO
7327
3
    break;
7328
15.5k
  }
7329
15.5k
  xmlXPathReleaseObject(ctxt->context, arg1);
7330
15.5k
  xmlXPathReleaseObject(ctxt->context, arg2);
7331
15.5k
  return(ret);
7332
15.5k
    }
7333
7334
9.18k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7335
24.7k
}
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
285k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7363
285k
    int ret = 0, arg1i = 0, arg2i = 0;
7364
285k
    xmlXPathObjectPtr arg1, arg2;
7365
7366
285k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7367
285k
    arg2 = valuePop(ctxt);
7368
285k
    arg1 = valuePop(ctxt);
7369
285k
    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
285k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7378
285k
      (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
120k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7385
120k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7386
41.0k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7387
79.3k
  } else {
7388
79.3k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7389
20.1k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7390
20.1k
                                arg1, arg2);
7391
59.1k
      } else {
7392
59.1k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7393
59.1k
                                arg2, arg1);
7394
59.1k
      }
7395
79.3k
  }
7396
120k
  return(ret);
7397
120k
    }
7398
7399
164k
    if (arg1->type != XPATH_NUMBER) {
7400
93.3k
  valuePush(ctxt, arg1);
7401
93.3k
  xmlXPathNumberFunction(ctxt, 1);
7402
93.3k
  arg1 = valuePop(ctxt);
7403
93.3k
    }
7404
164k
    if (arg1->type != XPATH_NUMBER) {
7405
0
  xmlXPathFreeObject(arg1);
7406
0
  xmlXPathFreeObject(arg2);
7407
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7408
0
    }
7409
164k
    if (arg2->type != XPATH_NUMBER) {
7410
75.0k
  valuePush(ctxt, arg2);
7411
75.0k
  xmlXPathNumberFunction(ctxt, 1);
7412
75.0k
  arg2 = valuePop(ctxt);
7413
75.0k
    }
7414
164k
    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
164k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7425
92.7k
  ret=0;
7426
92.7k
    } else {
7427
72.2k
  arg1i=xmlXPathIsInf(arg1->floatval);
7428
72.2k
  arg2i=xmlXPathIsInf(arg2->floatval);
7429
72.2k
  if (inf && strict) {
7430
35.7k
      if ((arg1i == -1 && arg2i != -1) ||
7431
35.7k
    (arg2i == 1 && arg1i != 1)) {
7432
602
    ret = 1;
7433
35.1k
      } else if (arg1i == 0 && arg2i == 0) {
7434
35.1k
    ret = (arg1->floatval < arg2->floatval);
7435
35.1k
      } else {
7436
13
    ret = 0;
7437
13
      }
7438
35.7k
  }
7439
36.4k
  else if (inf && !strict) {
7440
6.56k
      if (arg1i == -1 || arg2i == 1) {
7441
266
    ret = 1;
7442
6.30k
      } else if (arg1i == 0 && arg2i == 0) {
7443
6.29k
    ret = (arg1->floatval <= arg2->floatval);
7444
6.29k
      } else {
7445
6
    ret = 0;
7446
6
      }
7447
6.56k
  }
7448
29.9k
  else if (!inf && strict) {
7449
24.3k
      if ((arg1i == 1 && arg2i != 1) ||
7450
24.3k
    (arg2i == -1 && arg1i != -1)) {
7451
401
    ret = 1;
7452
23.9k
      } else if (arg1i == 0 && arg2i == 0) {
7453
23.9k
    ret = (arg1->floatval > arg2->floatval);
7454
23.9k
      } else {
7455
26
    ret = 0;
7456
26
      }
7457
24.3k
  }
7458
5.51k
  else if (!inf && !strict) {
7459
5.51k
      if (arg1i == 1 || arg2i == -1) {
7460
102
    ret = 1;
7461
5.41k
      } else if (arg1i == 0 && arg2i == 0) {
7462
5.39k
    ret = (arg1->floatval >= arg2->floatval);
7463
5.39k
      } else {
7464
14
    ret = 0;
7465
14
      }
7466
5.51k
  }
7467
72.2k
    }
7468
164k
    xmlXPathReleaseObject(ctxt->context, arg1);
7469
164k
    xmlXPathReleaseObject(ctxt->context, arg2);
7470
164k
    return(ret);
7471
164k
}
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
64.3k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7483
64.3k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7484
64.3k
    CAST_TO_NUMBER;
7485
64.3k
    CHECK_TYPE(XPATH_NUMBER);
7486
64.3k
    ctxt->value->floatval = -ctxt->value->floatval;
7487
64.3k
}
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
34.7k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7499
34.7k
    xmlXPathObjectPtr arg;
7500
34.7k
    double val;
7501
7502
34.7k
    arg = valuePop(ctxt);
7503
34.7k
    if (arg == NULL)
7504
34.7k
  XP_ERROR(XPATH_INVALID_OPERAND);
7505
34.7k
    val = xmlXPathCastToNumber(arg);
7506
34.7k
    xmlXPathReleaseObject(ctxt->context, arg);
7507
34.7k
    CAST_TO_NUMBER;
7508
34.7k
    CHECK_TYPE(XPATH_NUMBER);
7509
34.7k
    ctxt->value->floatval += val;
7510
34.7k
}
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
75.0k
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7522
75.0k
    xmlXPathObjectPtr arg;
7523
75.0k
    double val;
7524
7525
75.0k
    arg = valuePop(ctxt);
7526
75.0k
    if (arg == NULL)
7527
75.0k
  XP_ERROR(XPATH_INVALID_OPERAND);
7528
75.0k
    val = xmlXPathCastToNumber(arg);
7529
75.0k
    xmlXPathReleaseObject(ctxt->context, arg);
7530
75.0k
    CAST_TO_NUMBER;
7531
75.0k
    CHECK_TYPE(XPATH_NUMBER);
7532
75.0k
    ctxt->value->floatval -= val;
7533
75.0k
}
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
238k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7545
238k
    xmlXPathObjectPtr arg;
7546
238k
    double val;
7547
7548
238k
    arg = valuePop(ctxt);
7549
238k
    if (arg == NULL)
7550
238k
  XP_ERROR(XPATH_INVALID_OPERAND);
7551
238k
    val = xmlXPathCastToNumber(arg);
7552
238k
    xmlXPathReleaseObject(ctxt->context, arg);
7553
238k
    CAST_TO_NUMBER;
7554
238k
    CHECK_TYPE(XPATH_NUMBER);
7555
238k
    ctxt->value->floatval *= val;
7556
238k
}
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
7.82k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7569
7.82k
    xmlXPathObjectPtr arg;
7570
7.82k
    double val;
7571
7572
7.82k
    arg = valuePop(ctxt);
7573
7.82k
    if (arg == NULL)
7574
7.82k
  XP_ERROR(XPATH_INVALID_OPERAND);
7575
7.82k
    val = xmlXPathCastToNumber(arg);
7576
7.82k
    xmlXPathReleaseObject(ctxt->context, arg);
7577
7.82k
    CAST_TO_NUMBER;
7578
7.82k
    CHECK_TYPE(XPATH_NUMBER);
7579
7.82k
    ctxt->value->floatval /= val;
7580
7.82k
}
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
9.66k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7592
9.66k
    xmlXPathObjectPtr arg;
7593
9.66k
    double arg1, arg2;
7594
7595
9.66k
    arg = valuePop(ctxt);
7596
9.66k
    if (arg == NULL)
7597
9.66k
  XP_ERROR(XPATH_INVALID_OPERAND);
7598
9.66k
    arg2 = xmlXPathCastToNumber(arg);
7599
9.66k
    xmlXPathReleaseObject(ctxt->context, arg);
7600
9.66k
    CAST_TO_NUMBER;
7601
9.66k
    CHECK_TYPE(XPATH_NUMBER);
7602
9.66k
    arg1 = ctxt->value->floatval;
7603
9.66k
    if (arg2 == 0)
7604
1.55k
  ctxt->value->floatval = xmlXPathNAN;
7605
8.11k
    else {
7606
8.11k
  ctxt->value->floatval = fmod(arg1, arg2);
7607
8.11k
    }
7608
9.66k
}
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
8.32k
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7654
8.32k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7655
8.32k
    if (cur == NULL)
7656
4.17k
        return(ctxt->context->node);
7657
4.15k
    return(NULL);
7658
8.32k
}
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
158k
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7672
158k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7673
158k
    if (cur == NULL) {
7674
75.4k
  if (ctxt->context->node == NULL) return(NULL);
7675
75.4k
  switch (ctxt->context->node->type) {
7676
27.2k
            case XML_ELEMENT_NODE:
7677
62.3k
            case XML_TEXT_NODE:
7678
63.9k
            case XML_CDATA_SECTION_NODE:
7679
63.9k
            case XML_ENTITY_REF_NODE:
7680
63.9k
            case XML_ENTITY_NODE:
7681
66.6k
            case XML_PI_NODE:
7682
69.5k
            case XML_COMMENT_NODE:
7683
69.5k
            case XML_NOTATION_NODE:
7684
69.5k
            case XML_DTD_NODE:
7685
69.5k
    return(ctxt->context->node->children);
7686
5.17k
            case XML_DOCUMENT_NODE:
7687
5.17k
            case XML_DOCUMENT_TYPE_NODE:
7688
5.17k
            case XML_DOCUMENT_FRAG_NODE:
7689
5.17k
            case XML_HTML_DOCUMENT_NODE:
7690
5.17k
    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
528
            case XML_ATTRIBUTE_NODE:
7695
637
      case XML_NAMESPACE_DECL:
7696
637
      case XML_XINCLUDE_START:
7697
637
      case XML_XINCLUDE_END:
7698
637
    return(NULL);
7699
75.4k
  }
7700
0
  return(NULL);
7701
75.4k
    }
7702
83.2k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7703
83.2k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7704
0
  return(NULL);
7705
83.2k
    return(cur->next);
7706
83.2k
}
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
2.79M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7720
2.79M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7721
2.79M
    if (cur == NULL) {
7722
1.62M
  cur = ctxt->context->node;
7723
1.62M
  if (cur == NULL) return(NULL);
7724
  /*
7725
  * Get the first element child.
7726
  */
7727
1.62M
  switch (cur->type) {
7728
580k
            case XML_ELEMENT_NODE:
7729
580k
      case XML_DOCUMENT_FRAG_NODE:
7730
580k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7731
580k
            case XML_ENTITY_NODE:
7732
580k
    cur = cur->children;
7733
580k
    if (cur != NULL) {
7734
438k
        if (cur->type == XML_ELEMENT_NODE)
7735
0
      return(cur);
7736
438k
        do {
7737
438k
      cur = cur->next;
7738
438k
        } while ((cur != NULL) &&
7739
438k
      (cur->type != XML_ELEMENT_NODE));
7740
438k
        return(cur);
7741
438k
    }
7742
142k
    return(NULL);
7743
577k
            case XML_DOCUMENT_NODE:
7744
577k
            case XML_HTML_DOCUMENT_NODE:
7745
577k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7746
463k
      default:
7747
463k
    return(NULL);
7748
1.62M
  }
7749
0
  return(NULL);
7750
1.62M
    }
7751
    /*
7752
    * Get the next sibling element node.
7753
    */
7754
1.17M
    switch (cur->type) {
7755
1.17M
  case XML_ELEMENT_NODE:
7756
1.17M
  case XML_TEXT_NODE:
7757
1.17M
  case XML_ENTITY_REF_NODE:
7758
1.17M
  case XML_ENTITY_NODE:
7759
1.17M
  case XML_CDATA_SECTION_NODE:
7760
1.17M
  case XML_PI_NODE:
7761
1.17M
  case XML_COMMENT_NODE:
7762
1.17M
  case XML_XINCLUDE_END:
7763
1.17M
      break;
7764
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7765
0
  default:
7766
0
      return(NULL);
7767
1.17M
    }
7768
1.17M
    if (cur->next != NULL) {
7769
609k
  if (cur->next->type == XML_ELEMENT_NODE)
7770
1.26k
      return(cur->next);
7771
607k
  cur = cur->next;
7772
967k
  do {
7773
967k
      cur = cur->next;
7774
967k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7775
607k
  return(cur);
7776
609k
    }
7777
567k
    return(NULL);
7778
1.17M
}
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
8.22M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865
8.22M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866
8.22M
    if (cur == NULL) {
7867
534k
  if (ctxt->context->node == NULL)
7868
0
      return(NULL);
7869
534k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870
534k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871
7.06k
      return(NULL);
7872
7873
527k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874
101k
      return(ctxt->context->doc->children);
7875
426k
        return(ctxt->context->node->children);
7876
527k
    }
7877
7878
7.69M
    if (cur->type == XML_NAMESPACE_DECL)
7879
0
        return(NULL);
7880
7.69M
    if (cur->children != NULL) {
7881
  /*
7882
   * Do not descend on entities declarations
7883
   */
7884
1.81M
  if (cur->children->type != XML_ENTITY_DECL) {
7885
1.81M
      cur = cur->children;
7886
      /*
7887
       * Skip DTDs
7888
       */
7889
1.81M
      if (cur->type != XML_DTD_NODE)
7890
1.81M
    return(cur);
7891
1.81M
  }
7892
1.81M
    }
7893
7894
5.87M
    if (cur == ctxt->context->node) return(NULL);
7895
7896
5.83M
    while (cur->next != NULL) {
7897
3.94M
  cur = cur->next;
7898
3.94M
  if ((cur->type != XML_ENTITY_DECL) &&
7899
3.94M
      (cur->type != XML_DTD_NODE))
7900
3.94M
      return(cur);
7901
3.94M
    }
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.71M
  if (cur->next != NULL) {
7908
1.55M
      cur = cur->next;
7909
1.55M
      return(cur);
7910
1.55M
  }
7911
1.71M
    } while (cur != NULL);
7912
0
    return(cur);
7913
1.88M
}
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
2.88M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930
2.88M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931
2.88M
    if (cur == NULL)
7932
151k
        return(ctxt->context->node);
7933
7934
2.73M
    if (ctxt->context->node == NULL)
7935
0
        return(NULL);
7936
2.73M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7937
2.73M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7938
5.83k
        return(NULL);
7939
7940
2.73M
    return(xmlXPathNextDescendant(ctxt, cur));
7941
2.73M
}
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
384k
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955
384k
    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
384k
    if (cur == NULL) {
7962
198k
  if (ctxt->context->node == NULL) return(NULL);
7963
198k
  switch (ctxt->context->node->type) {
7964
61.8k
            case XML_ELEMENT_NODE:
7965
162k
            case XML_TEXT_NODE:
7966
167k
            case XML_CDATA_SECTION_NODE:
7967
167k
            case XML_ENTITY_REF_NODE:
7968
167k
            case XML_ENTITY_NODE:
7969
176k
            case XML_PI_NODE:
7970
185k
            case XML_COMMENT_NODE:
7971
185k
            case XML_NOTATION_NODE:
7972
185k
            case XML_DTD_NODE:
7973
185k
      case XML_ELEMENT_DECL:
7974
185k
      case XML_ATTRIBUTE_DECL:
7975
185k
      case XML_XINCLUDE_START:
7976
185k
      case XML_XINCLUDE_END:
7977
185k
      case XML_ENTITY_DECL:
7978
185k
    if (ctxt->context->node->parent == NULL)
7979
0
        return((xmlNodePtr) ctxt->context->doc);
7980
185k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981
185k
        ((ctxt->context->node->parent->name[0] == ' ') ||
7982
175k
         (xmlStrEqual(ctxt->context->node->parent->name,
7983
175k
         BAD_CAST "fake node libxslt"))))
7984
0
        return(NULL);
7985
185k
    return(ctxt->context->node->parent);
7986
952
            case XML_ATTRIBUTE_NODE: {
7987
952
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989
952
    return(att->parent);
7990
185k
      }
7991
11.6k
            case XML_DOCUMENT_NODE:
7992
11.6k
            case XML_DOCUMENT_TYPE_NODE:
7993
11.6k
            case XML_DOCUMENT_FRAG_NODE:
7994
11.6k
            case XML_HTML_DOCUMENT_NODE:
7995
11.6k
                return(NULL);
7996
269
      case XML_NAMESPACE_DECL: {
7997
269
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7998
7999
269
    if ((ns->next != NULL) &&
8000
269
        (ns->next->type != XML_NAMESPACE_DECL))
8001
269
        return((xmlNodePtr) ns->next);
8002
0
                return(NULL);
8003
269
      }
8004
198k
  }
8005
198k
    }
8006
186k
    return(NULL);
8007
384k
}
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
158k
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8025
158k
    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
158k
    if (cur == NULL) {
8032
27.1k
  if (ctxt->context->node == NULL) return(NULL);
8033
27.1k
  switch (ctxt->context->node->type) {
8034
8.42k
            case XML_ELEMENT_NODE:
8035
22.6k
            case XML_TEXT_NODE:
8036
23.3k
            case XML_CDATA_SECTION_NODE:
8037
23.3k
            case XML_ENTITY_REF_NODE:
8038
23.3k
            case XML_ENTITY_NODE:
8039
24.5k
            case XML_PI_NODE:
8040
25.8k
            case XML_COMMENT_NODE:
8041
25.8k
      case XML_DTD_NODE:
8042
25.8k
      case XML_ELEMENT_DECL:
8043
25.8k
      case XML_ATTRIBUTE_DECL:
8044
25.8k
      case XML_ENTITY_DECL:
8045
25.8k
            case XML_NOTATION_NODE:
8046
25.8k
      case XML_XINCLUDE_START:
8047
25.8k
      case XML_XINCLUDE_END:
8048
25.8k
    if (ctxt->context->node->parent == NULL)
8049
0
        return((xmlNodePtr) ctxt->context->doc);
8050
25.8k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8051
25.8k
        ((ctxt->context->node->parent->name[0] == ' ') ||
8052
24.5k
         (xmlStrEqual(ctxt->context->node->parent->name,
8053
24.5k
         BAD_CAST "fake node libxslt"))))
8054
0
        return(NULL);
8055
25.8k
    return(ctxt->context->node->parent);
8056
31
            case XML_ATTRIBUTE_NODE: {
8057
31
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8058
8059
31
    return(tmp->parent);
8060
25.8k
      }
8061
1.25k
            case XML_DOCUMENT_NODE:
8062
1.25k
            case XML_DOCUMENT_TYPE_NODE:
8063
1.25k
            case XML_DOCUMENT_FRAG_NODE:
8064
1.25k
            case XML_HTML_DOCUMENT_NODE:
8065
1.25k
                return(NULL);
8066
0
      case XML_NAMESPACE_DECL: {
8067
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8068
8069
0
    if ((ns->next != NULL) &&
8070
0
        (ns->next->type != XML_NAMESPACE_DECL))
8071
0
        return((xmlNodePtr) ns->next);
8072
    /* Bad, how did that namespace end up here ? */
8073
0
                return(NULL);
8074
0
      }
8075
27.1k
  }
8076
0
  return(NULL);
8077
27.1k
    }
8078
131k
    if (cur == ctxt->context->doc->children)
8079
367
  return((xmlNodePtr) ctxt->context->doc);
8080
131k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8081
42.9k
  return(NULL);
8082
88.2k
    switch (cur->type) {
8083
77.5k
  case XML_ELEMENT_NODE:
8084
86.5k
  case XML_TEXT_NODE:
8085
86.9k
  case XML_CDATA_SECTION_NODE:
8086
86.9k
  case XML_ENTITY_REF_NODE:
8087
86.9k
  case XML_ENTITY_NODE:
8088
87.3k
  case XML_PI_NODE:
8089
88.1k
  case XML_COMMENT_NODE:
8090
88.1k
  case XML_NOTATION_NODE:
8091
88.1k
  case XML_DTD_NODE:
8092
88.1k
        case XML_ELEMENT_DECL:
8093
88.1k
        case XML_ATTRIBUTE_DECL:
8094
88.1k
        case XML_ENTITY_DECL:
8095
88.1k
  case XML_XINCLUDE_START:
8096
88.1k
  case XML_XINCLUDE_END:
8097
88.1k
      if (cur->parent == NULL)
8098
0
    return(NULL);
8099
88.1k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8100
88.1k
    ((cur->parent->name[0] == ' ') ||
8101
47.8k
     (xmlStrEqual(cur->parent->name,
8102
47.8k
            BAD_CAST "fake node libxslt"))))
8103
0
    return(NULL);
8104
88.1k
      return(cur->parent);
8105
70
  case XML_ATTRIBUTE_NODE: {
8106
70
      xmlAttrPtr att = (xmlAttrPtr) cur;
8107
8108
70
      return(att->parent);
8109
88.1k
  }
8110
0
  case XML_NAMESPACE_DECL: {
8111
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8112
8113
0
      if ((ns->next != NULL) &&
8114
0
          (ns->next->type != XML_NAMESPACE_DECL))
8115
0
          return((xmlNodePtr) ns->next);
8116
      /* Bad, how did that namespace end up here ? */
8117
0
            return(NULL);
8118
0
  }
8119
0
  case XML_DOCUMENT_NODE:
8120
0
  case XML_DOCUMENT_TYPE_NODE:
8121
0
  case XML_DOCUMENT_FRAG_NODE:
8122
0
  case XML_HTML_DOCUMENT_NODE:
8123
0
      return(NULL);
8124
88.2k
    }
8125
0
    return(NULL);
8126
88.2k
}
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
78.7k
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8143
78.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8144
78.7k
    if (cur == NULL)
8145
17.2k
        return(ctxt->context->node);
8146
61.5k
    return(xmlXPathNextAncestor(ctxt, cur));
8147
78.7k
}
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
74.1k
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8162
74.1k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163
74.1k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8164
74.1k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8165
7
  return(NULL);
8166
74.1k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8167
0
        return(NULL);
8168
74.1k
    if (cur == NULL)
8169
15.5k
        return(ctxt->context->node->next);
8170
58.5k
    return(cur->next);
8171
74.1k
}
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
68.1k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8187
68.1k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8188
68.1k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8189
68.1k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8190
95
  return(NULL);
8191
68.0k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8192
0
        return(NULL);
8193
68.0k
    if (cur == NULL)
8194
14.4k
        return(ctxt->context->node->prev);
8195
53.5k
    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
53.5k
    return(cur->prev);
8201
53.5k
}
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
438k
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8218
438k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219
438k
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8220
438k
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8221
66.2k
        return(cur->children);
8222
8223
371k
    if (cur == NULL) {
8224
25.5k
        cur = ctxt->context->node;
8225
25.5k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8226
68
            cur = cur->parent;
8227
25.4k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8228
33
            xmlNsPtr ns = (xmlNsPtr) cur;
8229
8230
33
            if ((ns->next == NULL) ||
8231
33
                (ns->next->type == XML_NAMESPACE_DECL))
8232
0
                return (NULL);
8233
33
            cur = (xmlNodePtr) ns->next;
8234
33
        }
8235
25.5k
    }
8236
371k
    if (cur == NULL) return(NULL) ; /* ERROR */
8237
371k
    if (cur->next != NULL) return(cur->next) ;
8238
132k
    do {
8239
132k
        cur = cur->parent;
8240
132k
        if (cur == NULL) break;
8241
131k
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8242
107k
        if (cur->next != NULL) return(cur->next);
8243
107k
    } while (cur != NULL);
8244
1.20k
    return(cur);
8245
109k
}
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
449k
{
8344
449k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8345
449k
    if (cur == NULL) {
8346
26.0k
        cur = ctxt->context->node;
8347
26.0k
        if (cur == NULL)
8348
0
            return (NULL);
8349
26.0k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8350
27
            cur = cur->parent;
8351
25.9k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8352
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8353
8354
0
            if ((ns->next == NULL) ||
8355
0
                (ns->next->type == XML_NAMESPACE_DECL))
8356
0
                return (NULL);
8357
0
            cur = (xmlNodePtr) ns->next;
8358
0
        }
8359
26.0k
        ctxt->ancestor = cur->parent;
8360
26.0k
    }
8361
449k
    if (cur->type == XML_NAMESPACE_DECL)
8362
0
        return(NULL);
8363
449k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8364
0
  cur = cur->prev;
8365
517k
    while (cur->prev == NULL) {
8366
188k
        cur = cur->parent;
8367
188k
        if (cur == NULL)
8368
25.8k
            return (NULL);
8369
162k
        if (cur == ctxt->context->doc->children)
8370
0
            return (NULL);
8371
162k
        if (cur != ctxt->ancestor)
8372
95.3k
            return (cur);
8373
67.2k
        ctxt->ancestor = cur->parent;
8374
67.2k
    }
8375
328k
    cur = cur->prev;
8376
424k
    while (cur->last != NULL)
8377
95.4k
        cur = cur->last;
8378
328k
    return (cur);
8379
449k
}
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
92.5k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8397
92.5k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8398
92.5k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8399
60.4k
    if (cur == NULL) {
8400
16.3k
        if (ctxt->context->tmpNsList != NULL)
8401
176
      xmlFree(ctxt->context->tmpNsList);
8402
16.3k
  ctxt->context->tmpNsList =
8403
16.3k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8404
16.3k
  ctxt->context->tmpNsNr = 0;
8405
16.3k
  if (ctxt->context->tmpNsList != NULL) {
8406
44.4k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8407
28.1k
    ctxt->context->tmpNsNr++;
8408
28.1k
      }
8409
16.3k
  }
8410
16.3k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8411
16.3k
    }
8412
44.1k
    if (ctxt->context->tmpNsNr > 0) {
8413
27.9k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8414
27.9k
    } else {
8415
16.1k
  if (ctxt->context->tmpNsList != NULL)
8416
16.1k
      xmlFree(ctxt->context->tmpNsList);
8417
16.1k
  ctxt->context->tmpNsList = NULL;
8418
16.1k
  return(NULL);
8419
16.1k
    }
8420
44.1k
}
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
578k
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8434
578k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8435
578k
    if (ctxt->context->node == NULL)
8436
0
  return(NULL);
8437
578k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8438
280k
  return(NULL);
8439
297k
    if (cur == NULL) {
8440
189k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8441
0
      return(NULL);
8442
189k
        return((xmlNodePtr)ctxt->context->node->properties);
8443
189k
    }
8444
108k
    return((xmlNodePtr)cur->next);
8445
297k
}
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
297k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8470
297k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8471
0
  return;
8472
297k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8473
297k
  (xmlNodePtr) ctxt->context->doc));
8474
297k
}
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
6.81k
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8495
19.8k
    CHECK_ARITY(0);
8496
19.8k
    if (ctxt->context->contextSize >= 0) {
8497
6.50k
  valuePush(ctxt,
8498
6.50k
      xmlXPathCacheNewFloat(ctxt->context,
8499
6.50k
    (double) ctxt->context->contextSize));
8500
#ifdef DEBUG_EXPR
8501
  xmlGenericError(xmlGenericErrorContext,
8502
    "last() : %d\n", ctxt->context->contextSize);
8503
#endif
8504
6.50k
    } else {
8505
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8506
0
    }
8507
19.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
460
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522
956
    CHECK_ARITY(0);
8523
956
    if (ctxt->context->proximityPosition >= 0) {
8524
248
  valuePush(ctxt,
8525
248
        xmlXPathCacheNewFloat(ctxt->context,
8526
248
    (double) ctxt->context->proximityPosition));
8527
#ifdef DEBUG_EXPR
8528
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8529
    ctxt->context->proximityPosition);
8530
#endif
8531
248
    } else {
8532
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8533
0
    }
8534
956
}
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
932
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546
932
    xmlXPathObjectPtr cur;
8547
8548
2.20k
    CHECK_ARITY(1);
8549
2.20k
    if ((ctxt->value == NULL) ||
8550
636
  ((ctxt->value->type != XPATH_NODESET) &&
8551
636
   (ctxt->value->type != XPATH_XSLT_TREE)))
8552
420
  XP_ERROR(XPATH_INVALID_TYPE);
8553
420
    cur = valuePop(ctxt);
8554
8555
420
    if ((cur == NULL) || (cur->nodesetval == NULL))
8556
47
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8557
373
    else
8558
373
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8559
373
      (double) cur->nodesetval->nodeNr));
8560
420
    xmlXPathReleaseObject(ctxt->context, cur);
8561
420
}
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
6.09k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8574
6.09k
    xmlNodeSetPtr ret;
8575
6.09k
    const xmlChar *cur = ids;
8576
6.09k
    xmlChar *ID;
8577
6.09k
    xmlAttrPtr attr;
8578
6.09k
    xmlNodePtr elem = NULL;
8579
8580
6.09k
    if (ids == NULL) return(NULL);
8581
8582
6.09k
    ret = xmlXPathNodeSetCreate(NULL);
8583
6.09k
    if (ret == NULL)
8584
0
        return(ret);
8585
8586
36.8k
    while (IS_BLANK_CH(*cur)) cur++;
8587
20.9k
    while (*cur != 0) {
8588
89.5k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8589
74.7k
      cur++;
8590
8591
14.8k
        ID = xmlStrndup(ids, cur - ids);
8592
14.8k
  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
14.8k
      attr = xmlGetID(doc, ID);
8601
14.8k
      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
14.8k
      xmlFree(ID);
8613
14.8k
  }
8614
8615
185k
  while (IS_BLANK_CH(*cur)) cur++;
8616
14.8k
  ids = cur;
8617
14.8k
    }
8618
6.09k
    return(ret);
8619
6.09k
}
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
4.67k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8641
4.67k
    xmlChar *tokens;
8642
4.67k
    xmlNodeSetPtr ret;
8643
4.67k
    xmlXPathObjectPtr obj;
8644
8645
12.9k
    CHECK_ARITY(1);
8646
12.9k
    obj = valuePop(ctxt);
8647
12.9k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8648
4.13k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8649
2.71k
  xmlNodeSetPtr ns;
8650
2.71k
  int i;
8651
8652
        /* TODO: Check memory error. */
8653
2.71k
  ret = xmlXPathNodeSetCreate(NULL);
8654
8655
2.71k
  if (obj->nodesetval != NULL) {
8656
7.21k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8657
4.67k
    tokens =
8658
4.67k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8659
4.67k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8660
                /* TODO: Check memory error. */
8661
4.67k
    ret = xmlXPathNodeSetMerge(ret, ns);
8662
4.67k
    xmlXPathFreeNodeSet(ns);
8663
4.67k
    if (tokens != NULL)
8664
4.67k
        xmlFree(tokens);
8665
4.67k
      }
8666
2.53k
  }
8667
2.71k
  xmlXPathReleaseObject(ctxt->context, obj);
8668
2.71k
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8669
2.71k
  return;
8670
2.71k
    }
8671
1.42k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8672
1.42k
    if (obj == NULL) return;
8673
1.42k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8674
1.42k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8675
1.42k
    xmlXPathReleaseObject(ctxt->context, obj);
8676
1.42k
    return;
8677
1.42k
}
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
1.79k
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8694
1.79k
    xmlXPathObjectPtr cur;
8695
8696
1.79k
    if (ctxt == NULL) return;
8697
8698
1.79k
    if (nargs == 0) {
8699
14
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8700
14
      ctxt->context->node));
8701
14
  nargs = 1;
8702
14
    }
8703
8704
5.39k
    CHECK_ARITY(1);
8705
5.39k
    if ((ctxt->value == NULL) ||
8706
1.79k
  ((ctxt->value->type != XPATH_NODESET) &&
8707
1.79k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8708
1.79k
  XP_ERROR(XPATH_INVALID_TYPE);
8709
1.79k
    cur = valuePop(ctxt);
8710
8711
1.79k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8712
1
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
1.79k
    } else {
8714
1.79k
  int i = 0; /* Should be first in document order !!!!! */
8715
1.79k
  switch (cur->nodesetval->nodeTab[i]->type) {
8716
0
  case XML_ELEMENT_NODE:
8717
0
  case XML_ATTRIBUTE_NODE:
8718
27
  case XML_PI_NODE:
8719
27
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8720
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8721
27
      else
8722
27
    valuePush(ctxt,
8723
27
          xmlXPathCacheNewString(ctxt->context,
8724
27
      cur->nodesetval->nodeTab[i]->name));
8725
27
      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
1.76k
  default:
8731
1.76k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8732
1.79k
  }
8733
1.79k
    }
8734
1.79k
    xmlXPathReleaseObject(ctxt->context, cur);
8735
1.79k
}
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
1.15k
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8753
1.15k
    xmlXPathObjectPtr cur;
8754
8755
1.15k
    if (ctxt == NULL) return;
8756
8757
1.15k
    if (nargs == 0) {
8758
262
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8759
262
      ctxt->context->node));
8760
262
  nargs = 1;
8761
262
    }
8762
3.38k
    CHECK_ARITY(1);
8763
3.38k
    if ((ctxt->value == NULL) ||
8764
1.11k
  ((ctxt->value->type != XPATH_NODESET) &&
8765
1.11k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8766
929
  XP_ERROR(XPATH_INVALID_TYPE);
8767
929
    cur = valuePop(ctxt);
8768
8769
929
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8770
258
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8771
671
    } else {
8772
671
  int i = 0; /* Should be first in document order !!!!! */
8773
671
  switch (cur->nodesetval->nodeTab[i]->type) {
8774
149
  case XML_ELEMENT_NODE:
8775
149
  case XML_ATTRIBUTE_NODE:
8776
149
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8777
146
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8778
3
      else
8779
3
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8780
3
        cur->nodesetval->nodeTab[i]->ns->href));
8781
149
      break;
8782
522
  default:
8783
522
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784
671
  }
8785
671
    }
8786
929
    xmlXPathReleaseObject(ctxt->context, cur);
8787
929
}
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
3.61k
{
8814
3.61k
    xmlXPathObjectPtr cur;
8815
8816
3.61k
    if (nargs == 0) {
8817
1.78k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8818
1.78k
      ctxt->context->node));
8819
1.78k
        nargs = 1;
8820
1.78k
    }
8821
8822
10.4k
    CHECK_ARITY(1);
8823
10.4k
    if ((ctxt->value == NULL) ||
8824
3.43k
        ((ctxt->value->type != XPATH_NODESET) &&
8825
3.43k
         (ctxt->value->type != XPATH_XSLT_TREE)))
8826
2.98k
        XP_ERROR(XPATH_INVALID_TYPE);
8827
2.98k
    cur = valuePop(ctxt);
8828
8829
2.98k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8830
616
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8831
2.36k
    } else {
8832
2.36k
        int i = 0;              /* Should be first in document order !!!!! */
8833
8834
2.36k
        switch (cur->nodesetval->nodeTab[i]->type) {
8835
770
            case XML_ELEMENT_NODE:
8836
771
            case XML_ATTRIBUTE_NODE:
8837
771
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8838
0
        valuePush(ctxt,
8839
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8840
771
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8841
771
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8842
424
        valuePush(ctxt,
8843
424
            xmlXPathCacheNewString(ctxt->context,
8844
424
          cur->nodesetval->nodeTab[i]->name));
8845
424
    } else {
8846
347
        xmlChar *fullname;
8847
8848
347
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8849
347
             cur->nodesetval->nodeTab[i]->ns->prefix,
8850
347
             NULL, 0);
8851
347
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8852
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8853
347
        if (fullname == NULL) {
8854
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8855
0
        }
8856
347
        valuePush(ctxt, xmlXPathCacheWrapString(
8857
347
      ctxt->context, fullname));
8858
347
                }
8859
771
                break;
8860
1.59k
            default:
8861
1.59k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8862
1.59k
        cur->nodesetval->nodeTab[i]));
8863
1.59k
                xmlXPathLocalNameFunction(ctxt, 1);
8864
2.36k
        }
8865
2.36k
    }
8866
2.98k
    xmlXPathReleaseObject(ctxt->context, cur);
8867
2.98k
}
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
78.5k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908
78.5k
    xmlXPathObjectPtr cur;
8909
8910
78.5k
    if (ctxt == NULL) return;
8911
78.5k
    if (nargs == 0) {
8912
381
    valuePush(ctxt,
8913
381
  xmlXPathCacheWrapString(ctxt->context,
8914
381
      xmlXPathCastNodeToString(ctxt->context->node)));
8915
381
  return;
8916
381
    }
8917
8918
312k
    CHECK_ARITY(1);
8919
312k
    cur = valuePop(ctxt);
8920
312k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8921
77.8k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8922
77.8k
}
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
658
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8938
658
    xmlXPathObjectPtr cur;
8939
8940
658
    if (nargs == 0) {
8941
222
        if ((ctxt == NULL) || (ctxt->context == NULL))
8942
0
      return;
8943
222
  if (ctxt->context->node == NULL) {
8944
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8945
222
  } else {
8946
222
      xmlChar *content;
8947
8948
222
      content = xmlXPathCastNodeToString(ctxt->context->node);
8949
222
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8950
222
    xmlUTF8Strlen(content)));
8951
222
      xmlFree(content);
8952
222
  }
8953
222
  return;
8954
222
    }
8955
1.70k
    CHECK_ARITY(1);
8956
1.70k
    CAST_TO_STRING;
8957
1.70k
    CHECK_TYPE(XPATH_STRING);
8958
416
    cur = valuePop(ctxt);
8959
416
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960
416
  xmlUTF8Strlen(cur->stringval)));
8961
416
    xmlXPathReleaseObject(ctxt->context, cur);
8962
416
}
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
2.19k
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975
2.19k
    xmlXPathObjectPtr cur, newobj;
8976
2.19k
    xmlChar *tmp;
8977
8978
2.19k
    if (ctxt == NULL) return;
8979
2.19k
    if (nargs < 2) {
8980
471
  CHECK_ARITY(2);
8981
471
    }
8982
8983
1.72k
    CAST_TO_STRING;
8984
1.72k
    cur = valuePop(ctxt);
8985
1.72k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8986
0
  xmlXPathReleaseObject(ctxt->context, cur);
8987
0
  return;
8988
0
    }
8989
1.72k
    nargs--;
8990
8991
4.90k
    while (nargs > 0) {
8992
3.17k
  CAST_TO_STRING;
8993
3.17k
  newobj = valuePop(ctxt);
8994
3.17k
  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
3.17k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
9000
3.17k
  newobj->stringval = cur->stringval;
9001
3.17k
  cur->stringval = tmp;
9002
3.17k
  xmlXPathReleaseObject(ctxt->context, newobj);
9003
3.17k
  nargs--;
9004
3.17k
    }
9005
1.72k
    valuePush(ctxt, cur);
9006
1.72k
}
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
1.44k
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
1.44k
    xmlXPathObjectPtr hay, needle;
9021
9022
3.63k
    CHECK_ARITY(2);
9023
3.63k
    CAST_TO_STRING;
9024
3.63k
    CHECK_TYPE(XPATH_STRING);
9025
1.09k
    needle = valuePop(ctxt);
9026
1.09k
    CAST_TO_STRING;
9027
1.09k
    hay = valuePop(ctxt);
9028
9029
1.09k
    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
1.09k
    if (xmlStrstr(hay->stringval, needle->stringval))
9035
584
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9036
509
    else
9037
509
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
1.09k
    xmlXPathReleaseObject(ctxt->context, hay);
9039
1.09k
    xmlXPathReleaseObject(ctxt->context, needle);
9040
1.09k
}
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
1.00k
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9054
1.00k
    xmlXPathObjectPtr hay, needle;
9055
1.00k
    int n;
9056
9057
2.40k
    CHECK_ARITY(2);
9058
2.40k
    CAST_TO_STRING;
9059
2.40k
    CHECK_TYPE(XPATH_STRING);
9060
696
    needle = valuePop(ctxt);
9061
696
    CAST_TO_STRING;
9062
696
    hay = valuePop(ctxt);
9063
9064
696
    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
696
    n = xmlStrlen(needle->stringval);
9070
696
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9071
432
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9072
264
    else
9073
264
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9074
696
    xmlXPathReleaseObject(ctxt->context, hay);
9075
696
    xmlXPathReleaseObject(ctxt->context, needle);
9076
696
}
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
3.57k
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9108
3.57k
    xmlXPathObjectPtr str, start, len;
9109
3.57k
    double le=0, in;
9110
3.57k
    int i = 1, j = INT_MAX;
9111
9112
3.57k
    if (nargs < 2) {
9113
386
  CHECK_ARITY(2);
9114
386
    }
9115
3.18k
    if (nargs > 3) {
9116
242
  CHECK_ARITY(3);
9117
242
    }
9118
    /*
9119
     * take care of possible last (position) argument
9120
    */
9121
2.94k
    if (nargs == 3) {
9122
1.19k
  CAST_TO_NUMBER;
9123
1.19k
  CHECK_TYPE(XPATH_NUMBER);
9124
1.19k
  len = valuePop(ctxt);
9125
1.19k
  le = len->floatval;
9126
1.19k
  xmlXPathReleaseObject(ctxt->context, len);
9127
1.19k
    }
9128
9129
2.94k
    CAST_TO_NUMBER;
9130
2.94k
    CHECK_TYPE(XPATH_NUMBER);
9131
2.94k
    start = valuePop(ctxt);
9132
2.94k
    in = start->floatval;
9133
2.94k
    xmlXPathReleaseObject(ctxt->context, start);
9134
2.94k
    CAST_TO_STRING;
9135
2.94k
    CHECK_TYPE(XPATH_STRING);
9136
2.94k
    str = valuePop(ctxt);
9137
9138
2.94k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9139
747
        i = INT_MAX;
9140
2.19k
    } else if (in >= 1.0) {
9141
1.93k
        i = (int)in;
9142
1.93k
        if (in - floor(in) >= 0.5)
9143
18
            i += 1;
9144
1.93k
    }
9145
9146
2.94k
    if (nargs == 3) {
9147
1.19k
        double rin, rle, end;
9148
9149
1.19k
        rin = floor(in);
9150
1.19k
        if (in - rin >= 0.5)
9151
9
            rin += 1.0;
9152
9153
1.19k
        rle = floor(le);
9154
1.19k
        if (le - rle >= 0.5)
9155
0
            rle += 1.0;
9156
9157
1.19k
        end = rin + rle;
9158
1.19k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9159
511
            j = 1;
9160
684
        } else if (end < INT_MAX) {
9161
592
            j = (int)end;
9162
592
        }
9163
1.19k
    }
9164
9165
2.94k
    if (i < j) {
9166
1.93k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9167
1.93k
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9168
1.93k
  xmlFree(ret);
9169
1.93k
    } else {
9170
1.00k
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9171
1.00k
    }
9172
9173
2.94k
    xmlXPathReleaseObject(ctxt->context, str);
9174
2.94k
}
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
1.28k
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9191
1.28k
  xmlXPathObjectPtr str;
9192
1.28k
  xmlXPathObjectPtr find;
9193
1.28k
  xmlBufPtr target;
9194
1.28k
  const xmlChar *point;
9195
1.28k
  int offset;
9196
9197
3.28k
  CHECK_ARITY(2);
9198
3.28k
  CAST_TO_STRING;
9199
3.28k
  find = valuePop(ctxt);
9200
3.28k
  CAST_TO_STRING;
9201
3.28k
  str = valuePop(ctxt);
9202
9203
3.28k
  target = xmlBufCreate();
9204
3.28k
  if (target) {
9205
1.00k
    point = xmlStrstr(str->stringval, find->stringval);
9206
1.00k
    if (point) {
9207
479
      offset = point - str->stringval;
9208
479
      xmlBufAdd(target, str->stringval, offset);
9209
479
    }
9210
1.00k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211
1.00k
  xmlBufContent(target)));
9212
1.00k
    xmlBufFree(target);
9213
1.00k
  }
9214
3.28k
  xmlXPathReleaseObject(ctxt->context, str);
9215
3.28k
  xmlXPathReleaseObject(ctxt->context, find);
9216
3.28k
}
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
1.34k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234
1.34k
  xmlXPathObjectPtr str;
9235
1.34k
  xmlXPathObjectPtr find;
9236
1.34k
  xmlBufPtr target;
9237
1.34k
  const xmlChar *point;
9238
1.34k
  int offset;
9239
9240
3.44k
  CHECK_ARITY(2);
9241
3.44k
  CAST_TO_STRING;
9242
3.44k
  find = valuePop(ctxt);
9243
3.44k
  CAST_TO_STRING;
9244
3.44k
  str = valuePop(ctxt);
9245
9246
3.44k
  target = xmlBufCreate();
9247
3.44k
  if (target) {
9248
1.04k
    point = xmlStrstr(str->stringval, find->stringval);
9249
1.04k
    if (point) {
9250
492
      offset = point - str->stringval + xmlStrlen(find->stringval);
9251
492
      xmlBufAdd(target, &str->stringval[offset],
9252
492
       xmlStrlen(str->stringval) - offset);
9253
492
    }
9254
1.04k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9255
1.04k
  xmlBufContent(target)));
9256
1.04k
    xmlBufFree(target);
9257
1.04k
  }
9258
3.44k
  xmlXPathReleaseObject(ctxt->context, str);
9259
3.44k
  xmlXPathReleaseObject(ctxt->context, find);
9260
3.44k
}
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
575
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9278
575
    xmlChar *source, *target;
9279
575
    int blank;
9280
9281
575
    if (ctxt == NULL) return;
9282
575
    if (nargs == 0) {
9283
        /* Use current context node */
9284
237
        valuePush(ctxt,
9285
237
            xmlXPathCacheWrapString(ctxt->context,
9286
237
                xmlXPathCastNodeToString(ctxt->context->node)));
9287
237
        nargs = 1;
9288
237
    }
9289
9290
1.70k
    CHECK_ARITY(1);
9291
1.70k
    CAST_TO_STRING;
9292
1.70k
    CHECK_TYPE(XPATH_STRING);
9293
567
    source = ctxt->value->stringval;
9294
567
    if (source == NULL)
9295
0
        return;
9296
567
    target = source;
9297
9298
    /* Skip leading whitespaces */
9299
567
    while (IS_BLANK_CH(*source))
9300
6.84k
        source++;
9301
9302
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9303
567
    blank = 0;
9304
63.0k
    while (*source) {
9305
62.5k
        if (IS_BLANK_CH(*source)) {
9306
48.2k
      blank = 1;
9307
48.2k
        } else {
9308
14.2k
            if (blank) {
9309
2.44k
                *target++ = 0x20;
9310
2.44k
                blank = 0;
9311
2.44k
            }
9312
14.2k
            *target++ = *source;
9313
14.2k
        }
9314
62.5k
        source++;
9315
62.5k
    }
9316
567
    *target = 0;
9317
567
}
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
2.96k
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342
2.96k
    xmlXPathObjectPtr str;
9343
2.96k
    xmlXPathObjectPtr from;
9344
2.96k
    xmlXPathObjectPtr to;
9345
2.96k
    xmlBufPtr target;
9346
2.96k
    int offset, max;
9347
2.96k
    xmlChar ch;
9348
2.96k
    const xmlChar *point;
9349
2.96k
    xmlChar *cptr;
9350
9351
8.15k
    CHECK_ARITY(3);
9352
9353
8.15k
    CAST_TO_STRING;
9354
8.15k
    to = valuePop(ctxt);
9355
8.15k
    CAST_TO_STRING;
9356
8.15k
    from = valuePop(ctxt);
9357
8.15k
    CAST_TO_STRING;
9358
8.15k
    str = valuePop(ctxt);
9359
9360
8.15k
    target = xmlBufCreate();
9361
8.15k
    if (target) {
9362
2.59k
  max = xmlUTF8Strlen(to->stringval);
9363
300k
  for (cptr = str->stringval; (ch=*cptr); ) {
9364
297k
      offset = xmlUTF8Strloc(from->stringval, cptr);
9365
297k
      if (offset >= 0) {
9366
53.5k
    if (offset < max) {
9367
28.4k
        point = xmlUTF8Strpos(to->stringval, offset);
9368
28.4k
        if (point)
9369
27.5k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9370
28.4k
    }
9371
53.5k
      } else
9372
244k
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9373
9374
      /* Step to next character in input */
9375
297k
      cptr++;
9376
297k
      if ( ch & 0x80 ) {
9377
    /* if not simple ascii, verify proper format */
9378
6.51k
    if ( (ch & 0xc0) != 0xc0 ) {
9379
4
        xmlGenericError(xmlGenericErrorContext,
9380
4
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                    /* not asserting an XPath error is probably better */
9382
4
        break;
9383
4
    }
9384
    /* then skip over remaining bytes for this char */
9385
17.3k
    while ( (ch <<= 1) & 0x80 )
9386
10.8k
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9387
4
      xmlGenericError(xmlGenericErrorContext,
9388
4
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9389
                        /* not asserting an XPath error is probably better */
9390
4
      break;
9391
4
        }
9392
6.51k
    if (ch & 0x80) /* must have had error encountered */
9393
4
        break;
9394
6.51k
      }
9395
297k
  }
9396
2.59k
    }
9397
8.15k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9398
8.15k
  xmlBufContent(target)));
9399
8.15k
    xmlBufFree(target);
9400
8.15k
    xmlXPathReleaseObject(ctxt->context, str);
9401
8.15k
    xmlXPathReleaseObject(ctxt->context, from);
9402
8.15k
    xmlXPathReleaseObject(ctxt->context, to);
9403
8.15k
}
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
97.4k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420
97.4k
    xmlXPathObjectPtr cur;
9421
9422
292k
    CHECK_ARITY(1);
9423
292k
    cur = valuePop(ctxt);
9424
292k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9425
97.4k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9426
97.4k
    valuePush(ctxt, cur);
9427
97.4k
}
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
975
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9441
2.16k
    CHECK_ARITY(1);
9442
2.16k
    CAST_TO_BOOLEAN;
9443
2.16k
    CHECK_TYPE(XPATH_BOOLEAN);
9444
597
    ctxt->value->boolval = ! ctxt->value->boolval;
9445
597
}
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
6.90k
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457
20.2k
    CHECK_ARITY(0);
9458
20.2k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9459
20.2k
}
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
4.51k
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9471
13.1k
    CHECK_ARITY(0);
9472
13.1k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9473
13.1k
}
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
961
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498
961
    xmlXPathObjectPtr val = NULL;
9499
961
    const xmlChar *theLang = NULL;
9500
961
    const xmlChar *lang;
9501
961
    int ret = 0;
9502
961
    int i;
9503
9504
2.24k
    CHECK_ARITY(1);
9505
2.24k
    CAST_TO_STRING;
9506
2.24k
    CHECK_TYPE(XPATH_STRING);
9507
643
    val = valuePop(ctxt);
9508
643
    lang = val->stringval;
9509
643
    theLang = xmlNodeGetLang(ctxt->context->node);
9510
643
    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
643
not_equal:
9518
643
    if (theLang != NULL)
9519
0
  xmlFree((void *)theLang);
9520
9521
643
    xmlXPathReleaseObject(ctxt->context, val);
9522
643
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9523
643
}
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
433k
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
433k
    xmlXPathObjectPtr cur;
9536
433k
    double res;
9537
9538
433k
    if (ctxt == NULL) return;
9539
433k
    if (nargs == 0) {
9540
625
  if (ctxt->context->node == NULL) {
9541
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9542
625
  } else {
9543
625
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9544
9545
625
      res = xmlXPathStringEvalNumber(content);
9546
625
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9547
625
      xmlFree(content);
9548
625
  }
9549
625
  return;
9550
625
    }
9551
9552
1.73M
    CHECK_ARITY(1);
9553
1.73M
    cur = valuePop(ctxt);
9554
1.73M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9555
1.73M
}
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
2.24k
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9569
2.24k
    xmlXPathObjectPtr cur;
9570
2.24k
    int i;
9571
2.24k
    double res = 0.0;
9572
9573
5.84k
    CHECK_ARITY(1);
9574
5.84k
    if ((ctxt->value == NULL) ||
9575
1.80k
  ((ctxt->value->type != XPATH_NODESET) &&
9576
1.80k
   (ctxt->value->type != XPATH_XSLT_TREE)))
9577
1.52k
  XP_ERROR(XPATH_INVALID_TYPE);
9578
1.52k
    cur = valuePop(ctxt);
9579
9580
1.52k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9581
6.77k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9582
5.66k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9583
5.66k
  }
9584
1.10k
    }
9585
1.52k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9586
1.52k
    xmlXPathReleaseObject(ctxt->context, cur);
9587
1.52k
}
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
796
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601
1.78k
    CHECK_ARITY(1);
9602
1.78k
    CAST_TO_NUMBER;
9603
1.78k
    CHECK_TYPE(XPATH_NUMBER);
9604
9605
493
    ctxt->value->floatval = floor(ctxt->value->floatval);
9606
493
}
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
719
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9620
1.62k
    CHECK_ARITY(1);
9621
1.62k
    CAST_TO_NUMBER;
9622
1.62k
    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
452
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9629
452
#endif
9630
452
}
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
833
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9645
833
    double f;
9646
9647
1.97k
    CHECK_ARITY(1);
9648
1.97k
    CAST_TO_NUMBER;
9649
1.97k
    CHECK_TYPE(XPATH_NUMBER);
9650
9651
570
    f = ctxt->value->floatval;
9652
9653
570
    if ((f >= -0.5) && (f < 0.5)) {
9654
        /* Handles negative zero. */
9655
121
        ctxt->value->floatval *= 0.0;
9656
121
    }
9657
449
    else {
9658
449
        double rounded = floor(f);
9659
449
        if (f - rounded >= 0.5)
9660
9
            rounded += 1.0;
9661
449
        ctxt->value->floatval = rounded;
9662
449
    }
9663
570
}
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
24.5M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9696
24.5M
    unsigned char c;
9697
24.5M
    unsigned int val;
9698
24.5M
    const xmlChar *cur;
9699
9700
24.5M
    if (ctxt == NULL)
9701
0
  return(0);
9702
24.5M
    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
24.5M
    c = *cur;
9716
24.5M
    if (c & 0x80) {
9717
860k
  if ((cur[1] & 0xc0) != 0x80)
9718
150k
      goto encoding_error;
9719
710k
  if ((c & 0xe0) == 0xe0) {
9720
9721
33.6k
      if ((cur[2] & 0xc0) != 0x80)
9722
3.53k
    goto encoding_error;
9723
30.1k
      if ((c & 0xf0) == 0xf0) {
9724
8.77k
    if (((c & 0xf8) != 0xf0) ||
9725
8.77k
        ((cur[3] & 0xc0) != 0x80))
9726
3.79k
        goto encoding_error;
9727
    /* 4-byte code */
9728
4.97k
    *len = 4;
9729
4.97k
    val = (cur[0] & 0x7) << 18;
9730
4.97k
    val |= (cur[1] & 0x3f) << 12;
9731
4.97k
    val |= (cur[2] & 0x3f) << 6;
9732
4.97k
    val |= cur[3] & 0x3f;
9733
21.3k
      } else {
9734
        /* 3-byte code */
9735
21.3k
    *len = 3;
9736
21.3k
    val = (cur[0] & 0xf) << 12;
9737
21.3k
    val |= (cur[1] & 0x3f) << 6;
9738
21.3k
    val |= cur[2] & 0x3f;
9739
21.3k
      }
9740
676k
  } else {
9741
    /* 2-byte code */
9742
676k
      *len = 2;
9743
676k
      val = (cur[0] & 0x1f) << 6;
9744
676k
      val |= cur[1] & 0x3f;
9745
676k
  }
9746
703k
  if (!IS_CHAR(val)) {
9747
4.79k
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9748
0
  }
9749
698k
  return(val);
9750
23.6M
    } else {
9751
  /* 1-byte code */
9752
23.6M
  *len = 1;
9753
23.6M
  return(*cur);
9754
23.6M
    }
9755
157k
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
157k
    *len = 0;
9764
157k
    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
3.22M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9783
3.22M
    const xmlChar *in;
9784
3.22M
    xmlChar *ret;
9785
3.22M
    int count = 0;
9786
9787
3.22M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9788
    /*
9789
     * Accelerator for simple ASCII names
9790
     */
9791
3.22M
    in = ctxt->cur;
9792
3.22M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9793
3.22M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9794
3.22M
  (*in == '_')) {
9795
2.74M
  in++;
9796
12.3M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9797
12.3M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9798
12.3M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9799
12.3M
         (*in == '_') || (*in == '.') ||
9800
12.3M
         (*in == '-'))
9801
9.55M
      in++;
9802
2.74M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9803
2.74M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9804
2.74M
            (*in == '@') || (*in == '*')) {
9805
1.31M
      count = in - ctxt->cur;
9806
1.31M
      if (count == 0)
9807
0
    return(NULL);
9808
1.31M
      ret = xmlStrndup(ctxt->cur, count);
9809
1.31M
      ctxt->cur = in;
9810
1.31M
      return(ret);
9811
1.31M
  }
9812
2.74M
    }
9813
1.90M
    return(xmlXPathParseNameComplex(ctxt, 0));
9814
3.22M
}
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
676k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9836
676k
    xmlChar *ret = NULL;
9837
9838
676k
    *prefix = NULL;
9839
676k
    ret = xmlXPathParseNCName(ctxt);
9840
676k
    if (ret && CUR == ':') {
9841
318k
        *prefix = ret;
9842
318k
  NEXT;
9843
318k
  ret = xmlXPathParseNCName(ctxt);
9844
318k
    }
9845
676k
    return(ret);
9846
676k
}
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
34
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9864
34
    const xmlChar *in;
9865
34
    xmlChar *ret;
9866
34
    size_t count = 0;
9867
9868
34
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9869
    /*
9870
     * Accelerator for simple ASCII names
9871
     */
9872
34
    in = ctxt->cur;
9873
34
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874
34
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9875
34
  (*in == '_') || (*in == ':')) {
9876
14
  in++;
9877
164
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878
164
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9879
164
         ((*in >= 0x30) && (*in <= 0x39)) ||
9880
164
         (*in == '_') || (*in == '-') ||
9881
164
         (*in == ':') || (*in == '.'))
9882
150
      in++;
9883
14
  if ((*in > 0) && (*in < 0x80)) {
9884
10
      count = in - ctxt->cur;
9885
10
            if (count > XML_MAX_NAME_LENGTH) {
9886
0
                ctxt->cur = in;
9887
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9888
0
            }
9889
10
      ret = xmlStrndup(ctxt->cur, count);
9890
10
      ctxt->cur = in;
9891
10
      return(ret);
9892
10
  }
9893
14
    }
9894
24
    return(xmlXPathParseNameComplex(ctxt, 1));
9895
34
}
9896
9897
static xmlChar *
9898
1.90M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9899
1.90M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9900
1.90M
    int len = 0, l;
9901
1.90M
    int c;
9902
9903
    /*
9904
     * Handler for more complex cases
9905
     */
9906
1.90M
    c = CUR_CHAR(l);
9907
1.90M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9908
1.90M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9909
1.90M
        (c == '*') || /* accelerators */
9910
1.90M
  (!IS_LETTER(c) && (c != '_') &&
9911
1.66M
         ((!qualified) || (c != ':')))) {
9912
409k
  return(NULL);
9913
409k
    }
9914
9915
9.76M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9916
9.76M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9917
9.73M
            (c == '.') || (c == '-') ||
9918
9.73M
      (c == '_') || ((qualified) && (c == ':')) ||
9919
9.73M
      (IS_COMBINING(c)) ||
9920
9.73M
      (IS_EXTENDER(c)))) {
9921
8.26M
  COPY_BUF(l,buf,len,c);
9922
8.26M
  NEXTL(l);
9923
8.26M
  c = CUR_CHAR(l);
9924
8.26M
  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.67k
      xmlChar *buffer;
9930
1.67k
      int max = len * 2;
9931
9932
1.67k
            if (len > XML_MAX_NAME_LENGTH) {
9933
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9934
0
            }
9935
1.67k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9936
1.67k
      if (buffer == NULL) {
9937
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9938
0
      }
9939
1.67k
      memcpy(buffer, buf, len);
9940
43.8k
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9941
43.8k
       (c == '.') || (c == '-') ||
9942
43.8k
       (c == '_') || ((qualified) && (c == ':')) ||
9943
43.8k
       (IS_COMBINING(c)) ||
9944
43.8k
       (IS_EXTENDER(c))) {
9945
42.1k
    if (len + 10 > max) {
9946
84
                    xmlChar *tmp;
9947
84
                    if (max > XML_MAX_NAME_LENGTH) {
9948
0
                        xmlFree(buffer);
9949
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9950
0
                    }
9951
84
        max *= 2;
9952
84
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9953
84
        if (tmp == NULL) {
9954
0
                        xmlFree(buffer);
9955
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9956
0
        }
9957
84
                    buffer = tmp;
9958
84
    }
9959
42.1k
    COPY_BUF(l,buffer,len,c);
9960
42.1k
    NEXTL(l);
9961
42.1k
    c = CUR_CHAR(l);
9962
42.1k
      }
9963
1.67k
      buffer[len] = 0;
9964
1.67k
      return(buffer);
9965
1.67k
  }
9966
8.26M
    }
9967
1.49M
    if (len == 0)
9968
0
  return(NULL);
9969
1.49M
    return(xmlStrndup(buf, len));
9970
1.49M
}
9971
9972
170k
#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
722k
xmlXPathStringEvalNumber(const xmlChar *str) {
9992
722k
    const xmlChar *cur = str;
9993
722k
    double ret;
9994
722k
    int ok = 0;
9995
722k
    int isneg = 0;
9996
722k
    int exponent = 0;
9997
722k
    int is_exponent_negative = 0;
9998
722k
#ifdef __GNUC__
9999
722k
    unsigned long tmp = 0;
10000
722k
    double temp;
10001
722k
#endif
10002
722k
    if (cur == NULL) return(0);
10003
3.01M
    while (IS_BLANK_CH(*cur)) cur++;
10004
722k
    if (*cur == '-') {
10005
35.8k
  isneg = 1;
10006
35.8k
  cur++;
10007
35.8k
    }
10008
722k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
10009
609k
        return(xmlXPathNAN);
10010
609k
    }
10011
10012
113k
#ifdef __GNUC__
10013
    /*
10014
     * tmp/temp is a workaround against a gcc compiler bug
10015
     * http://veillard.com/gcc.bug
10016
     */
10017
113k
    ret = 0;
10018
296k
    while ((*cur >= '0') && (*cur <= '9')) {
10019
183k
  ret = ret * 10;
10020
183k
  tmp = (*cur - '0');
10021
183k
  ok = 1;
10022
183k
  cur++;
10023
183k
  temp = (double) tmp;
10024
183k
  ret = ret + temp;
10025
183k
    }
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
113k
    if (*cur == '.') {
10036
59.9k
  int v, frac = 0, max;
10037
59.9k
  double fraction = 0;
10038
10039
59.9k
        cur++;
10040
59.9k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10041
9.21k
      return(xmlXPathNAN);
10042
9.21k
  }
10043
63.1k
        while (*cur == '0') {
10044
12.4k
      frac = frac + 1;
10045
12.4k
      cur++;
10046
12.4k
        }
10047
50.7k
        max = frac + MAX_FRAC;
10048
113k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10049
62.3k
      v = (*cur - '0');
10050
62.3k
      fraction = fraction * 10 + v;
10051
62.3k
      frac = frac + 1;
10052
62.3k
      cur++;
10053
62.3k
  }
10054
50.7k
  fraction /= pow(10.0, frac);
10055
50.7k
  ret = ret + fraction;
10056
56.2k
  while ((*cur >= '0') && (*cur <= '9'))
10057
5.52k
      cur++;
10058
50.7k
    }
10059
103k
    if ((*cur == 'e') || (*cur == 'E')) {
10060
19.2k
      cur++;
10061
19.2k
      if (*cur == '-') {
10062
4.56k
  is_exponent_negative = 1;
10063
4.56k
  cur++;
10064
14.6k
      } else if (*cur == '+') {
10065
1.09k
        cur++;
10066
1.09k
      }
10067
45.9k
      while ((*cur >= '0') && (*cur <= '9')) {
10068
26.7k
        if (exponent < 1000000)
10069
22.0k
    exponent = exponent * 10 + (*cur - '0');
10070
26.7k
  cur++;
10071
26.7k
      }
10072
19.2k
    }
10073
127k
    while (IS_BLANK_CH(*cur)) cur++;
10074
103k
    if (*cur != 0) return(xmlXPathNAN);
10075
74.1k
    if (isneg) ret = -ret;
10076
74.1k
    if (is_exponent_negative) exponent = -exponent;
10077
74.1k
    ret *= pow(10.0, (double)exponent);
10078
74.1k
    return(ret);
10079
103k
}
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
447k
{
10095
447k
    double ret = 0.0;
10096
447k
    int ok = 0;
10097
447k
    int exponent = 0;
10098
447k
    int is_exponent_negative = 0;
10099
447k
    xmlXPathObjectPtr num;
10100
447k
#ifdef __GNUC__
10101
447k
    unsigned long tmp = 0;
10102
447k
    double temp;
10103
447k
#endif
10104
10105
447k
    CHECK_ERROR;
10106
444k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10107
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10108
0
    }
10109
444k
#ifdef __GNUC__
10110
    /*
10111
     * tmp/temp is a workaround against a gcc compiler bug
10112
     * http://veillard.com/gcc.bug
10113
     */
10114
444k
    ret = 0;
10115
1.15M
    while ((CUR >= '0') && (CUR <= '9')) {
10116
709k
  ret = ret * 10;
10117
709k
  tmp = (CUR - '0');
10118
709k
        ok = 1;
10119
709k
        NEXT;
10120
709k
  temp = (double) tmp;
10121
709k
  ret = ret + temp;
10122
709k
    }
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
444k
    if (CUR == '.') {
10132
119k
  int v, frac = 0, max;
10133
119k
  double fraction = 0;
10134
10135
119k
        NEXT;
10136
119k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10137
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10138
0
        }
10139
180k
        while (CUR == '0') {
10140
60.4k
            frac = frac + 1;
10141
60.4k
            NEXT;
10142
60.4k
        }
10143
119k
        max = frac + MAX_FRAC;
10144
248k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10145
128k
      v = (CUR - '0');
10146
128k
      fraction = fraction * 10 + v;
10147
128k
      frac = frac + 1;
10148
128k
            NEXT;
10149
128k
        }
10150
119k
        fraction /= pow(10.0, frac);
10151
119k
        ret = ret + fraction;
10152
138k
        while ((CUR >= '0') && (CUR <= '9'))
10153
18.3k
            NEXT;
10154
119k
    }
10155
444k
    if ((CUR == 'e') || (CUR == 'E')) {
10156
30.3k
        NEXT;
10157
30.3k
        if (CUR == '-') {
10158
6.04k
            is_exponent_negative = 1;
10159
6.04k
            NEXT;
10160
24.3k
        } else if (CUR == '+') {
10161
1.61k
      NEXT;
10162
1.61k
  }
10163
91.4k
        while ((CUR >= '0') && (CUR <= '9')) {
10164
61.0k
            if (exponent < 1000000)
10165
44.1k
                exponent = exponent * 10 + (CUR - '0');
10166
61.0k
            NEXT;
10167
61.0k
        }
10168
30.3k
        if (is_exponent_negative)
10169
6.04k
            exponent = -exponent;
10170
30.3k
        ret *= pow(10.0, (double) exponent);
10171
30.3k
    }
10172
444k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10173
444k
    if (num == NULL) {
10174
0
  ctxt->error = XPATH_MEMORY_ERROR;
10175
444k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10176
444k
                              NULL) == -1) {
10177
0
        xmlXPathReleaseObject(ctxt->context, num);
10178
0
    }
10179
444k
}
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
4.07k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10194
4.07k
    const xmlChar *q;
10195
4.07k
    xmlChar *ret = NULL;
10196
10197
4.07k
    if (CUR == '"') {
10198
1.53k
        NEXT;
10199
1.53k
  q = CUR_PTR;
10200
48.5k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10201
47.0k
      NEXT;
10202
1.53k
  if (!IS_CHAR_CH(CUR)) {
10203
1.09k
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10204
438
  } else {
10205
438
      ret = xmlStrndup(q, CUR_PTR - q);
10206
438
      NEXT;
10207
438
        }
10208
2.53k
    } else if (CUR == '\'') {
10209
1.78k
        NEXT;
10210
1.78k
  q = CUR_PTR;
10211
48.6k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10212
46.8k
      NEXT;
10213
1.78k
  if (!IS_CHAR_CH(CUR)) {
10214
1.10k
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10215
673
  } else {
10216
673
      ret = xmlStrndup(q, CUR_PTR - q);
10217
673
      NEXT;
10218
673
        }
10219
1.78k
    } else {
10220
758
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10221
0
    }
10222
1.11k
    return(ret);
10223
4.07k
}
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
405k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10238
405k
    const xmlChar *q;
10239
405k
    xmlChar *ret = NULL;
10240
405k
    xmlXPathObjectPtr lit;
10241
10242
405k
    if (CUR == '"') {
10243
21.9k
        NEXT;
10244
21.9k
  q = CUR_PTR;
10245
389k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10246
368k
      NEXT;
10247
21.9k
  if (!IS_CHAR_CH(CUR)) {
10248
10.4k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10249
11.4k
  } else {
10250
11.4k
      ret = xmlStrndup(q, CUR_PTR - q);
10251
11.4k
      NEXT;
10252
11.4k
        }
10253
383k
    } else if (CUR == '\'') {
10254
383k
        NEXT;
10255
383k
  q = CUR_PTR;
10256
7.03M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10257
6.65M
      NEXT;
10258
383k
  if (!IS_CHAR_CH(CUR)) {
10259
15.6k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10260
367k
  } else {
10261
367k
      ret = xmlStrndup(q, CUR_PTR - q);
10262
367k
      NEXT;
10263
367k
        }
10264
383k
    } else {
10265
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10266
0
    }
10267
379k
    if (ret == NULL) return;
10268
379k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10269
379k
    if (lit == NULL) {
10270
0
  ctxt->error = XPATH_MEMORY_ERROR;
10271
379k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10272
379k
                              NULL) == -1) {
10273
0
        xmlXPathReleaseObject(ctxt->context, lit);
10274
0
    }
10275
379k
    xmlFree(ret);
10276
379k
}
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
60.6k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10297
60.6k
    xmlChar *name;
10298
60.6k
    xmlChar *prefix;
10299
10300
60.6k
    SKIP_BLANKS;
10301
60.6k
    if (CUR != '$') {
10302
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10303
0
    }
10304
60.6k
    NEXT;
10305
60.6k
    name = xmlXPathParseQName(ctxt, &prefix);
10306
60.6k
    if (name == NULL) {
10307
7.31k
        xmlFree(prefix);
10308
7.31k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10309
0
    }
10310
53.2k
    ctxt->comp->last = -1;
10311
53.2k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10312
0
        xmlFree(prefix);
10313
0
        xmlFree(name);
10314
0
    }
10315
53.2k
    SKIP_BLANKS;
10316
53.2k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10317
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10318
0
    }
10319
53.2k
}
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
625k
xmlXPathIsNodeType(const xmlChar *name) {
10336
625k
    if (name == NULL)
10337
0
  return(0);
10338
10339
625k
    if (xmlStrEqual(name, BAD_CAST "node"))
10340
6.00k
  return(1);
10341
619k
    if (xmlStrEqual(name, BAD_CAST "text"))
10342
2.66k
  return(1);
10343
617k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10344
985
  return(1);
10345
616k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10346
310
  return(1);
10347
615k
    return(0);
10348
616k
}
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
615k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10362
615k
    xmlChar *name;
10363
615k
    xmlChar *prefix;
10364
615k
    int nbargs = 0;
10365
615k
    int sort = 1;
10366
10367
615k
    name = xmlXPathParseQName(ctxt, &prefix);
10368
615k
    if (name == NULL) {
10369
2.00k
  xmlFree(prefix);
10370
2.00k
  XP_ERROR(XPATH_EXPR_ERROR);
10371
0
    }
10372
613k
    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
613k
    if (CUR != '(') {
10383
1.40k
  xmlFree(name);
10384
1.40k
  xmlFree(prefix);
10385
1.40k
  XP_ERROR(XPATH_EXPR_ERROR);
10386
0
    }
10387
612k
    NEXT;
10388
612k
    SKIP_BLANKS;
10389
10390
    /*
10391
    * Optimization for count(): we don't need the node-set to be sorted.
10392
    */
10393
612k
    if ((prefix == NULL) && (name[0] == 'c') &&
10394
612k
  xmlStrEqual(name, BAD_CAST "count"))
10395
1.29k
    {
10396
1.29k
  sort = 0;
10397
1.29k
    }
10398
612k
    ctxt->comp->last = -1;
10399
612k
    if (CUR != ')') {
10400
838k
  while (CUR != 0) {
10401
804k
      int op1 = ctxt->comp->last;
10402
804k
      ctxt->comp->last = -1;
10403
804k
      xmlXPathCompileExpr(ctxt, sort);
10404
804k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10405
127k
    xmlFree(name);
10406
127k
    xmlFree(prefix);
10407
127k
    return;
10408
127k
      }
10409
677k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10410
677k
      nbargs++;
10411
677k
      if (CUR == ')') break;
10412
312k
      if (CUR != ',') {
10413
50.0k
    xmlFree(name);
10414
50.0k
    xmlFree(prefix);
10415
50.0k
    XP_ERROR(XPATH_EXPR_ERROR);
10416
0
      }
10417
262k
      NEXT;
10418
262k
      SKIP_BLANKS;
10419
262k
  }
10420
575k
    }
10421
435k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10422
0
        xmlFree(prefix);
10423
0
        xmlFree(name);
10424
0
    }
10425
435k
    NEXT;
10426
435k
    SKIP_BLANKS;
10427
435k
}
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
1.77M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10443
1.77M
    SKIP_BLANKS;
10444
1.77M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10445
1.71M
    else if (CUR == '(') {
10446
241k
  NEXT;
10447
241k
  SKIP_BLANKS;
10448
241k
  xmlXPathCompileExpr(ctxt, 1);
10449
241k
  CHECK_ERROR;
10450
84.1k
  if (CUR != ')') {
10451
18.3k
      XP_ERROR(XPATH_EXPR_ERROR);
10452
0
  }
10453
65.8k
  NEXT;
10454
65.8k
  SKIP_BLANKS;
10455
1.46M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10456
447k
  xmlXPathCompNumber(ctxt);
10457
1.02M
    } else if ((CUR == '\'') || (CUR == '"')) {
10458
405k
  xmlXPathCompLiteral(ctxt);
10459
615k
    } else {
10460
615k
  xmlXPathCompFunctionCall(ctxt);
10461
615k
    }
10462
1.59M
    SKIP_BLANKS;
10463
1.59M
}
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
1.77M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10482
1.77M
    xmlXPathCompPrimaryExpr(ctxt);
10483
1.77M
    CHECK_ERROR;
10484
1.37M
    SKIP_BLANKS;
10485
10486
1.46M
    while (CUR == '[') {
10487
85.8k
  xmlXPathCompPredicate(ctxt, 1);
10488
85.8k
  SKIP_BLANKS;
10489
85.8k
    }
10490
10491
10492
1.37M
}
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
3.29M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10513
3.29M
    int l;
10514
3.29M
    int c;
10515
3.29M
    const xmlChar *cur;
10516
3.29M
    xmlChar *ret;
10517
10518
3.29M
    cur = ctxt->cur;
10519
10520
3.29M
    c = CUR_CHAR(l);
10521
3.29M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10522
3.29M
  (!IS_LETTER(c) && (c != '_') &&
10523
3.29M
         (c != ':'))) {
10524
1.67M
  return(NULL);
10525
1.67M
    }
10526
10527
12.6M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10528
12.6M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10529
12.3M
            (c == '.') || (c == '-') ||
10530
12.3M
      (c == '_') || (c == ':') ||
10531
12.3M
      (IS_COMBINING(c)) ||
10532
12.3M
      (IS_EXTENDER(c)))) {
10533
11.0M
  NEXTL(l);
10534
11.0M
  c = CUR_CHAR(l);
10535
11.0M
    }
10536
1.62M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10537
1.62M
    ctxt->cur = cur;
10538
1.62M
    return(ret);
10539
3.29M
}
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
5.28M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10561
5.28M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10562
5.28M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10563
10564
5.28M
    SKIP_BLANKS;
10565
5.28M
    if ((CUR == '$') || (CUR == '(') ||
10566
5.28M
  (IS_ASCII_DIGIT(CUR)) ||
10567
5.28M
        (CUR == '\'') || (CUR == '"') ||
10568
5.28M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10569
1.15M
  lc = 0;
10570
4.13M
    } else if (CUR == '*') {
10571
  /* relative or absolute location path */
10572
220k
  lc = 1;
10573
3.91M
    } else if (CUR == '/') {
10574
  /* relative or absolute location path */
10575
415k
  lc = 1;
10576
3.49M
    } else if (CUR == '@') {
10577
  /* relative abbreviated attribute location path */
10578
66.4k
  lc = 1;
10579
3.42M
    } else if (CUR == '.') {
10580
  /* relative abbreviated attribute location path */
10581
130k
  lc = 1;
10582
3.29M
    } 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
3.29M
  SKIP_BLANKS;
10595
3.29M
  name = xmlXPathScanName(ctxt);
10596
3.29M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10597
#ifdef DEBUG_STEP
10598
      xmlGenericError(xmlGenericErrorContext,
10599
        "PathExpr: Axis\n");
10600
#endif
10601
18.0k
      lc = 1;
10602
18.0k
      xmlFree(name);
10603
3.27M
  } else if (name != NULL) {
10604
1.60M
      int len =xmlStrlen(name);
10605
10606
10607
2.41M
      while (NXT(len) != 0) {
10608
2.33M
    if (NXT(len) == '/') {
10609
        /* element name */
10610
#ifdef DEBUG_STEP
10611
        xmlGenericError(xmlGenericErrorContext,
10612
          "PathExpr: AbbrRelLocation\n");
10613
#endif
10614
163k
        lc = 1;
10615
163k
        break;
10616
2.17M
    } else if (IS_BLANK_CH(NXT(len))) {
10617
        /* ignore blanks */
10618
806k
        ;
10619
1.36M
    } else if (NXT(len) == ':') {
10620
#ifdef DEBUG_STEP
10621
        xmlGenericError(xmlGenericErrorContext,
10622
          "PathExpr: AbbrRelLocation\n");
10623
#endif
10624
3.75k
        lc = 1;
10625
3.75k
        break;
10626
1.36M
    } else if ((NXT(len) == '(')) {
10627
        /* Node Type or Function */
10628
625k
        if (xmlXPathIsNodeType(name)) {
10629
#ifdef DEBUG_STEP
10630
            xmlGenericError(xmlGenericErrorContext,
10631
        "PathExpr: Type search\n");
10632
#endif
10633
9.96k
      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
615k
        } else {
10640
#ifdef DEBUG_STEP
10641
            xmlGenericError(xmlGenericErrorContext,
10642
        "PathExpr: function call\n");
10643
#endif
10644
615k
      lc = 0;
10645
615k
        }
10646
625k
                    break;
10647
738k
    } else if ((NXT(len) == '[')) {
10648
        /* element name */
10649
#ifdef DEBUG_STEP
10650
        xmlGenericError(xmlGenericErrorContext,
10651
          "PathExpr: AbbrRelLocation\n");
10652
#endif
10653
75.7k
        lc = 1;
10654
75.7k
        break;
10655
663k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10656
663k
         (NXT(len) == '=')) {
10657
198k
        lc = 1;
10658
198k
        break;
10659
464k
    } else {
10660
464k
        lc = 1;
10661
464k
        break;
10662
464k
    }
10663
806k
    len++;
10664
806k
      }
10665
1.60M
      if (NXT(len) == 0) {
10666
#ifdef DEBUG_STEP
10667
    xmlGenericError(xmlGenericErrorContext,
10668
      "PathExpr: AbbrRelLocation\n");
10669
#endif
10670
    /* element name */
10671
75.9k
    lc = 1;
10672
75.9k
      }
10673
1.60M
      xmlFree(name);
10674
1.67M
  } else {
10675
      /* make sure all cases are covered explicitly */
10676
1.67M
      XP_ERROR(XPATH_EXPR_ERROR);
10677
0
  }
10678
3.29M
    }
10679
10680
3.61M
    if (lc) {
10681
1.84M
  if (CUR == '/') {
10682
415k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10683
1.42M
  } else {
10684
1.42M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10685
1.42M
  }
10686
1.84M
  xmlXPathCompLocationPath(ctxt);
10687
1.84M
    } else {
10688
1.77M
  xmlXPathCompFilterExpr(ctxt);
10689
1.77M
  CHECK_ERROR;
10690
1.35M
  if ((CUR == '/') && (NXT(1) == '/')) {
10691
18.9k
      SKIP(2);
10692
18.9k
      SKIP_BLANKS;
10693
10694
18.9k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10695
18.9k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10696
10697
18.9k
      xmlXPathCompRelativeLocationPath(ctxt);
10698
1.33M
  } else if (CUR == '/') {
10699
23.5k
      xmlXPathCompRelativeLocationPath(ctxt);
10700
23.5k
  }
10701
1.35M
    }
10702
3.20M
    SKIP_BLANKS;
10703
3.20M
}
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
4.95M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10717
4.95M
    xmlXPathCompPathExpr(ctxt);
10718
4.95M
    CHECK_ERROR;
10719
2.67M
    SKIP_BLANKS;
10720
2.99M
    while (CUR == '|') {
10721
327k
  int op1 = ctxt->comp->last;
10722
327k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723
10724
327k
  NEXT;
10725
327k
  SKIP_BLANKS;
10726
327k
  xmlXPathCompPathExpr(ctxt);
10727
10728
327k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10729
10730
327k
  SKIP_BLANKS;
10731
327k
    }
10732
2.67M
}
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
4.95M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10746
4.95M
    int minus = 0;
10747
4.95M
    int found = 0;
10748
10749
4.95M
    SKIP_BLANKS;
10750
5.27M
    while (CUR == '-') {
10751
313k
        minus = 1 - minus;
10752
313k
  found = 1;
10753
313k
  NEXT;
10754
313k
  SKIP_BLANKS;
10755
313k
    }
10756
10757
4.95M
    xmlXPathCompUnionExpr(ctxt);
10758
4.95M
    CHECK_ERROR;
10759
2.63M
    if (found) {
10760
119k
  if (minus)
10761
97.8k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10762
21.2k
  else
10763
21.2k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10764
119k
    }
10765
2.63M
}
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
4.64M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10782
4.64M
    xmlXPathCompUnaryExpr(ctxt);
10783
4.64M
    CHECK_ERROR;
10784
2.35M
    SKIP_BLANKS;
10785
2.63M
    while ((CUR == '*') ||
10786
2.63M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10787
2.63M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10788
316k
  int op = -1;
10789
316k
  int op1 = ctxt->comp->last;
10790
10791
316k
        if (CUR == '*') {
10792
294k
      op = 0;
10793
294k
      NEXT;
10794
294k
  } else if (CUR == 'd') {
10795
10.8k
      op = 1;
10796
10.8k
      SKIP(3);
10797
10.8k
  } else if (CUR == 'm') {
10798
10.7k
      op = 2;
10799
10.7k
      SKIP(3);
10800
10.7k
  }
10801
316k
  SKIP_BLANKS;
10802
316k
        xmlXPathCompUnaryExpr(ctxt);
10803
316k
  CHECK_ERROR;
10804
280k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10805
280k
  SKIP_BLANKS;
10806
280k
    }
10807
2.35M
}
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
4.44M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10822
10823
4.44M
    xmlXPathCompMultiplicativeExpr(ctxt);
10824
4.44M
    CHECK_ERROR;
10825
2.15M
    SKIP_BLANKS;
10826
2.31M
    while ((CUR == '+') || (CUR == '-')) {
10827
194k
  int plus;
10828
194k
  int op1 = ctxt->comp->last;
10829
10830
194k
        if (CUR == '+') plus = 1;
10831
135k
  else plus = 0;
10832
194k
  NEXT;
10833
194k
  SKIP_BLANKS;
10834
194k
        xmlXPathCompMultiplicativeExpr(ctxt);
10835
194k
  CHECK_ERROR;
10836
161k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10837
161k
  SKIP_BLANKS;
10838
161k
    }
10839
2.15M
}
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
4.23M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10861
4.23M
    xmlXPathCompAdditiveExpr(ctxt);
10862
4.23M
    CHECK_ERROR;
10863
1.93M
    SKIP_BLANKS;
10864
2.12M
    while ((CUR == '<') || (CUR == '>')) {
10865
215k
  int inf, strict;
10866
215k
  int op1 = ctxt->comp->last;
10867
10868
215k
        if (CUR == '<') inf = 1;
10869
137k
  else inf = 0;
10870
215k
  if (NXT(1) == '=') strict = 0;
10871
192k
  else strict = 1;
10872
215k
  NEXT;
10873
215k
  if (!strict) NEXT;
10874
215k
  SKIP_BLANKS;
10875
215k
        xmlXPathCompAdditiveExpr(ctxt);
10876
215k
  CHECK_ERROR;
10877
183k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10878
183k
  SKIP_BLANKS;
10879
183k
    }
10880
1.93M
}
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
4.03M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10900
4.03M
    xmlXPathCompRelationalExpr(ctxt);
10901
4.03M
    CHECK_ERROR;
10902
1.74M
    SKIP_BLANKS;
10903
1.90M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10904
194k
  int eq;
10905
194k
  int op1 = ctxt->comp->last;
10906
10907
194k
        if (CUR == '=') eq = 1;
10908
23.6k
  else eq = 0;
10909
194k
  NEXT;
10910
194k
  if (!eq) NEXT;
10911
194k
  SKIP_BLANKS;
10912
194k
        xmlXPathCompRelationalExpr(ctxt);
10913
194k
  CHECK_ERROR;
10914
166k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10915
166k
  SKIP_BLANKS;
10916
166k
    }
10917
1.74M
}
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
4.01M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10931
4.01M
    xmlXPathCompEqualityExpr(ctxt);
10932
4.01M
    CHECK_ERROR;
10933
1.69M
    SKIP_BLANKS;
10934
1.71M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10935
24.4k
  int op1 = ctxt->comp->last;
10936
24.4k
        SKIP(3);
10937
24.4k
  SKIP_BLANKS;
10938
24.4k
        xmlXPathCompEqualityExpr(ctxt);
10939
24.4k
  CHECK_ERROR;
10940
18.1k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10941
18.1k
  SKIP_BLANKS;
10942
18.1k
    }
10943
1.69M
}
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
3.97M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10957
3.97M
    xmlXPathContextPtr xpctxt = ctxt->context;
10958
10959
3.97M
    if (xpctxt != NULL) {
10960
3.97M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10961
3.97M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10962
        /*
10963
         * Parsing a single '(' pushes about 10 functions on the call stack
10964
         * before recursing!
10965
         */
10966
3.97M
        xpctxt->depth += 10;
10967
3.97M
    }
10968
10969
3.97M
    xmlXPathCompAndExpr(ctxt);
10970
3.97M
    CHECK_ERROR;
10971
1.65M
    SKIP_BLANKS;
10972
1.68M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10973
37.5k
  int op1 = ctxt->comp->last;
10974
37.5k
        SKIP(2);
10975
37.5k
  SKIP_BLANKS;
10976
37.5k
        xmlXPathCompAndExpr(ctxt);
10977
37.5k
  CHECK_ERROR;
10978
29.2k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10979
29.2k
  SKIP_BLANKS;
10980
29.2k
    }
10981
1.65M
    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
1.13M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10989
1.13M
    }
10990
10991
1.65M
    if (xpctxt != NULL)
10992
1.65M
        xpctxt->depth -= 10;
10993
1.65M
}
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
341k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11007
341k
    int op1 = ctxt->comp->last;
11008
11009
341k
    SKIP_BLANKS;
11010
341k
    if (CUR != '[') {
11011
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11012
0
    }
11013
341k
    NEXT;
11014
341k
    SKIP_BLANKS;
11015
11016
341k
    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
341k
    if (! filter)
11027
255k
  xmlXPathCompileExpr(ctxt, 0);
11028
85.8k
    else
11029
85.8k
  xmlXPathCompileExpr(ctxt, 1);
11030
341k
    CHECK_ERROR;
11031
11032
119k
    if (CUR != ']') {
11033
18.8k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11034
0
    }
11035
11036
100k
    if (filter)
11037
26.3k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11038
73.8k
    else
11039
73.8k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11040
11041
100k
    NEXT;
11042
100k
    SKIP_BLANKS;
11043
100k
}
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
2.06M
         xmlChar *name) {
11070
2.06M
    int blanks;
11071
11072
2.06M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11073
0
  STRANGE;
11074
0
  return(NULL);
11075
0
    }
11076
2.06M
    *type = (xmlXPathTypeVal) 0;
11077
2.06M
    *test = (xmlXPathTestVal) 0;
11078
2.06M
    *prefix = NULL;
11079
2.06M
    SKIP_BLANKS;
11080
11081
2.06M
    if ((name == NULL) && (CUR == '*')) {
11082
  /*
11083
   * All elements
11084
   */
11085
412k
  NEXT;
11086
412k
  *test = NODE_TEST_ALL;
11087
412k
  return(NULL);
11088
412k
    }
11089
11090
1.65M
    if (name == NULL)
11091
197k
  name = xmlXPathParseNCName(ctxt);
11092
1.65M
    if (name == NULL) {
11093
98.2k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11094
0
    }
11095
11096
1.55M
    blanks = IS_BLANK_CH(CUR);
11097
1.55M
    SKIP_BLANKS;
11098
1.55M
    if (CUR == '(') {
11099
62.3k
  NEXT;
11100
  /*
11101
   * NodeType or PI search
11102
   */
11103
62.3k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11104
5.49k
      *type = NODE_TYPE_COMMENT;
11105
56.8k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11106
15.1k
      *type = NODE_TYPE_NODE;
11107
41.7k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11108
6.00k
      *type = NODE_TYPE_PI;
11109
35.7k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11110
20.9k
      *type = NODE_TYPE_TEXT;
11111
14.7k
  else {
11112
14.7k
      if (name != NULL)
11113
14.7k
    xmlFree(name);
11114
14.7k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11115
0
  }
11116
11117
47.6k
  *test = NODE_TEST_TYPE;
11118
11119
47.6k
  SKIP_BLANKS;
11120
47.6k
  if (*type == NODE_TYPE_PI) {
11121
      /*
11122
       * Specific case: search a PI by name.
11123
       */
11124
6.00k
      if (name != NULL)
11125
6.00k
    xmlFree(name);
11126
6.00k
      name = NULL;
11127
6.00k
      if (CUR != ')') {
11128
4.07k
    name = xmlXPathParseLiteral(ctxt);
11129
4.07k
                if (name == NULL) {
11130
2.96k
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11131
0
                }
11132
1.11k
    *test = NODE_TEST_PI;
11133
1.11k
    SKIP_BLANKS;
11134
1.11k
      }
11135
6.00k
  }
11136
44.6k
  if (CUR != ')') {
11137
8.48k
      if (name != NULL)
11138
8.48k
    xmlFree(name);
11139
8.48k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11140
0
  }
11141
36.1k
  NEXT;
11142
36.1k
  return(name);
11143
44.6k
    }
11144
1.49M
    *test = NODE_TEST_NAME;
11145
1.49M
    if ((!blanks) && (CUR == ':')) {
11146
165k
  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
165k
  *prefix = name;
11164
165k
#endif
11165
11166
165k
  if (CUR == '*') {
11167
      /*
11168
       * All elements
11169
       */
11170
17.6k
      NEXT;
11171
17.6k
      *test = NODE_TEST_ALL;
11172
17.6k
      return(NULL);
11173
17.6k
  }
11174
11175
148k
  name = xmlXPathParseNCName(ctxt);
11176
148k
  if (name == NULL) {
11177
15.9k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11178
0
  }
11179
148k
    }
11180
1.46M
    return(name);
11181
1.49M
}
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
1.59M
xmlXPathIsAxisName(const xmlChar *name) {
11205
1.59M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11206
1.59M
    switch (name[0]) {
11207
154k
  case 'a':
11208
154k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11209
3.29k
    ret = AXIS_ANCESTOR;
11210
154k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11211
1.49k
    ret = AXIS_ANCESTOR_OR_SELF;
11212
154k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11213
1.91k
    ret = AXIS_ATTRIBUTE;
11214
154k
      break;
11215
108k
  case 'c':
11216
108k
      if (xmlStrEqual(name, BAD_CAST "child"))
11217
3.12k
    ret = AXIS_CHILD;
11218
108k
      break;
11219
110k
  case 'd':
11220
110k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11221
1.18k
    ret = AXIS_DESCENDANT;
11222
110k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11223
1.30k
    ret = AXIS_DESCENDANT_OR_SELF;
11224
110k
      break;
11225
34.5k
  case 'f':
11226
34.5k
      if (xmlStrEqual(name, BAD_CAST "following"))
11227
2.89k
    ret = AXIS_FOLLOWING;
11228
34.5k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11229
2.01k
    ret = AXIS_FOLLOWING_SIBLING;
11230
34.5k
      break;
11231
90.8k
  case 'n':
11232
90.8k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11233
5.48k
    ret = AXIS_NAMESPACE;
11234
90.8k
      break;
11235
51.3k
  case 'p':
11236
51.3k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11237
1.68k
    ret = AXIS_PARENT;
11238
51.3k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11239
3.07k
    ret = AXIS_PRECEDING;
11240
51.3k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11241
1.95k
    ret = AXIS_PRECEDING_SIBLING;
11242
51.3k
      break;
11243
129k
  case 's':
11244
129k
      if (xmlStrEqual(name, BAD_CAST "self"))
11245
6.81k
    ret = AXIS_SELF;
11246
129k
      break;
11247
1.59M
    }
11248
1.59M
    return(ret);
11249
1.59M
}
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
2.47M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11285
#ifdef LIBXML_XPTR_LOCS_ENABLED
11286
    int rangeto = 0;
11287
    int op2 = -1;
11288
#endif
11289
11290
2.47M
    SKIP_BLANKS;
11291
2.47M
    if ((CUR == '.') && (NXT(1) == '.')) {
11292
29.7k
  SKIP(2);
11293
29.7k
  SKIP_BLANKS;
11294
29.7k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11295
29.7k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11296
2.44M
    } else if (CUR == '.') {
11297
172k
  NEXT;
11298
172k
  SKIP_BLANKS;
11299
2.27M
    } else {
11300
2.27M
  xmlChar *name = NULL;
11301
2.27M
  xmlChar *prefix = NULL;
11302
2.27M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11303
2.27M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11304
2.27M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11305
2.27M
  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
2.27M
  if (CUR == '*') {
11338
392k
      axis = AXIS_CHILD;
11339
1.88M
  } else {
11340
1.88M
      if (name == NULL)
11341
1.88M
    name = xmlXPathParseNCName(ctxt);
11342
1.88M
      if (name != NULL) {
11343
1.59M
    axis = xmlXPathIsAxisName(name);
11344
1.59M
    if (axis != 0) {
11345
36.2k
        SKIP_BLANKS;
11346
36.2k
        if ((CUR == ':') && (NXT(1) == ':')) {
11347
23.2k
      SKIP(2);
11348
23.2k
      xmlFree(name);
11349
23.2k
      name = NULL;
11350
23.2k
        } else {
11351
      /* an element name can conflict with an axis one :-\ */
11352
12.9k
      axis = AXIS_CHILD;
11353
12.9k
        }
11354
1.56M
    } else {
11355
1.56M
        axis = AXIS_CHILD;
11356
1.56M
    }
11357
1.59M
      } else if (CUR == '@') {
11358
109k
    NEXT;
11359
109k
    axis = AXIS_ATTRIBUTE;
11360
176k
      } else {
11361
176k
    axis = AXIS_CHILD;
11362
176k
      }
11363
1.88M
  }
11364
11365
2.27M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11366
206k
            xmlFree(name);
11367
206k
            return;
11368
206k
        }
11369
11370
2.06M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11371
2.06M
  if (test == 0)
11372
113k
      return;
11373
11374
1.95M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11375
1.95M
      (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
1.95M
  op1 = ctxt->comp->last;
11399
1.95M
  ctxt->comp->last = -1;
11400
11401
1.95M
  SKIP_BLANKS;
11402
2.21M
  while (CUR == '[') {
11403
255k
      xmlXPathCompPredicate(ctxt, 0);
11404
255k
  }
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
1.95M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11412
1.95M
                           test, type, (void *)prefix, (void *)name) == -1) {
11413
0
            xmlFree(prefix);
11414
0
            xmlFree(name);
11415
0
        }
11416
1.95M
    }
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
2.47M
}
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
1.82M
(xmlXPathParserContextPtr ctxt) {
11443
1.82M
    SKIP_BLANKS;
11444
1.82M
    if ((CUR == '/') && (NXT(1) == '/')) {
11445
23.8k
  SKIP(2);
11446
23.8k
  SKIP_BLANKS;
11447
23.8k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11448
23.8k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11449
1.80M
    } else if (CUR == '/') {
11450
49.0k
      NEXT;
11451
49.0k
  SKIP_BLANKS;
11452
49.0k
    }
11453
1.82M
    xmlXPathCompStep(ctxt);
11454
1.82M
    CHECK_ERROR;
11455
1.58M
    SKIP_BLANKS;
11456
2.24M
    while (CUR == '/') {
11457
654k
  if ((CUR == '/') && (NXT(1) == '/')) {
11458
226k
      SKIP(2);
11459
226k
      SKIP_BLANKS;
11460
226k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11461
226k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11462
226k
      xmlXPathCompStep(ctxt);
11463
428k
  } else if (CUR == '/') {
11464
428k
      NEXT;
11465
428k
      SKIP_BLANKS;
11466
428k
      xmlXPathCompStep(ctxt);
11467
428k
  }
11468
654k
  SKIP_BLANKS;
11469
654k
    }
11470
1.58M
}
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
1.84M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11495
1.84M
    SKIP_BLANKS;
11496
1.84M
    if (CUR != '/') {
11497
1.42M
        xmlXPathCompRelativeLocationPath(ctxt);
11498
1.42M
    } else {
11499
774k
  while (CUR == '/') {
11500
427k
      if ((CUR == '/') && (NXT(1) == '/')) {
11501
205k
    SKIP(2);
11502
205k
    SKIP_BLANKS;
11503
205k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11504
205k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11505
205k
    xmlXPathCompRelativeLocationPath(ctxt);
11506
221k
      } else if (CUR == '/') {
11507
221k
    NEXT;
11508
221k
    SKIP_BLANKS;
11509
221k
    if ((CUR != 0 ) &&
11510
221k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11511
209k
         (CUR == '@') || (CUR == '*')))
11512
148k
        xmlXPathCompRelativeLocationPath(ctxt);
11513
221k
      }
11514
427k
      CHECK_ERROR;
11515
427k
  }
11516
415k
    }
11517
1.84M
}
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
110k
{
11635
110k
    xmlXPathContextPtr xpctxt;
11636
110k
    xmlNodePtr oldnode;
11637
110k
    xmlDocPtr olddoc;
11638
110k
    xmlXPathStepOpPtr filterOp;
11639
110k
    int oldcs, oldpp;
11640
110k
    int i, j, pos;
11641
11642
110k
    if ((set == NULL) || (set->nodeNr == 0))
11643
11.8k
        return;
11644
11645
    /*
11646
    * Check if the node set contains a sufficient number of nodes for
11647
    * the requested range.
11648
    */
11649
98.7k
    if (set->nodeNr < minPos) {
11650
2.12k
        xmlXPathNodeSetClear(set, hasNsNodes);
11651
2.12k
        return;
11652
2.12k
    }
11653
11654
96.6k
    xpctxt = ctxt->context;
11655
96.6k
    oldnode = xpctxt->node;
11656
96.6k
    olddoc = xpctxt->doc;
11657
96.6k
    oldcs = xpctxt->contextSize;
11658
96.6k
    oldpp = xpctxt->proximityPosition;
11659
96.6k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11660
11661
96.6k
    xpctxt->contextSize = set->nodeNr;
11662
11663
330k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11664
267k
        xmlNodePtr node = set->nodeTab[i];
11665
267k
        int res;
11666
11667
267k
        xpctxt->node = node;
11668
267k
        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
267k
        if ((node->type != XML_NAMESPACE_DECL) &&
11677
267k
            (node->doc != NULL))
11678
266k
            xpctxt->doc = node->doc;
11679
11680
267k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11681
11682
267k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11683
1.91k
            break;
11684
265k
        if (res < 0) {
11685
            /* Shouldn't happen */
11686
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11687
0
            break;
11688
0
        }
11689
11690
265k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11691
95.7k
            if (i != j) {
11692
6.90k
                set->nodeTab[j] = node;
11693
6.90k
                set->nodeTab[i] = NULL;
11694
6.90k
            }
11695
11696
95.7k
            j += 1;
11697
169k
        } else {
11698
            /* Remove the entry from the initial node set. */
11699
169k
            set->nodeTab[i] = NULL;
11700
169k
            if (node->type == XML_NAMESPACE_DECL)
11701
778
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11702
169k
        }
11703
11704
265k
        if (res != 0) {
11705
100k
            if (pos == maxPos) {
11706
32.1k
                i += 1;
11707
32.1k
                break;
11708
32.1k
            }
11709
11710
68.6k
            pos += 1;
11711
68.6k
        }
11712
265k
    }
11713
11714
    /* Free remaining nodes. */
11715
96.6k
    if (hasNsNodes) {
11716
7.25k
        for (; i < set->nodeNr; i++) {
11717
2.86k
            xmlNodePtr node = set->nodeTab[i];
11718
2.86k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11719
42
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11720
2.86k
        }
11721
4.38k
    }
11722
11723
96.6k
    set->nodeNr = j;
11724
11725
    /* If too many elements were removed, shrink table to preserve memory. */
11726
96.6k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11727
96.6k
        (set->nodeNr < set->nodeMax / 2)) {
11728
1.75k
        xmlNodePtr *tmp;
11729
1.75k
        int nodeMax = set->nodeNr;
11730
11731
1.75k
        if (nodeMax < XML_NODESET_DEFAULT)
11732
1.74k
            nodeMax = XML_NODESET_DEFAULT;
11733
1.75k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11734
1.75k
                nodeMax * sizeof(xmlNodePtr));
11735
1.75k
        if (tmp == NULL) {
11736
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11737
1.75k
        } else {
11738
1.75k
            set->nodeTab = tmp;
11739
1.75k
            set->nodeMax = nodeMax;
11740
1.75k
        }
11741
1.75k
    }
11742
11743
96.6k
    xpctxt->node = oldnode;
11744
96.6k
    xpctxt->doc = olddoc;
11745
96.6k
    xpctxt->contextSize = oldcs;
11746
96.6k
    xpctxt->proximityPosition = oldpp;
11747
96.6k
}
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
104k
{
11888
104k
    if (op->ch1 != -1) {
11889
20.9k
  xmlXPathCompExprPtr comp = ctxt->comp;
11890
  /*
11891
  * Process inner predicates first.
11892
  */
11893
20.9k
  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
20.9k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11899
20.9k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11900
20.9k
        ctxt->context->depth += 1;
11901
20.9k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11902
20.9k
                                    1, set->nodeNr, hasNsNodes);
11903
20.9k
        ctxt->context->depth -= 1;
11904
20.9k
  CHECK_ERROR;
11905
20.9k
    }
11906
11907
103k
    if (op->ch2 != -1)
11908
103k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11909
103k
}
11910
11911
static int
11912
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11913
          xmlXPathStepOpPtr op,
11914
          int *maxPos)
11915
51.7k
{
11916
11917
51.7k
    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
51.7k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11933
0
  return(0);
11934
11935
51.7k
    if (op->ch2 != -1) {
11936
51.7k
  exprOp = &ctxt->comp->steps[op->ch2];
11937
51.7k
    } else
11938
0
  return(0);
11939
11940
51.7k
    if ((exprOp != NULL) &&
11941
51.7k
  (exprOp->op == XPATH_OP_VALUE) &&
11942
51.7k
  (exprOp->value4 != NULL) &&
11943
51.7k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11944
22.7k
    {
11945
22.7k
        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
22.7k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11959
22.2k
      *maxPos = (int) floatval;
11960
22.2k
            if (floatval == (double) *maxPos)
11961
21.8k
                return(1);
11962
22.2k
        }
11963
22.7k
    }
11964
29.9k
    return(0);
11965
51.7k
}
11966
11967
static int
11968
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11969
                           xmlXPathStepOpPtr op,
11970
         xmlNodePtr * first, xmlNodePtr * last,
11971
         int toBool)
11972
1.44M
{
11973
11974
1.44M
#define XP_TEST_HIT \
11975
4.63M
    if (hasAxisRange != 0) { \
11976
41.8k
  if (++pos == maxPos) { \
11977
16.7k
      if (addNode(seq, cur) < 0) \
11978
16.7k
          ctxt->error = XPATH_MEMORY_ERROR; \
11979
16.7k
      goto axis_range_end; } \
11980
4.59M
    } else { \
11981
4.59M
  if (addNode(seq, cur) < 0) \
11982
4.59M
      ctxt->error = XPATH_MEMORY_ERROR; \
11983
4.59M
  if (breakOnFirstHit) goto first_hit; }
11984
11985
1.44M
#define XP_TEST_HIT_NS \
11986
1.44M
    if (hasAxisRange != 0) { \
11987
651
  if (++pos == maxPos) { \
11988
199
      hasNsNodes = 1; \
11989
199
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11990
199
          ctxt->error = XPATH_MEMORY_ERROR; \
11991
199
  goto axis_range_end; } \
11992
22.5k
    } else { \
11993
22.5k
  hasNsNodes = 1; \
11994
22.5k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11995
22.5k
      ctxt->error = XPATH_MEMORY_ERROR; \
11996
22.5k
  if (breakOnFirstHit) goto first_hit; }
11997
11998
1.44M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999
1.44M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000
1.44M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001
1.44M
    const xmlChar *prefix = op->value4;
12002
1.44M
    const xmlChar *name = op->value5;
12003
1.44M
    const xmlChar *URI = NULL;
12004
12005
#ifdef DEBUG_STEP
12006
    int nbMatches = 0, prevMatches = 0;
12007
#endif
12008
1.44M
    int total = 0, hasNsNodes = 0;
12009
    /* The popped object holding the context nodes */
12010
1.44M
    xmlXPathObjectPtr obj;
12011
    /* The set of context nodes for the node tests */
12012
1.44M
    xmlNodeSetPtr contextSeq;
12013
1.44M
    int contextIdx;
12014
1.44M
    xmlNodePtr contextNode;
12015
    /* The final resulting node set wrt to all context nodes */
12016
1.44M
    xmlNodeSetPtr outSeq;
12017
    /*
12018
    * The temporary resulting node set wrt 1 context node.
12019
    * Used to feed predicate evaluation.
12020
    */
12021
1.44M
    xmlNodeSetPtr seq;
12022
1.44M
    xmlNodePtr cur;
12023
    /* First predicate operator */
12024
1.44M
    xmlXPathStepOpPtr predOp;
12025
1.44M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12026
1.44M
    int hasPredicateRange, hasAxisRange, pos;
12027
1.44M
    int breakOnFirstHit;
12028
12029
1.44M
    xmlXPathTraversalFunction next = NULL;
12030
1.44M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12031
1.44M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12032
1.44M
    xmlNodePtr oldContextNode;
12033
1.44M
    xmlXPathContextPtr xpctxt = ctxt->context;
12034
12035
12036
1.44M
    CHECK_TYPE0(XPATH_NODESET);
12037
1.44M
    obj = valuePop(ctxt);
12038
    /*
12039
    * Setup namespaces.
12040
    */
12041
1.44M
    if (prefix != NULL) {
12042
66.4k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12043
66.4k
        if (URI == NULL) {
12044
20.3k
      xmlXPathReleaseObject(xpctxt, obj);
12045
20.3k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12046
0
  }
12047
66.4k
    }
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
1.42M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12062
1.42M
    switch (axis) {
12063
1.84k
        case AXIS_ANCESTOR:
12064
1.84k
            first = NULL;
12065
1.84k
            next = xmlXPathNextAncestor;
12066
1.84k
            break;
12067
1.32k
        case AXIS_ANCESTOR_OR_SELF:
12068
1.32k
            first = NULL;
12069
1.32k
            next = xmlXPathNextAncestorOrSelf;
12070
1.32k
            break;
12071
106k
        case AXIS_ATTRIBUTE:
12072
106k
            first = NULL;
12073
106k
      last = NULL;
12074
106k
            next = xmlXPathNextAttribute;
12075
106k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12076
106k
            break;
12077
1.04M
        case AXIS_CHILD:
12078
1.04M
      last = NULL;
12079
1.04M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12080
1.04M
    (type == NODE_TYPE_NODE))
12081
1.03M
      {
12082
    /*
12083
    * Optimization if an element node type is 'element'.
12084
    */
12085
1.03M
    next = xmlXPathNextChildElement;
12086
1.03M
      } else
12087
17.0k
    next = xmlXPathNextChild;
12088
1.04M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12089
1.04M
            break;
12090
159k
        case AXIS_DESCENDANT:
12091
159k
      last = NULL;
12092
159k
            next = xmlXPathNextDescendant;
12093
159k
            break;
12094
73.3k
        case AXIS_DESCENDANT_OR_SELF:
12095
73.3k
      last = NULL;
12096
73.3k
            next = xmlXPathNextDescendantOrSelf;
12097
73.3k
            break;
12098
1.95k
        case AXIS_FOLLOWING:
12099
1.95k
      last = NULL;
12100
1.95k
            next = xmlXPathNextFollowing;
12101
1.95k
            break;
12102
1.15k
        case AXIS_FOLLOWING_SIBLING:
12103
1.15k
      last = NULL;
12104
1.15k
            next = xmlXPathNextFollowingSibling;
12105
1.15k
            break;
12106
2.98k
        case AXIS_NAMESPACE:
12107
2.98k
            first = NULL;
12108
2.98k
      last = NULL;
12109
2.98k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12110
2.98k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12111
2.98k
            break;
12112
17.4k
        case AXIS_PARENT:
12113
17.4k
            first = NULL;
12114
17.4k
            next = xmlXPathNextParent;
12115
17.4k
            break;
12116
1.70k
        case AXIS_PRECEDING:
12117
1.70k
            first = NULL;
12118
1.70k
            next = xmlXPathNextPrecedingInternal;
12119
1.70k
            break;
12120
1.18k
        case AXIS_PRECEDING_SIBLING:
12121
1.18k
            first = NULL;
12122
1.18k
            next = xmlXPathNextPrecedingSibling;
12123
1.18k
            break;
12124
1.82k
        case AXIS_SELF:
12125
1.82k
            first = NULL;
12126
1.82k
      last = NULL;
12127
1.82k
            next = xmlXPathNextSelf;
12128
1.82k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12129
1.82k
            break;
12130
1.42M
    }
12131
12132
#ifdef DEBUG_STEP
12133
    xmlXPathDebugDumpStepAxis(op,
12134
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12135
#endif
12136
12137
1.42M
    if (next == NULL) {
12138
0
  xmlXPathReleaseObject(xpctxt, obj);
12139
0
        return(0);
12140
0
    }
12141
1.42M
    contextSeq = obj->nodesetval;
12142
1.42M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12143
227k
  xmlXPathReleaseObject(xpctxt, obj);
12144
227k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12145
227k
        return(0);
12146
227k
    }
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
1.19M
    maxPos = 0;
12166
1.19M
    predOp = NULL;
12167
1.19M
    hasPredicateRange = 0;
12168
1.19M
    hasAxisRange = 0;
12169
1.19M
    if (op->ch2 != -1) {
12170
  /*
12171
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12172
  */
12173
51.7k
  predOp = &ctxt->comp->steps[op->ch2];
12174
51.7k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12175
21.8k
      if (predOp->ch1 != -1) {
12176
    /*
12177
    * Use the next inner predicate operator.
12178
    */
12179
6.69k
    predOp = &ctxt->comp->steps[predOp->ch1];
12180
6.69k
    hasPredicateRange = 1;
12181
15.1k
      } else {
12182
    /*
12183
    * There's no other predicate than the [n] predicate.
12184
    */
12185
15.1k
    predOp = NULL;
12186
15.1k
    hasAxisRange = 1;
12187
15.1k
      }
12188
21.8k
  }
12189
51.7k
    }
12190
1.19M
    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
1.19M
    oldContextNode = xpctxt->node;
12205
1.19M
    addNode = xmlXPathNodeSetAddUnique;
12206
1.19M
    outSeq = NULL;
12207
1.19M
    seq = NULL;
12208
1.19M
    contextNode = NULL;
12209
1.19M
    contextIdx = 0;
12210
12211
12212
4.37M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12213
4.37M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12214
3.23M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12215
12216
3.23M
  if (seq == NULL) {
12217
1.24M
      seq = xmlXPathNodeSetCreate(NULL);
12218
1.24M
      if (seq == NULL) {
12219
                /* TODO: Propagate memory error. */
12220
0
    total = 0;
12221
0
    goto error;
12222
0
      }
12223
1.24M
  }
12224
  /*
12225
  * Traverse the axis and test the nodes.
12226
  */
12227
3.23M
  pos = 0;
12228
3.23M
  cur = NULL;
12229
3.23M
  hasNsNodes = 0;
12230
13.6M
        do {
12231
13.6M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12232
0
                goto error;
12233
12234
13.6M
            cur = next(ctxt, cur);
12235
13.6M
            if (cur == NULL)
12236
3.16M
                break;
12237
12238
      /*
12239
      * QUESTION TODO: What does the "first" and "last" stuff do?
12240
      */
12241
10.4M
            if ((first != NULL) && (*first != NULL)) {
12242
2.58k
    if (*first == cur)
12243
457
        break;
12244
2.12k
    if (((total % 256) == 0) &&
12245
2.12k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12246
2.12k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12247
#else
12248
        (xmlXPathCmpNodes(*first, cur) >= 0))
12249
#endif
12250
1.13k
    {
12251
1.13k
        break;
12252
1.13k
    }
12253
2.12k
      }
12254
10.4M
      if ((last != NULL) && (*last != NULL)) {
12255
221
    if (*last == cur)
12256
35
        break;
12257
186
    if (((total % 256) == 0) &&
12258
186
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12259
186
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12260
#else
12261
        (xmlXPathCmpNodes(cur, *last) >= 0))
12262
#endif
12263
56
    {
12264
56
        break;
12265
56
    }
12266
186
      }
12267
12268
10.4M
            total++;
12269
12270
#ifdef DEBUG_STEP
12271
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12272
#endif
12273
12274
10.4M
      switch (test) {
12275
0
                case NODE_TEST_NONE:
12276
0
        total = 0;
12277
0
                    STRANGE
12278
0
        goto error;
12279
3.41M
                case NODE_TEST_TYPE:
12280
3.41M
        if (type == NODE_TYPE_NODE) {
12281
3.09M
      switch (cur->type) {
12282
64.9k
          case XML_DOCUMENT_NODE:
12283
64.9k
          case XML_HTML_DOCUMENT_NODE:
12284
1.12M
          case XML_ELEMENT_NODE:
12285
1.13M
          case XML_ATTRIBUTE_NODE:
12286
1.26M
          case XML_PI_NODE:
12287
1.40M
          case XML_COMMENT_NODE:
12288
1.48M
          case XML_CDATA_SECTION_NODE:
12289
3.09M
          case XML_TEXT_NODE:
12290
3.09M
        XP_TEST_HIT
12291
3.09M
        break;
12292
3.09M
          case XML_NAMESPACE_DECL: {
12293
913
        if (axis == AXIS_NAMESPACE) {
12294
135
            XP_TEST_HIT_NS
12295
778
        } else {
12296
778
                              hasNsNodes = 1;
12297
778
            XP_TEST_HIT
12298
778
        }
12299
913
        break;
12300
913
                            }
12301
913
          default:
12302
0
        break;
12303
3.09M
      }
12304
3.09M
        } else if (cur->type == (xmlElementType) type) {
12305
133k
      if (cur->type == XML_NAMESPACE_DECL)
12306
0
          XP_TEST_HIT_NS
12307
133k
      else
12308
133k
          XP_TEST_HIT
12309
189k
        } else if ((type == NODE_TYPE_TEXT) &&
12310
189k
       (cur->type == XML_CDATA_SECTION_NODE))
12311
6.34k
        {
12312
6.34k
      XP_TEST_HIT
12313
6.34k
        }
12314
3.41M
        break;
12315
3.41M
                case NODE_TEST_PI:
12316
1.25k
                    if ((cur->type == XML_PI_NODE) &&
12317
1.25k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12318
0
        {
12319
0
      XP_TEST_HIT
12320
0
                    }
12321
1.25k
                    break;
12322
3.13M
                case NODE_TEST_ALL:
12323
3.13M
                    if (axis == AXIS_ATTRIBUTE) {
12324
78.8k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12325
78.8k
      {
12326
78.8k
                            if (prefix == NULL)
12327
77.3k
          {
12328
77.3k
        XP_TEST_HIT
12329
77.3k
                            } else if ((cur->ns != NULL) &&
12330
1.44k
        (xmlStrEqual(URI, cur->ns->href)))
12331
0
          {
12332
0
        XP_TEST_HIT
12333
0
                            }
12334
78.8k
                        }
12335
3.05M
                    } else if (axis == AXIS_NAMESPACE) {
12336
19.1k
                        if (cur->type == XML_NAMESPACE_DECL)
12337
19.1k
      {
12338
19.1k
          XP_TEST_HIT_NS
12339
19.1k
                        }
12340
3.03M
                    } else {
12341
3.03M
                        if (cur->type == XML_ELEMENT_NODE) {
12342
1.31M
                            if (prefix == NULL)
12343
1.18M
          {
12344
1.18M
        XP_TEST_HIT
12345
12346
1.18M
                            } else if ((cur->ns != NULL) &&
12347
131k
        (xmlStrEqual(URI, cur->ns->href)))
12348
41.3k
          {
12349
41.3k
        XP_TEST_HIT
12350
41.3k
                            }
12351
1.31M
                        }
12352
3.03M
                    }
12353
3.08M
                    break;
12354
3.08M
                case NODE_TEST_NS:{
12355
0
                        TODO;
12356
0
                        break;
12357
3.13M
                    }
12358
3.88M
                case NODE_TEST_NAME:
12359
3.88M
                    if (axis == AXIS_ATTRIBUTE) {
12360
59.5k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12361
0
          break;
12362
3.82M
        } else if (axis == AXIS_NAMESPACE) {
12363
25.0k
                        if (cur->type != XML_NAMESPACE_DECL)
12364
0
          break;
12365
3.80M
        } else {
12366
3.80M
            if (cur->type != XML_ELEMENT_NODE)
12367
2.19M
          break;
12368
3.80M
        }
12369
1.69M
                    switch (cur->type) {
12370
1.60M
                        case XML_ELEMENT_NODE:
12371
1.60M
                            if (xmlStrEqual(name, cur->name)) {
12372
145k
                                if (prefix == NULL) {
12373
130k
                                    if (cur->ns == NULL)
12374
85.3k
            {
12375
85.3k
          XP_TEST_HIT
12376
85.3k
                                    }
12377
130k
                                } else {
12378
14.4k
                                    if ((cur->ns != NULL) &&
12379
14.4k
                                        (xmlStrEqual(URI, cur->ns->href)))
12380
4.38k
            {
12381
4.38k
          XP_TEST_HIT
12382
4.38k
                                    }
12383
14.4k
                                }
12384
145k
                            }
12385
1.60M
                            break;
12386
1.60M
                        case XML_ATTRIBUTE_NODE:{
12387
59.5k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389
59.5k
                                if (xmlStrEqual(name, attr->name)) {
12390
12.5k
                                    if (prefix == NULL) {
12391
12.1k
                                        if ((attr->ns == NULL) ||
12392
12.1k
                                            (attr->ns->prefix == NULL))
12393
12.1k
          {
12394
12.1k
              XP_TEST_HIT
12395
12.1k
                                        }
12396
12.1k
                                    } else {
12397
445
                                        if ((attr->ns != NULL) &&
12398
445
                                            (xmlStrEqual(URI,
12399
0
                attr->ns->href)))
12400
0
          {
12401
0
              XP_TEST_HIT
12402
0
                                        }
12403
445
                                    }
12404
12.5k
                                }
12405
58.8k
                                break;
12406
59.5k
                            }
12407
58.8k
                        case XML_NAMESPACE_DECL:
12408
25.0k
                            if (cur->type == XML_NAMESPACE_DECL) {
12409
25.0k
                                xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411
25.0k
                                if ((ns->prefix != NULL) && (name != NULL)
12412
25.0k
                                    && (xmlStrEqual(ns->prefix, name)))
12413
3.91k
        {
12414
3.91k
            XP_TEST_HIT_NS
12415
3.91k
                                }
12416
25.0k
                            }
12417
25.0k
                            break;
12418
25.0k
                        default:
12419
0
                            break;
12420
1.69M
                    }
12421
1.68M
                    break;
12422
10.4M
      } /* switch(test) */
12423
10.4M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12424
12425
3.17M
  goto apply_predicates;
12426
12427
3.17M
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
16.9k
  if (outSeq == NULL) {
12435
9.33k
      outSeq = seq;
12436
9.33k
      seq = NULL;
12437
9.33k
  } else
12438
            /* TODO: Check memory error. */
12439
7.62k
      outSeq = mergeAndClear(outSeq, seq);
12440
  /*
12441
  * Break if only a true/false result was requested.
12442
  */
12443
16.9k
  if (toBool)
12444
895
      break;
12445
16.0k
  continue;
12446
12447
43.0k
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
43.0k
  if (outSeq == NULL) {
12453
43.0k
      outSeq = seq;
12454
43.0k
      seq = NULL;
12455
43.0k
  } else
12456
            /* TODO: Check memory error. */
12457
0
      outSeq = mergeAndClear(outSeq, seq);
12458
43.0k
  break;
12459
12460
#ifdef DEBUG_STEP
12461
  if (seq != NULL)
12462
      nbMatches += seq->nodeNr;
12463
#endif
12464
12465
3.17M
apply_predicates: /* --------------------------------------------------- */
12466
3.17M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12467
0
      goto error;
12468
12469
        /*
12470
  * Apply predicates.
12471
  */
12472
3.17M
        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
83.2k
      if (hasPredicateRange != 0)
12502
20.7k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12503
20.7k
              hasNsNodes);
12504
62.4k
      else
12505
62.4k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12506
62.4k
              hasNsNodes);
12507
12508
83.2k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12509
1.58k
    total = 0;
12510
1.58k
    goto error;
12511
1.58k
      }
12512
83.2k
        }
12513
12514
3.16M
        if (seq->nodeNr > 0) {
12515
      /*
12516
      * Add to result set.
12517
      */
12518
789k
      if (outSeq == NULL) {
12519
395k
    outSeq = seq;
12520
395k
    seq = NULL;
12521
395k
      } else {
12522
                /* TODO: Check memory error. */
12523
394k
    outSeq = mergeAndClear(outSeq, seq);
12524
394k
      }
12525
12526
789k
            if (toBool)
12527
795
                break;
12528
789k
  }
12529
3.16M
    }
12530
12531
1.19M
error:
12532
1.19M
    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
1.19M
    xmlXPathReleaseObject(xpctxt, obj);
12544
12545
    /*
12546
    * Ensure we return at least an empty set.
12547
    */
12548
1.19M
    if (outSeq == NULL) {
12549
745k
  if ((seq != NULL) && (seq->nodeNr == 0))
12550
745k
      outSeq = seq;
12551
1
  else
12552
            /* TODO: Check memory error. */
12553
1
      outSeq = xmlXPathNodeSetCreate(NULL);
12554
745k
    }
12555
1.19M
    if ((seq != NULL) && (seq != outSeq)) {
12556
54.9k
   xmlXPathFreeNodeSet(seq);
12557
54.9k
    }
12558
    /*
12559
    * Hand over the result. Better to push the set also in
12560
    * case of errors.
12561
    */
12562
1.19M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563
    /*
12564
    * Reset the context node.
12565
    */
12566
1.19M
    xpctxt->node = oldContextNode;
12567
    /*
12568
    * When traversing the namespace axis in "toBool" mode, it's
12569
    * possible that tmpNsList wasn't freed.
12570
    */
12571
1.19M
    if (xpctxt->tmpNsList != NULL) {
12572
49
        xmlFree(xpctxt->tmpNsList);
12573
49
        xpctxt->tmpNsList = NULL;
12574
49
    }
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
1.19M
    return(total);
12583
1.19M
}
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
23.9k
{
12604
23.9k
    int total = 0, cur;
12605
23.9k
    xmlXPathCompExprPtr comp;
12606
23.9k
    xmlXPathObjectPtr arg1, arg2;
12607
12608
23.9k
    CHECK_ERROR0;
12609
23.9k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12610
0
        return(0);
12611
23.9k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12612
23.9k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12613
23.9k
    ctxt->context->depth += 1;
12614
23.9k
    comp = ctxt->comp;
12615
23.9k
    switch (op->op) {
12616
0
        case XPATH_OP_END:
12617
0
            break;
12618
3.83k
        case XPATH_OP_UNION:
12619
3.83k
            total =
12620
3.83k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12621
3.83k
                                        first);
12622
3.83k
      CHECK_ERROR0;
12623
3.43k
            if ((ctxt->value != NULL)
12624
3.43k
                && (ctxt->value->type == XPATH_NODESET)
12625
3.43k
                && (ctxt->value->nodesetval != NULL)
12626
3.43k
                && (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
1.87k
    if (ctxt->value->nodesetval->nodeNr > 1)
12638
554
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12639
1.87k
                *first = ctxt->value->nodesetval->nodeTab[0];
12640
1.87k
            }
12641
3.43k
            cur =
12642
3.43k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12643
3.43k
                                        first);
12644
3.43k
      CHECK_ERROR0;
12645
12646
3.32k
            arg2 = valuePop(ctxt);
12647
3.32k
            arg1 = valuePop(ctxt);
12648
3.32k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12649
3.32k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12650
49
          xmlXPathReleaseObject(ctxt->context, arg1);
12651
49
          xmlXPathReleaseObject(ctxt->context, arg2);
12652
49
                XP_ERROR0(XPATH_INVALID_TYPE);
12653
0
            }
12654
3.27k
            if ((ctxt->context->opLimit != 0) &&
12655
3.27k
                (((arg1->nodesetval != NULL) &&
12656
3.27k
                  (xmlXPathCheckOpLimit(ctxt,
12657
3.01k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12658
3.27k
                 ((arg2->nodesetval != NULL) &&
12659
3.27k
                  (xmlXPathCheckOpLimit(ctxt,
12660
2.66k
                                        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
3.27k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668
3.27k
                                                    arg2->nodesetval);
12669
3.27k
            valuePush(ctxt, arg1);
12670
3.27k
      xmlXPathReleaseObject(ctxt->context, arg2);
12671
            /* optimizer */
12672
3.27k
      if (total > cur)
12673
2.37k
    xmlXPathCompSwap(op);
12674
3.27k
            total += cur;
12675
3.27k
            break;
12676
528
        case XPATH_OP_ROOT:
12677
528
            xmlXPathRoot(ctxt);
12678
528
            break;
12679
232
        case XPATH_OP_NODE:
12680
232
            if (op->ch1 != -1)
12681
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12682
232
      CHECK_ERROR0;
12683
232
            if (op->ch2 != -1)
12684
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12685
232
      CHECK_ERROR0;
12686
232
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12687
232
    ctxt->context->node));
12688
232
            break;
12689
8.76k
        case XPATH_OP_COLLECT:{
12690
8.76k
                if (op->ch1 == -1)
12691
0
                    break;
12692
12693
8.76k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12694
8.76k
    CHECK_ERROR0;
12695
12696
8.58k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12697
8.58k
                break;
12698
8.76k
            }
12699
55
        case XPATH_OP_VALUE:
12700
55
            valuePush(ctxt,
12701
55
                      xmlXPathCacheObjectCopy(ctxt->context,
12702
55
      (xmlXPathObjectPtr) op->value4));
12703
55
            break;
12704
7.04k
        case XPATH_OP_SORT:
12705
7.04k
            if (op->ch1 != -1)
12706
7.04k
                total +=
12707
7.04k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12708
7.04k
                                            first);
12709
7.04k
      CHECK_ERROR0;
12710
6.21k
            if ((ctxt->value != NULL)
12711
6.21k
                && (ctxt->value->type == XPATH_NODESET)
12712
6.21k
                && (ctxt->value->nodesetval != NULL)
12713
6.21k
    && (ctxt->value->nodesetval->nodeNr > 1))
12714
1.72k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12715
6.21k
            break;
12716
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12717
2.76k
  case XPATH_OP_FILTER:
12718
2.76k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12719
2.76k
            break;
12720
0
#endif
12721
712
        default:
12722
712
            total += xmlXPathCompOpEval(ctxt, op);
12723
712
            break;
12724
23.9k
    }
12725
12726
22.3k
    ctxt->context->depth -= 1;
12727
22.3k
    return(total);
12728
23.9k
}
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
2.41k
{
12745
2.41k
    int total = 0, cur;
12746
2.41k
    xmlXPathCompExprPtr comp;
12747
2.41k
    xmlXPathObjectPtr arg1, arg2;
12748
12749
2.41k
    CHECK_ERROR0;
12750
2.41k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12751
0
        return(0);
12752
2.41k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12753
2.41k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12754
2.41k
    ctxt->context->depth += 1;
12755
2.41k
    comp = ctxt->comp;
12756
2.41k
    switch (op->op) {
12757
0
        case XPATH_OP_END:
12758
0
            break;
12759
776
        case XPATH_OP_UNION:
12760
776
            total =
12761
776
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12762
776
      CHECK_ERROR0;
12763
675
            if ((ctxt->value != NULL)
12764
675
                && (ctxt->value->type == XPATH_NODESET)
12765
675
                && (ctxt->value->nodesetval != NULL)
12766
675
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767
                /*
12768
                 * limit tree traversing to first node in the result
12769
                 */
12770
422
    if (ctxt->value->nodesetval->nodeNr > 1)
12771
152
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12772
422
                *last =
12773
422
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12774
422
                                                     nodesetval->nodeNr -
12775
422
                                                     1];
12776
422
            }
12777
675
            cur =
12778
675
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12779
675
      CHECK_ERROR0;
12780
657
            if ((ctxt->value != NULL)
12781
657
                && (ctxt->value->type == XPATH_NODESET)
12782
657
                && (ctxt->value->nodesetval != NULL)
12783
657
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12784
202
            }
12785
12786
657
            arg2 = valuePop(ctxt);
12787
657
            arg1 = valuePop(ctxt);
12788
657
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12789
657
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12790
16
          xmlXPathReleaseObject(ctxt->context, arg1);
12791
16
          xmlXPathReleaseObject(ctxt->context, arg2);
12792
16
                XP_ERROR0(XPATH_INVALID_TYPE);
12793
0
            }
12794
641
            if ((ctxt->context->opLimit != 0) &&
12795
641
                (((arg1->nodesetval != NULL) &&
12796
641
                  (xmlXPathCheckOpLimit(ctxt,
12797
604
                                        arg1->nodesetval->nodeNr) < 0)) ||
12798
641
                 ((arg2->nodesetval != NULL) &&
12799
641
                  (xmlXPathCheckOpLimit(ctxt,
12800
487
                                        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
641
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12808
641
                                                    arg2->nodesetval);
12809
641
            valuePush(ctxt, arg1);
12810
641
      xmlXPathReleaseObject(ctxt->context, arg2);
12811
            /* optimizer */
12812
641
      if (total > cur)
12813
462
    xmlXPathCompSwap(op);
12814
641
            total += cur;
12815
641
            break;
12816
71
        case XPATH_OP_ROOT:
12817
71
            xmlXPathRoot(ctxt);
12818
71
            break;
12819
66
        case XPATH_OP_NODE:
12820
66
            if (op->ch1 != -1)
12821
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822
66
      CHECK_ERROR0;
12823
66
            if (op->ch2 != -1)
12824
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12825
66
      CHECK_ERROR0;
12826
66
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12827
66
    ctxt->context->node));
12828
66
            break;
12829
897
        case XPATH_OP_COLLECT:{
12830
897
                if (op->ch1 == -1)
12831
0
                    break;
12832
12833
897
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12834
897
    CHECK_ERROR0;
12835
12836
880
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12837
880
                break;
12838
897
            }
12839
20
        case XPATH_OP_VALUE:
12840
20
            valuePush(ctxt,
12841
20
                      xmlXPathCacheObjectCopy(ctxt->context,
12842
20
      (xmlXPathObjectPtr) op->value4));
12843
20
            break;
12844
492
        case XPATH_OP_SORT:
12845
492
            if (op->ch1 != -1)
12846
492
                total +=
12847
492
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12848
492
                                           last);
12849
492
      CHECK_ERROR0;
12850
404
            if ((ctxt->value != NULL)
12851
404
                && (ctxt->value->type == XPATH_NODESET)
12852
404
                && (ctxt->value->nodesetval != NULL)
12853
404
    && (ctxt->value->nodesetval->nodeNr > 1))
12854
60
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12855
404
            break;
12856
93
        default:
12857
93
            total += xmlXPathCompOpEval(ctxt, op);
12858
93
            break;
12859
2.41k
    }
12860
12861
2.17k
    ctxt->context->depth -= 1;
12862
2.17k
    return (total);
12863
2.41k
}
12864
12865
#ifdef XP_OPTIMIZED_FILTER_FIRST
12866
static int
12867
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12868
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12869
2.76k
{
12870
2.76k
    int total = 0;
12871
2.76k
    xmlXPathCompExprPtr comp;
12872
2.76k
    xmlNodeSetPtr set;
12873
12874
2.76k
    CHECK_ERROR0;
12875
2.76k
    comp = ctxt->comp;
12876
    /*
12877
    * Optimization for ()[last()] selection i.e. the last elem
12878
    */
12879
2.76k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12880
2.76k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12881
2.76k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12882
423
  int f = comp->steps[op->ch2].ch1;
12883
12884
423
  if ((f != -1) &&
12885
423
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12886
423
      (comp->steps[f].value5 == NULL) &&
12887
423
      (comp->steps[f].value == 0) &&
12888
423
      (comp->steps[f].value4 != NULL) &&
12889
423
      (xmlStrEqual
12890
37
      (comp->steps[f].value4, BAD_CAST "last"))) {
12891
28
      xmlNodePtr last = NULL;
12892
12893
28
      total +=
12894
28
    xmlXPathCompOpEvalLast(ctxt,
12895
28
        &comp->steps[op->ch1],
12896
28
        &last);
12897
28
      CHECK_ERROR0;
12898
      /*
12899
      * The nodeset should be in document order,
12900
      * Keep only the last value
12901
      */
12902
22
      if ((ctxt->value != NULL) &&
12903
22
    (ctxt->value->type == XPATH_NODESET) &&
12904
22
    (ctxt->value->nodesetval != NULL) &&
12905
22
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12906
22
    (ctxt->value->nodesetval->nodeNr > 1)) {
12907
6
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12908
6
    *first = *(ctxt->value->nodesetval->nodeTab);
12909
6
      }
12910
22
      return (total);
12911
28
  }
12912
423
    }
12913
12914
2.74k
    if (op->ch1 != -1)
12915
2.74k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12916
2.74k
    CHECK_ERROR0;
12917
2.02k
    if (op->ch2 == -1)
12918
0
  return (total);
12919
2.02k
    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
2.02k
    CHECK_TYPE0(XPATH_NODESET);
12940
1.63k
    set = ctxt->value->nodesetval;
12941
1.63k
    if (set != NULL) {
12942
1.35k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12943
1.35k
        if (set->nodeNr > 0)
12944
503
            *first = set->nodeTab[0];
12945
1.35k
    }
12946
12947
1.63k
    return (total);
12948
2.02k
}
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
6.00M
{
12962
6.00M
    int total = 0;
12963
6.00M
    int equal, ret;
12964
6.00M
    xmlXPathCompExprPtr comp;
12965
6.00M
    xmlXPathObjectPtr arg1, arg2;
12966
12967
6.00M
    CHECK_ERROR0;
12968
6.00M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12969
0
        return(0);
12970
6.00M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12971
6.00M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12972
6.00M
    ctxt->context->depth += 1;
12973
6.00M
    comp = ctxt->comp;
12974
6.00M
    switch (op->op) {
12975
0
        case XPATH_OP_END:
12976
0
            break;
12977
14.6k
        case XPATH_OP_AND:
12978
14.6k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12979
14.6k
      CHECK_ERROR0;
12980
11.6k
            xmlXPathBooleanFunction(ctxt, 1);
12981
11.6k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12982
7.29k
                break;
12983
4.38k
            arg2 = valuePop(ctxt);
12984
4.38k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12985
4.38k
      if (ctxt->error) {
12986
535
    xmlXPathFreeObject(arg2);
12987
535
    break;
12988
535
      }
12989
3.85k
            xmlXPathBooleanFunction(ctxt, 1);
12990
3.85k
            if (ctxt->value != NULL)
12991
3.85k
                ctxt->value->boolval &= arg2->boolval;
12992
3.85k
      xmlXPathReleaseObject(ctxt->context, arg2);
12993
3.85k
            break;
12994
24.0k
        case XPATH_OP_OR:
12995
24.0k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996
24.0k
      CHECK_ERROR0;
12997
20.4k
            xmlXPathBooleanFunction(ctxt, 1);
12998
20.4k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12999
6.04k
                break;
13000
14.3k
            arg2 = valuePop(ctxt);
13001
14.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13002
14.3k
      if (ctxt->error) {
13003
1.20k
    xmlXPathFreeObject(arg2);
13004
1.20k
    break;
13005
1.20k
      }
13006
13.1k
            xmlXPathBooleanFunction(ctxt, 1);
13007
13.1k
            if (ctxt->value != NULL)
13008
13.1k
                ctxt->value->boolval |= arg2->boolval;
13009
13.1k
      xmlXPathReleaseObject(ctxt->context, arg2);
13010
13.1k
            break;
13011
173k
        case XPATH_OP_EQUAL:
13012
173k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013
173k
      CHECK_ERROR0;
13014
163k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13015
163k
      CHECK_ERROR0;
13016
154k
      if (op->value)
13017
130k
    equal = xmlXPathEqualValues(ctxt);
13018
24.7k
      else
13019
24.7k
    equal = xmlXPathNotEqualValues(ctxt);
13020
154k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13021
154k
            break;
13022
171k
        case XPATH_OP_CMP:
13023
171k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
171k
      CHECK_ERROR0;
13025
160k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13026
160k
      CHECK_ERROR0;
13027
156k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13028
156k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13029
156k
            break;
13030
208k
        case XPATH_OP_PLUS:
13031
208k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13032
208k
      CHECK_ERROR0;
13033
197k
            if (op->ch2 != -1) {
13034
114k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13035
114k
      }
13036
197k
      CHECK_ERROR0;
13037
192k
            if (op->value == 0)
13038
75.0k
                xmlXPathSubValues(ctxt);
13039
117k
            else if (op->value == 1)
13040
34.7k
                xmlXPathAddValues(ctxt);
13041
82.3k
            else if (op->value == 2)
13042
64.3k
                xmlXPathValueFlipSign(ctxt);
13043
17.9k
            else if (op->value == 3) {
13044
17.9k
                CAST_TO_NUMBER;
13045
17.9k
                CHECK_TYPE0(XPATH_NUMBER);
13046
17.9k
            }
13047
192k
            break;
13048
279k
        case XPATH_OP_MULT:
13049
279k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13050
279k
      CHECK_ERROR0;
13051
260k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13052
260k
      CHECK_ERROR0;
13053
255k
            if (op->value == 0)
13054
238k
                xmlXPathMultValues(ctxt);
13055
17.4k
            else if (op->value == 1)
13056
7.82k
                xmlXPathDivValues(ctxt);
13057
9.66k
            else if (op->value == 2)
13058
9.66k
                xmlXPathModValues(ctxt);
13059
255k
            break;
13060
149k
        case XPATH_OP_UNION:
13061
149k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13062
149k
      CHECK_ERROR0;
13063
139k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13064
139k
      CHECK_ERROR0;
13065
13066
135k
            arg2 = valuePop(ctxt);
13067
135k
            arg1 = valuePop(ctxt);
13068
135k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13069
135k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13070
3.56k
          xmlXPathReleaseObject(ctxt->context, arg1);
13071
3.56k
          xmlXPathReleaseObject(ctxt->context, arg2);
13072
3.56k
                XP_ERROR0(XPATH_INVALID_TYPE);
13073
0
            }
13074
132k
            if ((ctxt->context->opLimit != 0) &&
13075
132k
                (((arg1->nodesetval != NULL) &&
13076
132k
                  (xmlXPathCheckOpLimit(ctxt,
13077
111k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13078
132k
                 ((arg2->nodesetval != NULL) &&
13079
132k
                  (xmlXPathCheckOpLimit(ctxt,
13080
103k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13081
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13082
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13083
0
                break;
13084
0
            }
13085
13086
132k
      if ((arg1->nodesetval == NULL) ||
13087
132k
    ((arg2->nodesetval != NULL) &&
13088
111k
     (arg2->nodesetval->nodeNr != 0)))
13089
60.1k
      {
13090
                /* TODO: Check memory error. */
13091
60.1k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13092
60.1k
              arg2->nodesetval);
13093
60.1k
      }
13094
13095
132k
            valuePush(ctxt, arg1);
13096
132k
      xmlXPathReleaseObject(ctxt->context, arg2);
13097
132k
            break;
13098
297k
        case XPATH_OP_ROOT:
13099
297k
            xmlXPathRoot(ctxt);
13100
297k
            break;
13101
897k
        case XPATH_OP_NODE:
13102
897k
            if (op->ch1 != -1)
13103
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104
897k
      CHECK_ERROR0;
13105
897k
            if (op->ch2 != -1)
13106
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13107
897k
      CHECK_ERROR0;
13108
897k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13109
897k
    ctxt->context->node));
13110
897k
            break;
13111
1.34M
        case XPATH_OP_COLLECT:{
13112
1.34M
                if (op->ch1 == -1)
13113
0
                    break;
13114
13115
1.34M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13116
1.34M
    CHECK_ERROR0;
13117
13118
1.32M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13119
1.32M
                break;
13120
1.34M
            }
13121
631k
        case XPATH_OP_VALUE:
13122
631k
            valuePush(ctxt,
13123
631k
                      xmlXPathCacheObjectCopy(ctxt->context,
13124
631k
      (xmlXPathObjectPtr) op->value4));
13125
631k
            break;
13126
9.67k
        case XPATH_OP_VARIABLE:{
13127
9.67k
    xmlXPathObjectPtr val;
13128
13129
9.67k
                if (op->ch1 != -1)
13130
0
                    total +=
13131
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13132
9.67k
                if (op->value5 == NULL) {
13133
7.62k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13134
7.62k
        if (val == NULL)
13135
7.62k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13136
0
                    valuePush(ctxt, val);
13137
2.04k
    } else {
13138
2.04k
                    const xmlChar *URI;
13139
13140
2.04k
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13141
2.04k
                    if (URI == NULL) {
13142
1.38k
                        xmlGenericError(xmlGenericErrorContext,
13143
1.38k
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13144
1.38k
                                    (char *) op->value4, (char *)op->value5);
13145
1.38k
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13146
1.38k
                        break;
13147
1.38k
                    }
13148
660
        val = xmlXPathVariableLookupNS(ctxt->context,
13149
660
                                                       op->value4, URI);
13150
660
        if (val == NULL)
13151
660
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13152
0
                    valuePush(ctxt, val);
13153
0
                }
13154
0
                break;
13155
9.67k
            }
13156
404k
        case XPATH_OP_FUNCTION:{
13157
404k
                xmlXPathFunction func;
13158
404k
                const xmlChar *oldFunc, *oldFuncURI;
13159
404k
    int i;
13160
404k
                int frame;
13161
13162
404k
                frame = xmlXPathSetFrame(ctxt);
13163
404k
                if (op->ch1 != -1) {
13164
355k
                    total +=
13165
355k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13166
355k
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13167
11.2k
                        xmlXPathPopFrame(ctxt, frame);
13168
11.2k
                        break;
13169
11.2k
                    }
13170
355k
                }
13171
393k
    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
925k
    for (i = 0; i < op->value; i++) {
13179
531k
        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
531k
                }
13187
393k
                if (op->cache != NULL)
13188
6.41k
                    func = op->cache;
13189
387k
                else {
13190
387k
                    const xmlChar *URI = NULL;
13191
13192
387k
                    if (op->value5 == NULL)
13193
151k
                        func =
13194
151k
                            xmlXPathFunctionLookup(ctxt->context,
13195
151k
                                                   op->value4);
13196
235k
                    else {
13197
235k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13198
235k
                        if (URI == NULL) {
13199
10.0k
                            xmlGenericError(xmlGenericErrorContext,
13200
10.0k
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13201
10.0k
                                    (char *)op->value4, (char *)op->value5);
13202
10.0k
                            xmlXPathPopFrame(ctxt, frame);
13203
10.0k
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13204
10.0k
                            break;
13205
10.0k
                        }
13206
225k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13207
225k
                                                        op->value4, URI);
13208
225k
                    }
13209
376k
                    if (func == NULL) {
13210
44.5k
                        xmlGenericError(xmlGenericErrorContext,
13211
44.5k
                                "xmlXPathCompOpEval: function %s not found\n",
13212
44.5k
                                        (char *)op->value4);
13213
44.5k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13214
0
                    }
13215
332k
                    op->cache = func;
13216
332k
                    op->cacheURI = (void *) URI;
13217
332k
                }
13218
338k
                oldFunc = ctxt->context->function;
13219
338k
                oldFuncURI = ctxt->context->functionURI;
13220
338k
                ctxt->context->function = op->value4;
13221
338k
                ctxt->context->functionURI = op->cacheURI;
13222
338k
                func(ctxt, op->value);
13223
338k
                ctxt->context->function = oldFunc;
13224
338k
                ctxt->context->functionURI = oldFuncURI;
13225
338k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13226
338k
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13227
336k
                    XP_ERROR0(XPATH_STACK_ERROR);
13228
336k
                xmlXPathPopFrame(ctxt, frame);
13229
336k
                break;
13230
338k
            }
13231
551k
        case XPATH_OP_ARG:
13232
551k
            if (op->ch1 != -1) {
13233
196k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13234
196k
          CHECK_ERROR0;
13235
196k
            }
13236
547k
            if (op->ch2 != -1) {
13237
547k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238
547k
          CHECK_ERROR0;
13239
547k
      }
13240
536k
            break;
13241
536k
        case XPATH_OP_PREDICATE:
13242
21.4k
        case XPATH_OP_FILTER:{
13243
21.4k
                xmlNodeSetPtr set;
13244
13245
                /*
13246
                 * Optimization for ()[1] selection i.e. the first elem
13247
                 */
13248
21.4k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13249
21.4k
#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
21.4k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13260
21.4k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13261
#else
13262
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13263
#endif
13264
21.4k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13265
13.1k
                    xmlXPathObjectPtr val;
13266
13267
13.1k
                    val = comp->steps[op->ch2].value4;
13268
13.1k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13269
13.1k
                        (val->floatval == 1.0)) {
13270
9.63k
                        xmlNodePtr first = NULL;
13271
13272
9.63k
                        total +=
13273
9.63k
                            xmlXPathCompOpEvalFirst(ctxt,
13274
9.63k
                                                    &comp->steps[op->ch1],
13275
9.63k
                                                    &first);
13276
9.63k
      CHECK_ERROR0;
13277
                        /*
13278
                         * The nodeset should be in document order,
13279
                         * Keep only the first value
13280
                         */
13281
7.73k
                        if ((ctxt->value != NULL) &&
13282
7.73k
                            (ctxt->value->type == XPATH_NODESET) &&
13283
7.73k
                            (ctxt->value->nodesetval != NULL) &&
13284
7.73k
                            (ctxt->value->nodesetval->nodeNr > 1))
13285
1.72k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13286
1.72k
                                                        1, 1);
13287
7.73k
                        break;
13288
9.63k
                    }
13289
13.1k
                }
13290
                /*
13291
                 * Optimization for ()[last()] selection i.e. the last elem
13292
                 */
13293
11.8k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13294
11.8k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13295
11.8k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13296
3.26k
                    int f = comp->steps[op->ch2].ch1;
13297
13298
3.26k
                    if ((f != -1) &&
13299
3.26k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13300
3.26k
                        (comp->steps[f].value5 == NULL) &&
13301
3.26k
                        (comp->steps[f].value == 0) &&
13302
3.26k
                        (comp->steps[f].value4 != NULL) &&
13303
3.26k
                        (xmlStrEqual
13304
562
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13305
444
                        xmlNodePtr last = NULL;
13306
13307
444
                        total +=
13308
444
                            xmlXPathCompOpEvalLast(ctxt,
13309
444
                                                   &comp->steps[op->ch1],
13310
444
                                                   &last);
13311
444
      CHECK_ERROR0;
13312
                        /*
13313
                         * The nodeset should be in document order,
13314
                         * Keep only the last value
13315
                         */
13316
366
                        if ((ctxt->value != NULL) &&
13317
366
                            (ctxt->value->type == XPATH_NODESET) &&
13318
366
                            (ctxt->value->nodesetval != NULL) &&
13319
366
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13320
366
                            (ctxt->value->nodesetval->nodeNr > 1))
13321
53
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13322
366
                        break;
13323
444
                    }
13324
3.26k
                }
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
11.3k
                if (op->ch1 != -1)
13337
11.3k
                    total +=
13338
11.3k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339
11.3k
    CHECK_ERROR0;
13340
8.22k
                if (op->ch2 == -1)
13341
0
                    break;
13342
8.22k
                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
8.22k
                CHECK_TYPE0(XPATH_NODESET);
13358
6.29k
                set = ctxt->value->nodesetval;
13359
6.29k
                if (set != NULL)
13360
5.54k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13361
5.54k
                                          1, set->nodeNr, 1);
13362
6.29k
                break;
13363
8.22k
            }
13364
821k
        case XPATH_OP_SORT:
13365
821k
            if (op->ch1 != -1)
13366
821k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367
821k
      CHECK_ERROR0;
13368
670k
            if ((ctxt->value != NULL) &&
13369
670k
                (ctxt->value->type == XPATH_NODESET) &&
13370
670k
                (ctxt->value->nodesetval != NULL) &&
13371
670k
    (ctxt->value->nodesetval->nodeNr > 1))
13372
90.1k
      {
13373
90.1k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13374
90.1k
      }
13375
670k
            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
6.00M
    }
13541
13542
5.65M
    ctxt->context->depth -= 1;
13543
5.65M
    return (total);
13544
6.00M
}
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
267k
{
13559
267k
    xmlXPathObjectPtr resObj = NULL;
13560
13561
282k
start:
13562
282k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13563
0
        return(0);
13564
    /* comp = ctxt->comp; */
13565
282k
    switch (op->op) {
13566
0
        case XPATH_OP_END:
13567
0
            return (0);
13568
25.5k
  case XPATH_OP_VALUE:
13569
25.5k
      resObj = (xmlXPathObjectPtr) op->value4;
13570
25.5k
      if (isPredicate)
13571
25.5k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13572
0
      return(xmlXPathCastToBoolean(resObj));
13573
14.9k
  case XPATH_OP_SORT:
13574
      /*
13575
      * We don't need sorting for boolean results. Skip this one.
13576
      */
13577
14.9k
            if (op->ch1 != -1) {
13578
14.9k
    op = &ctxt->comp->steps[op->ch1];
13579
14.9k
    goto start;
13580
14.9k
      }
13581
0
      return(0);
13582
112k
  case XPATH_OP_COLLECT:
13583
112k
      if (op->ch1 == -1)
13584
0
    return(0);
13585
13586
112k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13587
112k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13588
216
    return(-1);
13589
13590
112k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13591
112k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13592
547
    return(-1);
13593
13594
111k
      resObj = valuePop(ctxt);
13595
111k
      if (resObj == NULL)
13596
0
    return(-1);
13597
111k
      break;
13598
129k
  default:
13599
      /*
13600
      * Fallback to call xmlXPathCompOpEval().
13601
      */
13602
129k
      xmlXPathCompOpEval(ctxt, op);
13603
129k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13604
1.14k
    return(-1);
13605
13606
128k
      resObj = valuePop(ctxt);
13607
128k
      if (resObj == NULL)
13608
0
    return(-1);
13609
128k
      break;
13610
282k
    }
13611
13612
240k
    if (resObj) {
13613
240k
  int res;
13614
13615
240k
  if (resObj->type == XPATH_BOOLEAN) {
13616
64.7k
      res = resObj->boolval;
13617
175k
  } 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
175k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13627
175k
  } else {
13628
0
      res = xmlXPathCastToBoolean(resObj);
13629
0
  }
13630
240k
  xmlXPathReleaseObject(ctxt->context, resObj);
13631
240k
  return(res);
13632
240k
    }
13633
13634
0
    return(0);
13635
240k
}
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
86.0k
{
13648
86.0k
    int max_depth, min_depth;
13649
86.0k
    int from_root;
13650
86.0k
    int ret, depth;
13651
86.0k
    int eval_all_nodes;
13652
86.0k
    xmlNodePtr cur = NULL, limit = NULL;
13653
86.0k
    xmlStreamCtxtPtr patstream = NULL;
13654
13655
86.0k
    if ((ctxt == NULL) || (comp == NULL))
13656
0
        return(-1);
13657
86.0k
    max_depth = xmlPatternMaxDepth(comp);
13658
86.0k
    if (max_depth == -1)
13659
0
        return(-1);
13660
86.0k
    if (max_depth == -2)
13661
30.6k
        max_depth = 10000;
13662
86.0k
    min_depth = xmlPatternMinDepth(comp);
13663
86.0k
    if (min_depth == -1)
13664
0
        return(-1);
13665
86.0k
    from_root = xmlPatternFromRoot(comp);
13666
86.0k
    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
86.0k
    if (! toBool) {
13673
86.0k
  if (resultSeq == NULL)
13674
0
      return(-1);
13675
86.0k
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13676
86.0k
  if (*resultSeq == NULL)
13677
0
      return(-1);
13678
86.0k
    }
13679
13680
    /*
13681
     * handle the special cases of "/" amd "." being matched
13682
     */
13683
86.0k
    if (min_depth == 0) {
13684
14.3k
  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
14.3k
  } else {
13692
      /* Select "self::node()" */
13693
14.3k
      if (toBool)
13694
0
    return(1);
13695
            /* TODO: Check memory error. */
13696
14.3k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13697
14.3k
  }
13698
14.3k
    }
13699
86.0k
    if (max_depth == 0) {
13700
10.0k
  return(0);
13701
10.0k
    }
13702
13703
75.9k
    if (from_root) {
13704
28.2k
        cur = (xmlNodePtr)ctxt->doc;
13705
47.7k
    } else if (ctxt->node != NULL) {
13706
47.7k
        switch (ctxt->node->type) {
13707
7.43k
            case XML_ELEMENT_NODE:
13708
45.2k
            case XML_DOCUMENT_NODE:
13709
45.2k
            case XML_DOCUMENT_FRAG_NODE:
13710
45.2k
            case XML_HTML_DOCUMENT_NODE:
13711
45.2k
          cur = ctxt->node;
13712
45.2k
    break;
13713
0
            case XML_ATTRIBUTE_NODE:
13714
2.02k
            case XML_TEXT_NODE:
13715
2.11k
            case XML_CDATA_SECTION_NODE:
13716
2.11k
            case XML_ENTITY_REF_NODE:
13717
2.11k
            case XML_ENTITY_NODE:
13718
2.29k
            case XML_PI_NODE:
13719
2.48k
            case XML_COMMENT_NODE:
13720
2.48k
            case XML_NOTATION_NODE:
13721
2.48k
            case XML_DTD_NODE:
13722
2.48k
            case XML_DOCUMENT_TYPE_NODE:
13723
2.48k
            case XML_ELEMENT_DECL:
13724
2.48k
            case XML_ATTRIBUTE_DECL:
13725
2.48k
            case XML_ENTITY_DECL:
13726
2.48k
            case XML_NAMESPACE_DECL:
13727
2.48k
            case XML_XINCLUDE_START:
13728
2.48k
            case XML_XINCLUDE_END:
13729
2.48k
    break;
13730
47.7k
  }
13731
47.7k
  limit = cur;
13732
47.7k
    }
13733
75.9k
    if (cur == NULL) {
13734
2.48k
        return(0);
13735
2.48k
    }
13736
13737
73.5k
    patstream = xmlPatternGetStreamCtxt(comp);
13738
73.5k
    if (patstream == NULL) {
13739
  /*
13740
  * QUESTION TODO: Is this an error?
13741
  */
13742
0
  return(0);
13743
0
    }
13744
13745
73.5k
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746
13747
73.5k
    if (from_root) {
13748
28.2k
  ret = xmlStreamPush(patstream, NULL, NULL);
13749
28.2k
  if (ret < 0) {
13750
28.2k
  } else if (ret == 1) {
13751
1.63k
      if (toBool)
13752
0
    goto return_1;
13753
            /* TODO: Check memory error. */
13754
1.63k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755
1.63k
  }
13756
28.2k
    }
13757
73.5k
    depth = 0;
13758
73.5k
    goto scan_children;
13759
924k
next_node:
13760
1.60M
    do {
13761
1.60M
        if (ctxt->opLimit != 0) {
13762
1.60M
            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
1.60M
            ctxt->opCount++;
13769
1.60M
        }
13770
13771
1.60M
  switch (cur->type) {
13772
509k
      case XML_ELEMENT_NODE:
13773
1.37M
      case XML_TEXT_NODE:
13774
1.40M
      case XML_CDATA_SECTION_NODE:
13775
1.49M
      case XML_COMMENT_NODE:
13776
1.60M
      case XML_PI_NODE:
13777
1.60M
    if (cur->type == XML_ELEMENT_NODE) {
13778
509k
        ret = xmlStreamPush(patstream, cur->name,
13779
509k
        (cur->ns ? cur->ns->href : NULL));
13780
1.09M
    } else if (eval_all_nodes)
13781
182k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13782
908k
    else
13783
908k
        break;
13784
13785
692k
    if (ret < 0) {
13786
        /* NOP. */
13787
692k
    } else if (ret == 1) {
13788
157k
        if (toBool)
13789
0
      goto return_1;
13790
157k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13791
157k
            < 0) {
13792
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13793
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13794
0
        }
13795
157k
    }
13796
692k
    if ((cur->children == NULL) || (depth >= max_depth)) {
13797
367k
        ret = xmlStreamPop(patstream);
13798
367k
        while (cur->next != NULL) {
13799
287k
      cur = cur->next;
13800
287k
      if ((cur->type != XML_ENTITY_DECL) &&
13801
287k
          (cur->type != XML_DTD_NODE))
13802
287k
          goto next_node;
13803
287k
        }
13804
367k
    }
13805
404k
      default:
13806
404k
    break;
13807
1.60M
  }
13808
13809
1.38M
scan_children:
13810
1.38M
  if (cur->type == XML_NAMESPACE_DECL) break;
13811
1.38M
  if ((cur->children != NULL) && (depth < max_depth)) {
13812
      /*
13813
       * Do not descend on entities declarations
13814
       */
13815
395k
      if (cur->children->type != XML_ENTITY_DECL) {
13816
395k
    cur = cur->children;
13817
395k
    depth++;
13818
    /*
13819
     * Skip DTDs
13820
     */
13821
395k
    if (cur->type != XML_DTD_NODE)
13822
395k
        continue;
13823
395k
      }
13824
395k
  }
13825
13826
991k
  if (cur == limit)
13827
1.93k
      break;
13828
13829
989k
  while (cur->next != NULL) {
13830
637k
      cur = cur->next;
13831
637k
      if ((cur->type != XML_ENTITY_DECL) &&
13832
637k
    (cur->type != XML_DTD_NODE))
13833
637k
    goto next_node;
13834
637k
  }
13835
13836
395k
  do {
13837
395k
      cur = cur->parent;
13838
395k
      depth--;
13839
395k
      if ((cur == NULL) || (cur == limit) ||
13840
395k
                (cur->type == XML_DOCUMENT_NODE))
13841
71.5k
          goto done;
13842
324k
      if (cur->type == XML_ELEMENT_NODE) {
13843
324k
    ret = xmlStreamPop(patstream);
13844
324k
      } 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
324k
      if (cur->next != NULL) {
13853
280k
    cur = cur->next;
13854
280k
    break;
13855
280k
      }
13856
324k
  } while (cur != NULL);
13857
13858
676k
    } while ((cur != NULL) && (depth >= 0));
13859
13860
73.5k
done:
13861
13862
73.5k
    if (patstream)
13863
73.5k
  xmlFreeStreamCtxt(patstream);
13864
73.5k
    return(0);
13865
13866
0
return_1:
13867
0
    if (patstream)
13868
0
  xmlFreeStreamCtxt(patstream);
13869
0
    return(1);
13870
924k
}
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
676k
{
13883
676k
    xmlXPathCompExprPtr comp;
13884
676k
    int oldDepth;
13885
13886
676k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13887
0
  return(-1);
13888
13889
676k
    if (ctxt->valueTab == NULL) {
13890
  /* Allocate the value stack */
13891
1.15k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13892
1.15k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13893
1.15k
  if (ctxt->valueTab == NULL) {
13894
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13895
0
      return(-1);
13896
0
  }
13897
1.15k
  ctxt->valueNr = 0;
13898
1.15k
  ctxt->valueMax = 10;
13899
1.15k
  ctxt->value = NULL;
13900
1.15k
        ctxt->valueFrame = 0;
13901
1.15k
    }
13902
676k
#ifdef XPATH_STREAMING
13903
676k
    if (ctxt->comp->stream) {
13904
86.0k
  int res;
13905
13906
86.0k
  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
86.0k
  } else {
13915
86.0k
      xmlXPathObjectPtr resObj = NULL;
13916
13917
      /*
13918
      * Evaluation to a sequence.
13919
      */
13920
86.0k
      res = xmlXPathRunStreamEval(ctxt->context,
13921
86.0k
    ctxt->comp->stream, &resObj, 0);
13922
13923
86.0k
      if ((res != -1) && (resObj != NULL)) {
13924
86.0k
    valuePush(ctxt, resObj);
13925
86.0k
    return(0);
13926
86.0k
      }
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
86.0k
    }
13935
590k
#endif
13936
590k
    comp = ctxt->comp;
13937
590k
    if (comp->last < 0) {
13938
0
  xmlGenericError(xmlGenericErrorContext,
13939
0
      "xmlXPathRunEval: last is less than zero\n");
13940
0
  return(-1);
13941
0
    }
13942
590k
    oldDepth = ctxt->context->depth;
13943
590k
    if (toBool)
13944
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13945
0
      &comp->steps[comp->last], 0));
13946
590k
    else
13947
590k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13948
590k
    ctxt->context->depth = oldDepth;
13949
13950
590k
    return(0);
13951
590k
}
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
200k
                                xmlXPathObjectPtr res) {
14016
200k
    if ((ctxt == NULL) || (res == NULL)) return(0);
14017
200k
    switch (res->type) {
14018
0
        case XPATH_BOOLEAN:
14019
0
      return(res->boolval);
14020
61.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
61.2k
      return(res->floatval == ctxt->context->proximityPosition);
14026
0
#endif
14027
130k
        case XPATH_NODESET:
14028
130k
        case XPATH_XSLT_TREE:
14029
130k
      if (res->nodesetval == NULL)
14030
8.01k
    return(0);
14031
122k
      return(res->nodesetval->nodeNr != 0);
14032
9.05k
        case XPATH_STRING:
14033
9.05k
      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
200k
    }
14045
0
    return(0);
14046
200k
}
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
2.65M
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
2.65M
    xmlPatternPtr stream;
14065
2.65M
    xmlXPathCompExprPtr comp;
14066
2.65M
    xmlDictPtr dict = NULL;
14067
2.65M
    const xmlChar **namespaces = NULL;
14068
2.65M
    xmlNsPtr ns;
14069
2.65M
    int i, j;
14070
14071
2.65M
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14072
2.65M
        (!xmlStrchr(str, '@'))) {
14073
536k
  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
536k
  tmp = xmlStrchr(str, ':');
14085
536k
  if ((tmp != NULL) &&
14086
536k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14087
93.2k
      return(NULL);
14088
14089
443k
  if (ctxt != NULL) {
14090
443k
      dict = ctxt->dict;
14091
443k
      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
443k
  }
14106
14107
443k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14108
443k
  if (namespaces != NULL) {
14109
0
      xmlFree((xmlChar **)namespaces);
14110
0
  }
14111
443k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14112
66.7k
      comp = xmlXPathNewCompExpr();
14113
66.7k
      if (comp == NULL) {
14114
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14115
0
    return(NULL);
14116
0
      }
14117
66.7k
      comp->stream = stream;
14118
66.7k
      comp->dict = dict;
14119
66.7k
      if (comp->dict)
14120
0
    xmlDictReference(comp->dict);
14121
66.7k
      return(comp);
14122
66.7k
  }
14123
376k
  xmlFreePattern(stream);
14124
376k
    }
14125
2.49M
    return(NULL);
14126
2.65M
}
14127
#endif /* XPATH_STREAMING */
14128
14129
static void
14130
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14131
                           xmlXPathStepOpPtr op)
14132
5.22M
{
14133
5.22M
    xmlXPathCompExprPtr comp = pctxt->comp;
14134
5.22M
    xmlXPathContextPtr ctxt;
14135
14136
    /*
14137
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14138
    * internal representation.
14139
    */
14140
14141
5.22M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14142
5.22M
        (op->ch1 != -1) &&
14143
5.22M
        (op->ch2 == -1 /* no predicate */))
14144
1.06M
    {
14145
1.06M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14146
14147
1.06M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14148
1.06M
            ((xmlXPathAxisVal) prevop->value ==
14149
359k
                AXIS_DESCENDANT_OR_SELF) &&
14150
1.06M
            (prevop->ch2 == -1) &&
14151
1.06M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14152
1.06M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14153
164k
        {
14154
            /*
14155
            * This is a "descendant-or-self::node()" without predicates.
14156
            * Try to eliminate it.
14157
            */
14158
14159
164k
            switch ((xmlXPathAxisVal) op->value) {
14160
140k
                case AXIS_CHILD:
14161
140k
                case AXIS_DESCENDANT:
14162
                    /*
14163
                    * Convert "descendant-or-self::node()/child::" or
14164
                    * "descendant-or-self::node()/descendant::" to
14165
                    * "descendant::"
14166
                    */
14167
140k
                    op->ch1   = prevop->ch1;
14168
140k
                    op->value = AXIS_DESCENDANT;
14169
140k
                    break;
14170
61
                case AXIS_SELF:
14171
3.12k
                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
3.12k
                    op->ch1   = prevop->ch1;
14178
3.12k
                    op->value = AXIS_DESCENDANT_OR_SELF;
14179
3.12k
                    break;
14180
20.9k
                default:
14181
20.9k
                    break;
14182
164k
            }
14183
164k
  }
14184
1.06M
    }
14185
14186
    /* OP_VALUE has invalid ch1. */
14187
5.22M
    if (op->op == XPATH_OP_VALUE)
14188
591k
        return;
14189
14190
    /* Recurse */
14191
4.63M
    ctxt = pctxt->context;
14192
4.63M
    if (ctxt != NULL) {
14193
4.63M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14194
0
            return;
14195
4.63M
        ctxt->depth += 1;
14196
4.63M
    }
14197
4.63M
    if (op->ch1 != -1)
14198
3.28M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14199
4.63M
    if (op->ch2 != -1)
14200
1.37M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14201
4.63M
    if (ctxt != NULL)
14202
4.63M
        ctxt->depth -= 1;
14203
4.63M
}
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
2.65M
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14217
2.65M
    xmlXPathParserContextPtr pctxt;
14218
2.65M
    xmlXPathCompExprPtr comp;
14219
2.65M
    int oldDepth = 0;
14220
14221
2.65M
#ifdef XPATH_STREAMING
14222
2.65M
    comp = xmlXPathTryStreamCompile(ctxt, str);
14223
2.65M
    if (comp != NULL)
14224
66.5k
        return(comp);
14225
2.59M
#endif
14226
14227
2.59M
    xmlInitParser();
14228
14229
2.59M
    pctxt = xmlXPathNewParserContext(str, ctxt);
14230
2.59M
    if (pctxt == NULL)
14231
0
        return NULL;
14232
2.59M
    if (ctxt != NULL)
14233
2.59M
        oldDepth = ctxt->depth;
14234
2.59M
    xmlXPathCompileExpr(pctxt, 1);
14235
2.59M
    if (ctxt != NULL)
14236
2.59M
        ctxt->depth = oldDepth;
14237
14238
2.59M
    if( pctxt->error != XPATH_EXPRESSION_OK )
14239
1.82M
    {
14240
1.82M
        xmlXPathFreeParserContext(pctxt);
14241
1.82M
        return(NULL);
14242
1.82M
    }
14243
14244
769k
    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
205k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14252
205k
  comp = NULL;
14253
563k
    } else {
14254
563k
  comp = pctxt->comp;
14255
563k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14256
560k
            if (ctxt != NULL)
14257
560k
                oldDepth = ctxt->depth;
14258
560k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14259
560k
            if (ctxt != NULL)
14260
560k
                ctxt->depth = oldDepth;
14261
560k
  }
14262
563k
  pctxt->comp = NULL;
14263
563k
    }
14264
769k
    xmlXPathFreeParserContext(pctxt);
14265
14266
769k
    if (comp != NULL) {
14267
563k
  comp->expr = xmlStrdup(str);
14268
#ifdef DEBUG_EVAL_COUNTS
14269
  comp->string = xmlStrdup(str);
14270
  comp->nb = 0;
14271
#endif
14272
563k
    }
14273
769k
    return(comp);
14274
2.59M
}
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
675k
{
14309
675k
    xmlXPathParserContextPtr pctxt;
14310
675k
    xmlXPathObjectPtr resObj;
14311
#ifndef LIBXML_THREAD_ENABLED
14312
    static int reentance = 0;
14313
#endif
14314
675k
    int res;
14315
14316
675k
    CHECK_CTXT_NEG(ctxt)
14317
14318
675k
    if (comp == NULL)
14319
0
  return(-1);
14320
675k
    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
675k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14336
675k
    res = xmlXPathRunEval(pctxt, toBool);
14337
14338
675k
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14339
137k
        resObj = NULL;
14340
537k
    } else {
14341
537k
        resObj = valuePop(pctxt);
14342
537k
        if (resObj == NULL) {
14343
0
            if (!toBool)
14344
0
                xmlGenericError(xmlGenericErrorContext,
14345
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14346
537k
        } 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
537k
    }
14352
14353
675k
    if (resObjPtr)
14354
675k
        *resObjPtr = resObj;
14355
0
    else
14356
0
        xmlXPathReleaseObject(ctxt, resObj);
14357
14358
675k
    pctxt->comp = NULL;
14359
675k
    xmlXPathFreeParserContext(pctxt);
14360
#ifndef LIBXML_THREAD_ENABLED
14361
    reentance--;
14362
#endif
14363
14364
675k
    return(res);
14365
675k
}
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
675k
{
14380
675k
    xmlXPathObjectPtr res = NULL;
14381
14382
675k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14383
675k
    return(res);
14384
675k
}
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
1.89k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14413
1.89k
#ifdef XPATH_STREAMING
14414
1.89k
    xmlXPathCompExprPtr comp;
14415
1.89k
#endif
14416
1.89k
    int oldDepth = 0;
14417
14418
1.89k
    if (ctxt == NULL) return;
14419
14420
1.89k
#ifdef XPATH_STREAMING
14421
1.89k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422
1.89k
    if (comp != NULL) {
14423
223
        if (ctxt->comp != NULL)
14424
223
      xmlXPathFreeCompExpr(ctxt->comp);
14425
223
        ctxt->comp = comp;
14426
223
    } else
14427
1.67k
#endif
14428
1.67k
    {
14429
1.67k
        if (ctxt->context != NULL)
14430
1.67k
            oldDepth = ctxt->context->depth;
14431
1.67k
  xmlXPathCompileExpr(ctxt, 1);
14432
1.67k
        if (ctxt->context != NULL)
14433
1.67k
            ctxt->context->depth = oldDepth;
14434
1.67k
        CHECK_ERROR;
14435
14436
        /* Check for trailing characters. */
14437
1.22k
        if (*ctxt->cur != 0)
14438
935
            XP_ERROR(XPATH_EXPR_ERROR);
14439
14440
935
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441
666
            if (ctxt->context != NULL)
14442
666
                oldDepth = ctxt->context->depth;
14443
666
      xmlXPathOptimizeExpression(ctxt,
14444
666
    &ctxt->comp->steps[ctxt->comp->last]);
14445
666
            if (ctxt->context != NULL)
14446
666
                ctxt->context->depth = oldDepth;
14447
666
        }
14448
935
    }
14449
14450
1.15k
    xmlXPathRunEval(ctxt, 0);
14451
1.15k
}
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
1.89k
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14465
1.89k
    xmlXPathParserContextPtr ctxt;
14466
1.89k
    xmlXPathObjectPtr res;
14467
14468
1.89k
    CHECK_CTXT(ctx)
14469
14470
1.89k
    xmlInitParser();
14471
14472
1.89k
    ctxt = xmlXPathNewParserContext(str, ctx);
14473
1.89k
    if (ctxt == NULL)
14474
0
        return NULL;
14475
1.89k
    xmlXPathEvalExpr(ctxt);
14476
14477
1.89k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14478
758
  res = NULL;
14479
1.13k
    } else {
14480
1.13k
  res = valuePop(ctxt);
14481
1.13k
        if (res == NULL) {
14482
0
            xmlGenericError(xmlGenericErrorContext,
14483
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14484
1.13k
        } 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
1.13k
    }
14490
14491
1.89k
    xmlXPathFreeParserContext(ctxt);
14492
1.89k
    return(res);
14493
1.89k
}
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
820
{
14676
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14677
820
                         xmlXPathBooleanFunction);
14678
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14679
820
                         xmlXPathCeilingFunction);
14680
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14681
820
                         xmlXPathCountFunction);
14682
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14683
820
                         xmlXPathConcatFunction);
14684
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14685
820
                         xmlXPathContainsFunction);
14686
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14687
820
                         xmlXPathIdFunction);
14688
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14689
820
                         xmlXPathFalseFunction);
14690
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14691
820
                         xmlXPathFloorFunction);
14692
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14693
820
                         xmlXPathLastFunction);
14694
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14695
820
                         xmlXPathLangFunction);
14696
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14697
820
                         xmlXPathLocalNameFunction);
14698
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14699
820
                         xmlXPathNotFunction);
14700
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14701
820
                         xmlXPathNameFunction);
14702
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14703
820
                         xmlXPathNamespaceURIFunction);
14704
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14705
820
                         xmlXPathNormalizeFunction);
14706
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14707
820
                         xmlXPathNumberFunction);
14708
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14709
820
                         xmlXPathPositionFunction);
14710
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14711
820
                         xmlXPathRoundFunction);
14712
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14713
820
                         xmlXPathStringFunction);
14714
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14715
820
                         xmlXPathStringLengthFunction);
14716
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14717
820
                         xmlXPathStartsWithFunction);
14718
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14719
820
                         xmlXPathSubstringFunction);
14720
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14721
820
                         xmlXPathSubstringBeforeFunction);
14722
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14723
820
                         xmlXPathSubstringAfterFunction);
14724
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14725
820
                         xmlXPathSumFunction);
14726
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14727
820
                         xmlXPathTrueFunction);
14728
820
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14729
820
                         xmlXPathTranslateFunction);
14730
14731
820
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14732
820
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14733
820
                         xmlXPathEscapeUriFunction);
14734
820
}
14735
14736
#endif /* LIBXML_XPATH_ENABLED */