Coverage Report

Created: 2024-05-29 15:23

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